[DRE-commits] [chef] 03/13: Imported Upstream version 12.7.2

Lucas Kanashiro kanashiro.duarte at gmail.com
Wed May 4 15:54:47 UTC 2016


This is an automated email from the git hooks/post-receive script.

kanashiro-guest pushed a commit to branch master
in repository chef.

commit 7f4a76dbd4647615a3a4e28a5bcf878ab790c78e
Author: Lucas Kanashiro <kanashiro.duarte at gmail.com>
Date:   Thu Mar 3 15:18:26 2016 -0300

    Imported Upstream version 12.7.2
---
 .gitattributes                                     |    6 +
 .gitignore                                         |   61 +
 .kitchen.yml                                       |   82 +
 .mailmap                                           |  117 +
 .rspec                                             |    2 +
 .rubocop.yml                                       |    6 +
 .travis.yml                                        |  165 ++
 .yardopts                                          |    1 +
 CBGB.md                                            |   40 +
 CBGB.toml                                          |   96 +
 CHANGELOG.md                                       |  923 +++++++
 CHEF_MVPS.md                                       |  108 +
 CLA_ARCHIVE.md                                     | 2510 ++++++++++++++++++++
 CONTRIBUTING.md                                    |   46 +-
 DOC_CHANGES.md                                     |  133 ++
 Gemfile                                            |   58 +
 MAINTAINERS.md                                     |  234 ++
 MAINTAINERS.toml                                   |  338 +++
 NOTICE                                             |   21 +
 README.md                                          |   63 +-
 RELEASE_NOTES.md                                   |   82 +
 ROADMAP.md                                         |   15 +
 Rakefile                                           |   68 +-
 VERSION                                            |    1 +
 acceptance/.gitignore                              |    1 +
 .../kitchen_acceptance/.kitchen.digitalocean.yml   |   27 +
 .../.shared/kitchen_acceptance/.kitchen.ec2.yml    |  281 +++
 .../kitchen_acceptance/.kitchen.vagrant.yml        |   49 +
 .../kitchen_acceptance/libraries/kitchen.rb        |   46 +
 acceptance/.shared/kitchen_acceptance/metadata.rb  |    1 +
 acceptance/Gemfile                                 |   11 +
 acceptance/README.md                               |   86 +
 .../.acceptance/acceptance-cookbook/.gitignore     |    2 +
 .../.acceptance/acceptance-cookbook/metadata.rb    |    3 +
 .../acceptance-cookbook/recipes/destroy.rb         |    1 +
 .../acceptance-cookbook/recipes/provision.rb       |    1 +
 .../acceptance-cookbook/recipes/verify.rb          |    1 +
 acceptance/basics/.kitchen.yml                     |    4 +
 .../serverspec/chef_client_spec.rb                 |   19 +
 .../chef-current-install/serverspec/spec_helper.rb |    6 +
 .../.acceptance/acceptance-cookbook/.gitignore     |    2 +
 .../libraries/cookbook_kitchen.rb                  |   43 +
 .../acceptance-cookbook/libraries/top_cookbooks.rb |   21 +
 .../.acceptance/acceptance-cookbook/metadata.rb    |    3 +
 .../acceptance-cookbook/recipes/destroy.rb         |    1 +
 .../acceptance-cookbook/recipes/provision.rb       |    1 +
 .../acceptance-cookbook/recipes/verify.rb          |    1 +
 acceptance/top-cookbooks/.gitignore                |    1 +
 acceptance/top-cookbooks/.kitchen.git.yml          |   10 +
 .../.kitchen.learn-the-basics-rhel.yml             |    4 +
 .../.kitchen.learn-the-basics-ubuntu.yml           |    4 +
 .../.kitchen.learn-the-basics-windows.yml          |    4 +
 .../.acceptance/acceptance-cookbook/.gitignore     |    2 +
 .../.acceptance/acceptance-cookbook/metadata.rb    |    2 +
 .../acceptance-cookbook/recipes/destroy.rb         |    1 +
 .../acceptance-cookbook/recipes/provision.rb       |    1 +
 .../acceptance-cookbook/recipes/verify.rb          |    1 +
 acceptance/trivial/.kitchen.yml                    |    7 +
 .../inspec/chef_client_spec.rb                     |    5 +
 .../.acceptance/acceptance-cookbook/.gitignore     |    2 +
 .../.acceptance/acceptance-cookbook/metadata.rb    |    2 +
 .../acceptance-cookbook/recipes/destroy.rb         |    1 +
 .../acceptance-cookbook/recipes/provision.rb       |    1 +
 .../acceptance-cookbook/recipes/verify.rb          |    1 +
 acceptance/windows-service/.kitchen.yml            |    7 +
 .../inspec/chef_windows_service_spec.rb            |   58 +
 appveyor.yml                                       |   36 +
 bin/chef-apply                                     |    6 +-
 bin/chef-client                                    |   10 +-
 bin/chef-service-manager                           |   38 +
 bin/chef-shell                                     |    2 +-
 bin/chef-solo                                      |    8 +-
 bin/chef-windows-service                           |   35 +
 bin/knife                                          |    9 +-
 chef-config/.gitignore                             |    9 +
 chef-config/.rspec                                 |    2 +
 chef-config/.travis.yml                            |   31 +
 chef-config/Gemfile                                |    4 +
 chef-config/LICENSE                                |  201 ++
 chef-config/README.md                              |    4 +
 chef-config/Rakefile                               |   13 +
 chef-config/chef-config.gemspec                    |   32 +
 chef-config/lib/chef-config.rb                     |   20 +
 chef-config/lib/chef-config/config.rb              |  920 +++++++
 chef-config/lib/chef-config/exceptions.rb          |   26 +
 chef-config/lib/chef-config/logger.rb              |   59 +
 chef-config/lib/chef-config/package_task.rb        |  222 ++
 chef-config/lib/chef-config/path_helper.rb         |  264 ++
 chef-config/lib/chef-config/version.rb             |   34 +
 chef-config/lib/chef-config/windows.rb             |   28 +
 .../lib/chef-config/workstation_config_loader.rb   |  178 ++
 chef-config/spec/spec_helper.rb                    |   75 +
 chef-config/spec/unit/config_spec.rb               |  843 +++++++
 chef-config/spec/unit/path_helper_spec.rb          |  290 +++
 .../spec/unit/workstation_config_loader_spec.rb    |  289 +++
 chef.gemspec                                       |   58 +
 ci/verify-chef.bat                                 |   64 +
 ci/verify-chef.sh                                  |  118 +
 distro/common/man/man1/knife-cookbook-site.1       |   22 +-
 distro/common/markdown/man1/chef-shell.mkd         |    8 +-
 distro/common/markdown/man1/knife-bootstrap.mkd    |    2 +-
 distro/common/markdown/man1/knife-client.mkd       |    2 +-
 distro/common/markdown/man1/knife-configure.mkd    |    2 +-
 .../common/markdown/man1/knife-cookbook-site.mkd   |    2 +-
 distro/common/markdown/man1/knife-cookbook.mkd     |    8 +-
 distro/common/markdown/man1/knife-data-bag.mkd     |    2 +-
 distro/common/markdown/man1/knife-environment.mkd  |    6 +-
 distro/common/markdown/man1/knife-exec.mkd         |    2 +-
 distro/common/markdown/man1/knife-index.mkd        |    2 +-
 distro/common/markdown/man1/knife-node.mkd         |    2 +-
 distro/common/markdown/man1/knife-role.mkd         |    6 +-
 distro/common/markdown/man1/knife-search.mkd       |    4 +-
 distro/common/markdown/man1/knife-ssh.mkd          |    2 +-
 distro/common/markdown/man1/knife-status.mkd       |    2 +-
 distro/common/markdown/man1/knife-tag.mkd          |    2 +-
 distro/common/markdown/man1/knife.mkd              |    4 +-
 distro/common/markdown/man8/chef-client.mkd        |    3 +-
 distro/common/markdown/man8/chef-expander.mkd      |    3 +-
 distro/common/markdown/man8/chef-expanderctl.mkd   |    3 +-
 distro/common/markdown/man8/chef-server-webui.mkd  |    2 +-
 distro/common/markdown/man8/chef-server.mkd        |    3 +-
 distro/common/markdown/man8/chef-solo.mkd          |    4 +-
 distro/common/markdown/man8/chef-solr.mkd          |    2 +-
 distro/powershell/chef/chef.psm1                   |  327 +++
 ext/win32-eventlog/Rakefile                        |   53 +
 ext/win32-eventlog/chef-log.man                    |   56 +
 kitchen-tests/.chef/client.rb                      |   10 +
 kitchen-tests/.kitchen.travis.yml                  |   42 +
 kitchen-tests/.kitchen.yml                         |   38 +
 kitchen-tests/Berksfile                            |    5 +
 kitchen-tests/Gemfile                              |   10 +
 kitchen-tests/README.md                            |   89 +
 kitchen-tests/cookbooks/audit_test/.gitignore      |   16 +
 kitchen-tests/cookbooks/audit_test/.kitchen.yml    |   16 +
 kitchen-tests/cookbooks/audit_test/Berksfile       |    3 +
 kitchen-tests/cookbooks/audit_test/README.md       |   12 +
 kitchen-tests/cookbooks/audit_test/chefignore      |   95 +
 kitchen-tests/cookbooks/audit_test/metadata.rb     |    7 +
 .../cookbooks/audit_test/recipes/default.rb        |   26 +
 .../recipes/error_duplicate_control_groups.rb      |   17 +
 .../cookbooks/audit_test/recipes/error_no_block.rb |    7 +
 .../audit_test/recipes/error_orphan_control.rb     |   13 +
 .../cookbooks/audit_test/recipes/failed_specs.rb   |   14 +
 .../audit_test/recipes/serverspec_collision.rb     |   31 +
 .../audit_test/recipes/serverspec_support.rb       |   37 +
 .../audit_test/recipes/with_include_recipe.rb      |   16 +
 kitchen-tests/cookbooks/webapp/Berksfile           |    5 +
 kitchen-tests/cookbooks/webapp/README.md           |    3 +
 .../cookbooks/webapp/attributes/default.rb         |   14 +
 kitchen-tests/cookbooks/webapp/metadata.rb         |   12 +
 kitchen-tests/cookbooks/webapp/recipes/default.rb  |   64 +
 .../webapp/templates/default/index.html.erb        |    5 +
 .../webapp/templates/default/index.php.erb         |    8 +
 kitchen-tests/data_bags/passwords/mysql.json       |    5 +
 kitchen-tests/data_bags/passwords/webapp.json      |    4 +
 .../test/fixtures/platforms/centos/5.json          |   14 +
 .../test/fixtures/platforms/centos/6.json          |   14 +
 .../test/fixtures/platforms/ubuntu/10.04.json      |   14 +
 .../test/fixtures/platforms/ubuntu/12.04.json      |   14 +
 .../test/fixtures/platforms/ubuntu/14.04.json      |   14 +
 .../test/fixtures/platforms/ubuntu/14.10.json      |   14 +
 kitchen-tests/test/fixtures/serverspec_helper.rb   |   32 +
 .../test/integration/webapp/serverspec/Gemfile     |    4 +
 .../webapp/serverspec/localhost/default_spec.rb    |  127 +
 .../chef/chef_fs/file_system/acl_entry.rb          |    5 +
 .../chef_repository_file_system_root_dir.rb        |    5 +
 .../chef_fs/file_system/chef_server_root_dir.rb    |    5 +
 lib/chef.rb                                        |   34 +-
 lib/chef/api_client.rb                             |   65 +-
 lib/chef/api_client/registration.rb                |   53 +-
 lib/chef/api_client_v1.rb                          |  325 +++
 lib/chef/application.rb                            |  143 +-
 lib/chef/application/apply.rb                      |   71 +-
 lib/chef/application/client.rb                     |  150 +-
 lib/chef/application/knife.rb                      |   40 +-
 lib/chef/application/solo.rb                       |   99 +-
 lib/chef/application/windows_service.rb            |   69 +-
 lib/chef/application/windows_service_manager.rb    |   74 +-
 lib/chef/applications.rb                           |    8 +-
 lib/chef/audit/audit_event_proxy.rb                |    6 +-
 lib/chef/audit/audit_reporter.rb                   |   37 +-
 lib/chef/audit/control_group_data.rb               |   19 +-
 lib/chef/audit/logger.rb                           |   36 +
 lib/chef/audit/rspec_formatter.rb                  |    4 +-
 lib/chef/audit/runner.rb                           |   34 +-
 lib/chef/chef_class.rb                             |  122 +-
 lib/chef/chef_fs.rb                                |   52 +-
 lib/chef/chef_fs/chef_fs_data_store.rb             |  576 ++++-
 lib/chef/chef_fs/command_line.rb                   |   16 +-
 lib/chef/chef_fs/config.rb                         |  113 +-
 lib/chef/chef_fs/data_handler/acl_data_handler.rb  |   20 +-
 .../chef_fs/data_handler/client_data_handler.rb    |   24 +-
 .../chef_fs/data_handler/container_data_handler.rb |   12 +-
 .../chef_fs/data_handler/cookbook_data_handler.rb  |   30 +-
 .../data_handler/data_bag_item_data_handler.rb     |   22 +-
 lib/chef/chef_fs/data_handler/data_handler_base.rb |   16 +-
 .../data_handler/environment_data_handler.rb       |   28 +-
 .../chef_fs/data_handler/group_data_handler.rb     |   36 +-
 lib/chef/chef_fs/data_handler/node_data_handler.rb |   28 +-
 .../data_handler/organization_data_handler.rb      |   18 +-
 .../organization_invites_data_handler.rb           |    4 +-
 .../organization_members_data_handler.rb           |    4 +-
 .../chef_fs/data_handler/policy_data_handler.rb    |   33 +-
 .../data_handler/policy_group_data_handler.rb      |   27 +
 lib/chef/chef_fs/data_handler/role_data_handler.rb |   32 +-
 lib/chef/chef_fs/data_handler/user_data_handler.rb |   24 +-
 lib/chef/chef_fs/file_pattern.rb                   |   67 +-
 lib/chef/chef_fs/file_system.rb                    |   20 +-
 lib/chef/chef_fs/file_system/acl_dir.rb            |   64 -
 lib/chef/chef_fs/file_system/acl_entry.rb          |   58 -
 lib/chef/chef_fs/file_system/acls_dir.rb           |   68 -
 .../chef_fs/file_system/already_exists_error.rb    |    9 +-
 lib/chef/chef_fs/file_system/base_fs_dir.rb        |   13 +-
 lib/chef/chef_fs/file_system/base_fs_object.rb     |   23 +-
 .../chef_repository_file_system_acls_dir.rb        |   37 -
 .../chef_repository_file_system_cookbook_dir.rb    |  109 -
 .../chef_repository_file_system_cookbook_entry.rb  |   87 -
 .../chef_repository_file_system_cookbooks_dir.rb   |   89 -
 .../chef_repository_file_system_data_bags_dir.rb   |   36 -
 .../chef_repository_file_system_entry.rb           |   92 -
 .../chef_repository_file_system_policies_dir.rb    |   38 -
 .../chef_repository_file_system_root_dir.rb        |  192 --
 .../chef_fs/file_system/chef_server/acl_dir.rb     |   65 +
 .../chef_fs/file_system/chef_server/acl_entry.rb   |   60 +
 .../chef_fs/file_system/chef_server/acls_dir.rb    |   75 +
 .../chef_server/chef_server_root_dir.rb            |  196 ++
 .../chef_server/cookbook_artifact_dir.rb           |   38 +
 .../chef_server/cookbook_artifacts_dir.rb          |  102 +
 .../file_system/chef_server/cookbook_dir.rb        |  222 ++
 .../file_system/chef_server/cookbook_file.rb       |   84 +
 .../file_system/chef_server/cookbook_subdir.rb     |   61 +
 .../file_system/chef_server/cookbooks_acl_dir.rb   |   42 +
 .../file_system/chef_server/cookbooks_dir.rb       |  102 +
 .../file_system/chef_server/data_bag_dir.rb        |   71 +
 .../file_system/chef_server/data_bags_dir.rb       |   69 +
 .../file_system/chef_server/environments_dir.rb    |   57 +
 .../chef_fs/file_system/chef_server/nodes_dir.rb   |   53 +
 .../chef_fs/file_system/chef_server/org_entry.rb   |   31 +
 .../chef_server/organization_invites_entry.rb      |   61 +
 .../chef_server/organization_members_entry.rb      |   60 +
 .../file_system/chef_server/policies_acl_dir.rb    |   41 +
 .../file_system/chef_server/policies_dir.rb        |  160 ++
 .../file_system/chef_server/policy_group_entry.rb  |  137 ++
 .../file_system/chef_server/policy_groups_dir.rb   |   43 +
 .../chef_server/policy_revision_entry.rb           |   34 +
 .../file_system/chef_server/rest_list_dir.rb       |  178 ++
 .../file_system/chef_server/rest_list_entry.rb     |  187 ++
 .../chef_server/versioned_cookbook_dir.rb          |   45 +
 .../chef_server/versioned_cookbooks_dir.rb         |  107 +
 .../chef_fs/file_system/chef_server_root_dir.rb    |  159 --
 lib/chef/chef_fs/file_system/cookbook_dir.rb       |  224 --
 lib/chef/chef_fs/file_system/cookbook_file.rb      |   82 -
 .../chef_fs/file_system/cookbook_frozen_error.rb   |    9 +-
 lib/chef/chef_fs/file_system/cookbook_subdir.rb    |   54 -
 lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb  |   41 -
 lib/chef/chef_fs/file_system/cookbooks_dir.rb      |  164 --
 lib/chef/chef_fs/file_system/data_bag_dir.rb       |   69 -
 lib/chef/chef_fs/file_system/data_bags_dir.rb      |   73 -
 ...default_environment_cannot_be_modified_error.rb |   10 +-
 lib/chef/chef_fs/file_system/environments_dir.rb   |   60 -
 lib/chef/chef_fs/file_system/file_system_entry.rb  |  108 -
 lib/chef/chef_fs/file_system/file_system_error.rb  |   17 +-
 .../chef_fs/file_system/file_system_root_dir.rb    |   31 -
 lib/chef/chef_fs/file_system/memory/memory_dir.rb  |   53 +
 lib/chef/chef_fs/file_system/memory/memory_file.rb |   20 +
 lib/chef/chef_fs/file_system/memory/memory_root.rb |   23 +
 lib/chef/chef_fs/file_system/memory_dir.rb         |   52 -
 lib/chef/chef_fs/file_system/memory_file.rb        |   17 -
 lib/chef/chef_fs/file_system/memory_root.rb        |   21 -
 lib/chef/chef_fs/file_system/multiplexed_dir.rb    |   19 +-
 .../file_system/must_delete_recursively_error.rb   |    9 +-
 lib/chef/chef_fs/file_system/nodes_dir.rb          |   55 -
 .../chef_fs/file_system/nonexistent_fs_object.rb   |    8 +-
 lib/chef/chef_fs/file_system/not_found_error.rb    |    9 +-
 .../chef_fs/file_system/operation_failed_error.rb  |   10 +-
 .../file_system/operation_not_allowed_error.rb     |   34 +-
 lib/chef/chef_fs/file_system/org_entry.rb          |   34 -
 .../file_system/organization_invites_entry.rb      |   59 -
 .../file_system/organization_members_entry.rb      |   58 -
 .../chef_repository_file_system_acls_dir.rb        |   39 +
 ...repository_file_system_cookbook_artifact_dir.rb |   41 +
 ...epository_file_system_cookbook_artifacts_dir.rb |   34 +
 .../chef_repository_file_system_cookbook_dir.rb    |   95 +
 .../chef_repository_file_system_cookbook_entry.rb  |   82 +
 .../chef_repository_file_system_cookbooks_dir.rb   |   84 +
 .../chef_repository_file_system_data_bags_dir.rb   |   38 +
 .../chef_repository_file_system_entry.rb           |   83 +
 .../chef_repository_file_system_policies_dir.rb    |   38 +
 .../chef_repository_file_system_root_dir.rb        |  210 ++
 ...epository_file_system_versioned_cookbook_dir.rb |   42 +
 ...pository_file_system_versioned_cookbooks_dir.rb |   34 +
 .../file_system/repository/file_system_entry.rb    |  117 +
 .../file_system/repository/file_system_root_dir.rb |   33 +
 lib/chef/chef_fs/file_system/rest_list_dir.rb      |  115 -
 lib/chef/chef_fs/file_system/rest_list_entry.rb    |  185 --
 lib/chef/chef_fs/knife.rb                          |   70 +-
 lib/chef/chef_fs/parallelizer.rb                   |    6 +-
 .../chef_fs/parallelizer/flatten_enumerable.rb     |    2 +-
 .../chef_fs/parallelizer/parallel_enumerable.rb    |    6 +-
 lib/chef/chef_fs/path_utils.rb                     |  108 +-
 lib/chef/client.rb                                 |  937 ++++++--
 lib/chef/config.rb                                 |  755 +-----
 lib/chef/config_fetcher.rb                         |   16 +-
 lib/chef/constants.rb                              |   28 +
 lib/chef/cookbook/chefignore.rb                    |    9 +-
 lib/chef/cookbook/cookbook_collection.rb           |   25 +-
 lib/chef/cookbook/cookbook_version_loader.rb       |   32 +-
 lib/chef/cookbook/file_system_file_vendor.rb       |    8 +-
 lib/chef/cookbook/file_vendor.rb                   |    7 +-
 lib/chef/cookbook/metadata.rb                      |  341 ++-
 lib/chef/cookbook/remote_file_vendor.rb            |   16 +-
 lib/chef/cookbook/synchronizer.rb                  |   23 +-
 lib/chef/cookbook/syntax_check.rb                  |   28 +-
 lib/chef/cookbook_loader.rb                        |   28 +-
 lib/chef/cookbook_manifest.rb                      |   31 +-
 lib/chef/cookbook_site_streaming_uploader.rb       |   66 +-
 lib/chef/cookbook_uploader.rb                      |   43 +-
 lib/chef/cookbook_version.rb                       |  184 +-
 lib/chef/daemon.rb                                 |   12 +-
 lib/chef/data_bag.rb                               |   60 +-
 lib/chef/data_bag_item.rb                          |   85 +-
 lib/chef/delayed_evaluator.rb                      |   21 +
 lib/chef/deprecation/mixin/template.rb             |   11 +-
 lib/chef/deprecation/provider/cookbook_file.rb     |    7 +-
 lib/chef/deprecation/provider/file.rb              |   22 +-
 lib/chef/deprecation/provider/remote_directory.rb  |   52 +
 lib/chef/deprecation/provider/remote_file.rb       |    9 +-
 lib/chef/deprecation/provider/template.rb          |    8 +-
 lib/chef/deprecation/warnings.rb                   |   11 +-
 lib/chef/digester.rb                               |   18 +-
 lib/chef/dsl.rb                                    |   12 +-
 lib/chef/dsl/audit.rb                              |    8 +-
 lib/chef/dsl/chef_provisioning.rb                  |   57 +
 lib/chef/dsl/cheffish.rb                           |   64 +
 lib/chef/dsl/data_query.rb                         |   20 +-
 lib/chef/dsl/declare_resource.rb                   |  108 +
 lib/chef/dsl/definitions.rb                        |   43 +
 lib/chef/dsl/include_attribute.rb                  |   10 +-
 lib/chef/dsl/include_recipe.rb                     |    8 +-
 lib/chef/dsl/platform_introspection.rb             |   28 +-
 lib/chef/dsl/powershell.rb                         |    6 +-
 lib/chef/dsl/reboot_pending.rb                     |   24 +-
 lib/chef/dsl/recipe.rb                             |  201 +-
 lib/chef/dsl/registry_helper.rb                    |   10 +-
 lib/chef/dsl/resources.rb                          |   58 +
 lib/chef/encrypted_data_bag_item.rb                |   20 +-
 lib/chef/encrypted_data_bag_item/assertions.rb     |    8 +-
 .../encrypted_data_bag_item/check_encrypted.rb     |    6 +-
 .../encrypted_data_bag_item/decryption_failure.rb  |    4 +-
 lib/chef/encrypted_data_bag_item/decryptor.rb      |   30 +-
 .../encrypted_data_bag_item_assertions.rb          |    2 +-
 .../encrypted_data_bag_item/encryption_failure.rb  |    2 +-
 lib/chef/encrypted_data_bag_item/encryptor.rb      |   40 +-
 .../unacceptable_encrypted_data_bag_item_format.rb |    4 +-
 .../encrypted_data_bag_item/unsupported_cipher.rb  |    4 +-
 .../unsupported_encrypted_data_bag_item_format.rb  |    4 +-
 lib/chef/environment.rb                            |   75 +-
 lib/chef/event_dispatch/base.rb                    |   87 +-
 lib/chef/event_dispatch/dispatcher.rb              |   36 +-
 lib/chef/event_dispatch/dsl.rb                     |   65 +
 lib/chef/event_dispatch/events_output_stream.rb    |    8 +
 lib/chef/event_loggers/base.rb                     |    6 +-
 lib/chef/event_loggers/windows_eventlog.rb         |   32 +-
 lib/chef/exceptions.rb                             |   81 +-
 lib/chef/file_access_control.rb                    |   12 +-
 lib/chef/file_access_control/unix.rb               |   39 +-
 lib/chef/file_access_control/windows.rb            |   10 +-
 lib/chef/file_cache.rb                             |   42 +-
 lib/chef/file_content_management/content_base.rb   |    4 +-
 lib/chef/file_content_management/deploy.rb         |   11 +-
 lib/chef/file_content_management/deploy/cp.rb      |    8 +-
 lib/chef/file_content_management/deploy/mv_unix.rb |   13 +-
 .../file_content_management/deploy/mv_windows.rb   |   34 +-
 lib/chef/file_content_management/tempfile.rb       |    8 +-
 lib/chef/formatters/base.rb                        |   25 +-
 lib/chef/formatters/doc.rb                         |   96 +-
 lib/chef/formatters/error_descriptor.rb            |   10 +-
 lib/chef/formatters/error_inspectors.rb            |   10 +-
 .../error_inspectors/api_error_formatting.rb       |   81 +-
 .../error_inspectors/compile_error_inspector.rb    |   82 +-
 .../cookbook_resolve_error_inspector.rb            |   18 +-
 .../cookbook_sync_error_inspector.rb               |   16 +-
 .../error_inspectors/node_load_error_inspector.rb  |   29 +-
 .../registration_error_inspector.rb                |   40 +-
 .../error_inspectors/resource_failure_inspector.rb |   23 +-
 .../run_list_expansion_error_inspector.rb          |   31 +-
 lib/chef/formatters/error_mapper.rb                |    4 +-
 lib/chef/formatters/indentable_output_stream.rb    |   15 +-
 lib/chef/formatters/minimal.rb                     |   20 +-
 lib/chef/guard_interpreter.rb                      |    6 +-
 .../guard_interpreter/default_guard_interpreter.rb |    7 +-
 .../resource_guard_interpreter.rb                  |   26 +-
 lib/chef/handler.rb                                |    8 +-
 lib/chef/handler/error_report.rb                   |    8 +-
 lib/chef/handler/json_file.rb                      |   10 +-
 lib/chef/http.rb                                   |   85 +-
 lib/chef/http/auth_credentials.rb                  |   24 +-
 lib/chef/http/authenticator.rb                     |   35 +-
 lib/chef/http/basic_client.rb                      |   48 +-
 lib/chef/http/cookie_jar.rb                        |   14 +-
 lib/chef/http/cookie_manager.rb                    |   16 +-
 lib/chef/http/decompressor.rb                      |   20 +-
 lib/chef/http/http_request.rb                      |   65 +-
 lib/chef/http/json_input.rb                        |   25 +-
 lib/chef/http/json_output.rb                       |   18 +-
 lib/chef/http/json_to_model_output.rb              |    8 +-
 lib/chef/http/remote_request_id.rb                 |   12 +-
 lib/chef/http/simple.rb                            |   28 +-
 lib/chef/http/simple_json.rb                       |   43 +
 lib/chef/http/socketless_chef_zero_client.rb       |  113 +-
 lib/chef/http/ssl_policies.rb                      |   18 +-
 lib/chef/http/validate_content_length.rb           |   24 +-
 lib/chef/json_compat.rb                            |   13 +-
 lib/chef/key.rb                                    |  273 +++
 lib/chef/knife.rb                                  |  215 +-
 lib/chef/knife/bootstrap.rb                        |  168 +-
 lib/chef/knife/bootstrap/chef_vault_handler.rb     |   38 +-
 lib/chef/knife/bootstrap/client_builder.rb         |   42 +-
 lib/chef/knife/bootstrap/templates/README.md       |    7 +-
 .../knife/bootstrap/templates/archlinux-gems.erb   |   76 -
 lib/chef/knife/bootstrap/templates/chef-aix.erb    |   72 -
 lib/chef/knife/bootstrap/templates/chef-full.erb   |  197 +-
 lib/chef/knife/client_bulk_delete.rb               |   12 +-
 lib/chef/knife/client_create.rb                    |   96 +-
 lib/chef/knife/client_delete.rb                    |   14 +-
 lib/chef/knife/client_edit.rb                      |   20 +-
 lib/chef/knife/client_key_create.rb                |   67 +
 lib/chef/knife/client_key_delete.rb                |   76 +
 lib/chef/knife/client_key_edit.rb                  |   79 +
 lib/chef/knife/client_key_list.rb                  |   69 +
 lib/chef/knife/client_key_show.rb                  |   76 +
 lib/chef/knife/client_list.rb                      |   12 +-
 lib/chef/knife/client_reregister.rb                |   12 +-
 lib/chef/knife/client_show.rb                      |   12 +-
 lib/chef/knife/configure.rb                        |   28 +-
 lib/chef/knife/configure_client.rb                 |   12 +-
 lib/chef/knife/cookbook_bulk_delete.rb             |   19 +-
 lib/chef/knife/cookbook_create.rb                  |   26 +-
 lib/chef/knife/cookbook_delete.rb                  |   20 +-
 lib/chef/knife/cookbook_download.rb                |   18 +-
 lib/chef/knife/cookbook_list.rb                    |   10 +-
 lib/chef/knife/cookbook_metadata.rb                |   16 +-
 lib/chef/knife/cookbook_metadata_from_file.rb      |   10 +-
 lib/chef/knife/cookbook_show.rb                    |   32 +-
 lib/chef/knife/cookbook_site_download.rb           |   46 +-
 lib/chef/knife/cookbook_site_install.rb            |   26 +-
 lib/chef/knife/cookbook_site_list.rb               |   16 +-
 lib/chef/knife/cookbook_site_search.rb             |   15 +-
 lib/chef/knife/cookbook_site_share.rb              |   45 +-
 lib/chef/knife/cookbook_site_show.rb               |   19 +-
 lib/chef/knife/cookbook_site_unshare.rb            |   16 +-
 lib/chef/knife/cookbook_site_vendor.rb             |   10 +-
 lib/chef/knife/cookbook_test.rb                    |   13 +-
 lib/chef/knife/cookbook_upload.rb                  |   39 +-
 lib/chef/knife/core/bootstrap_context.rb           |   63 +-
 lib/chef/knife/core/cookbook_scm_repo.rb           |   23 +-
 lib/chef/knife/core/custom_manifest_loader.rb      |   69 +
 lib/chef/knife/core/gem_glob_loader.rb             |  138 ++
 lib/chef/knife/core/generic_presenter.rb           |   67 +-
 lib/chef/knife/core/hashed_command_loader.rb       |   80 +
 lib/chef/knife/core/node_editor.rb                 |   97 +-
 lib/chef/knife/core/node_presenter.rb              |   54 +-
 lib/chef/knife/core/object_loader.rb               |   17 +-
 lib/chef/knife/core/status_presenter.rb            |   34 +-
 lib/chef/knife/core/subcommand_loader.rb           |  290 ++-
 lib/chef/knife/core/text_formatter.rb              |   27 +-
 lib/chef/knife/core/ui.rb                          |   35 +-
 lib/chef/knife/data_bag_create.rb                  |   21 +-
 lib/chef/knife/data_bag_delete.rb                  |   14 +-
 lib/chef/knife/data_bag_edit.rb                    |   19 +-
 lib/chef/knife/data_bag_from_file.rb               |   23 +-
 lib/chef/knife/data_bag_list.rb                    |   12 +-
 lib/chef/knife/data_bag_secret_options.rb          |   12 +-
 lib/chef/knife/data_bag_show.rb                    |   62 +-
 lib/chef/knife/delete.rb                           |   13 +-
 lib/chef/knife/deps.rb                             |   36 +-
 lib/chef/knife/diff.rb                             |   17 +-
 lib/chef/knife/download.rb                         |   23 +-
 lib/chef/knife/edit.rb                             |   11 +-
 lib/chef/knife/environment_compare.rb              |   46 +-
 lib/chef/knife/environment_create.rb               |   10 +-
 lib/chef/knife/environment_delete.rb               |   10 +-
 lib/chef/knife/environment_edit.rb                 |   10 +-
 lib/chef/knife/environment_from_file.rb            |    9 +-
 lib/chef/knife/environment_list.rb                 |   10 +-
 lib/chef/knife/environment_show.rb                 |   10 +-
 lib/chef/knife/exec.rb                             |   14 +-
 lib/chef/knife/help.rb                             |   16 +-
 lib/chef/knife/index_rebuild.rb                    |    9 +-
 lib/chef/knife/key_create.rb                       |  108 +
 lib/chef/knife/key_create_base.rb                  |   50 +
 lib/chef/knife/key_delete.rb                       |   55 +
 lib/chef/knife/key_edit.rb                         |  114 +
 lib/chef/knife/key_edit_base.rb                    |   55 +
 lib/chef/knife/key_list.rb                         |   88 +
 lib/chef/knife/key_list_base.rb                    |   45 +
 lib/chef/knife/key_show.rb                         |   53 +
 lib/chef/knife/list.rb                             |   27 +-
 lib/chef/knife/node_bulk_delete.rb                 |   18 +-
 lib/chef/knife/node_create.rb                      |   13 +-
 lib/chef/knife/node_delete.rb                      |   11 +-
 lib/chef/knife/node_edit.rb                        |   14 +-
 lib/chef/knife/node_environment_set.rb             |    8 +-
 lib/chef/knife/node_from_file.rb                   |   20 +-
 lib/chef/knife/node_list.rb                        |   12 +-
 lib/chef/knife/node_run_list_add.rb                |   16 +-
 lib/chef/knife/node_run_list_remove.rb             |   27 +-
 lib/chef/knife/node_run_list_set.rb                |   12 +-
 lib/chef/knife/node_show.rb                        |   13 +-
 lib/chef/knife/null.rb                             |   10 +
 lib/chef/knife/osc_user_create.rb                  |   97 +
 lib/chef/knife/osc_user_delete.rb                  |   51 +
 lib/chef/knife/osc_user_edit.rb                    |   58 +
 lib/chef/knife/osc_user_list.rb                    |   47 +
 lib/chef/knife/osc_user_reregister.rb              |   64 +
 lib/chef/knife/osc_user_show.rb                    |   54 +
 lib/chef/knife/raw.rb                              |   35 +-
 lib/chef/knife/recipe_list.rb                      |    8 +-
 lib/chef/knife/rehash.rb                           |   62 +
 lib/chef/knife/role_bulk_delete.rb                 |   15 +-
 lib/chef/knife/role_create.rb                      |   12 +-
 lib/chef/knife/role_delete.rb                      |   11 +-
 lib/chef/knife/role_edit.rb                        |   13 +-
 lib/chef/knife/role_env_run_list_add.rb            |   18 +-
 lib/chef/knife/role_env_run_list_clear.rb          |    8 +-
 lib/chef/knife/role_env_run_list_remove.rb         |   26 +-
 lib/chef/knife/role_env_run_list_replace.rb        |   12 +-
 lib/chef/knife/role_env_run_list_set.rb            |   12 +-
 lib/chef/knife/role_from_file.rb                   |   17 +-
 lib/chef/knife/role_list.rb                        |   11 +-
 lib/chef/knife/role_run_list_add.rb                |   18 +-
 lib/chef/knife/role_run_list_clear.rb              |    8 +-
 lib/chef/knife/role_run_list_remove.rb             |   26 +-
 lib/chef/knife/role_run_list_replace.rb            |   12 +-
 lib/chef/knife/role_run_list_set.rb                |   12 +-
 lib/chef/knife/role_show.rb                        |   13 +-
 lib/chef/knife/search.rb                           |   28 +-
 lib/chef/knife/serve.rb                            |   20 +-
 lib/chef/knife/show.rb                             |    8 +-
 lib/chef/knife/ssh.rb                              |  236 +-
 lib/chef/knife/ssl_check.rb                        |   32 +-
 lib/chef/knife/ssl_fetch.rb                        |   31 +-
 lib/chef/knife/status.rb                           |   33 +-
 lib/chef/knife/tag_create.rb                       |   10 +-
 lib/chef/knife/tag_delete.rb                       |   10 +-
 lib/chef/knife/tag_list.rb                         |   10 +-
 lib/chef/knife/upload.rb                           |   21 +-
 lib/chef/knife/user_create.rb                      |  135 +-
 lib/chef/knife/user_delete.rb                      |   63 +-
 lib/chef/knife/user_edit.rb                        |   54 +-
 lib/chef/knife/user_key_create.rb                  |   69 +
 lib/chef/knife/user_key_delete.rb                  |   76 +
 lib/chef/knife/user_key_edit.rb                    |   79 +
 lib/chef/knife/user_key_list.rb                    |   69 +
 lib/chef/knife/user_key_show.rb                    |   76 +
 lib/chef/knife/user_list.rb                        |   15 +-
 lib/chef/knife/user_reregister.rb                  |   56 +-
 lib/chef/knife/user_show.rb                        |   43 +-
 lib/chef/knife/xargs.rb                            |   45 +-
 lib/chef/local_mode.rb                             |   25 +-
 lib/chef/log.rb                                    |   36 +-
 lib/chef/log/syslog.rb                             |   45 +
 lib/chef/log/winevt.rb                             |   99 +
 lib/chef/mash.rb                                   |   11 +-
 lib/chef/mixin/api_version_request_handling.rb     |   66 +
 lib/chef/mixin/checksum.rb                         |    8 +-
 lib/chef/mixin/command.rb                          |   26 +-
 lib/chef/mixin/command/unix.rb                     |   14 +-
 lib/chef/mixin/command/windows.rb                  |   13 +-
 lib/chef/mixin/convert_to_class_name.rb            |   30 +-
 lib/chef/mixin/create_path.rb                      |    6 +-
 lib/chef/mixin/deep_merge.rb                       |    6 +-
 lib/chef/mixin/deprecation.rb                      |   65 +-
 lib/chef/mixin/descendants_tracker.rb              |    5 +-
 .../mixin/enforce_ownership_and_permissions.rb     |    6 +-
 lib/chef/mixin/file_class.rb                       |   20 +-
 lib/chef/mixin/from_file.rb                        |    6 +-
 lib/chef/mixin/get_source_from_package.rb          |   12 +-
 lib/chef/mixin/homebrew_user.rb                    |   12 +-
 lib/chef/mixin/language.rb                         |   10 +-
 lib/chef/mixin/language_include_attribute.rb       |    9 +-
 lib/chef/mixin/language_include_recipe.rb          |    9 +-
 lib/chef/mixin/params_validate.rb                  |  521 ++--
 lib/chef/mixin/path_sanity.rb                      |   14 +-
 lib/chef/mixin/powershell_out.rb                   |   98 +
 lib/chef/mixin/powershell_type_coercions.rb        |   22 +-
 lib/chef/mixin/properties.rb                       |  302 +++
 lib/chef/mixin/provides.rb                         |   30 +-
 lib/chef/mixin/proxified_socket.rb                 |   38 +
 lib/chef/mixin/recipe_definition_dsl_core.rb       |    8 +-
 lib/chef/mixin/securable.rb                        |   51 +-
 lib/chef/mixin/shell_out.rb                        |   20 +-
 lib/chef/mixin/subclass_directive.rb               |   37 +
 lib/chef/mixin/template.rb                         |   63 +-
 lib/chef/mixin/unformatter.rb                      |   32 +
 lib/chef/mixin/uris.rb                             |   43 +
 lib/chef/mixin/which.rb                            |    8 +-
 lib/chef/mixin/why_run.rb                          |   13 +-
 lib/chef/mixin/wide_string.rb                      |   72 +
 lib/chef/mixin/windows_architecture_helper.rb      |   76 +-
 lib/chef/mixin/windows_env_helper.rb               |   27 +-
 lib/chef/mixin/xml_escape.rb                       |   26 +-
 lib/chef/mixins.rb                                 |   27 +-
 lib/chef/monkey_patches/net-ssh-multi.rb           |   12 +-
 lib/chef/monkey_patches/net_http.rb                |    4 +-
 lib/chef/monkey_patches/webrick-utils.rb           |   51 +
 lib/chef/monkey_patches/win32/registry.rb          |   72 +
 lib/chef/monologger.rb                             |    6 +-
 lib/chef/node.rb                                   |  260 +-
 lib/chef/node/attribute.rb                         |  578 ++---
 lib/chef/node/attribute_collections.rb             |   16 +-
 lib/chef/node/immutable_collections.rb             |    6 +-
 lib/chef/node_map.rb                               |  246 +-
 lib/chef/null_logger.rb                            |    6 +-
 lib/chef/org.rb                                    |   61 +-
 lib/chef/platform.rb                               |    8 +-
 lib/chef/platform/handler_map.rb                   |   40 +
 lib/chef/platform/priority_map.rb                  |   41 +
 lib/chef/platform/provider_handler_map.rb          |   29 +
 lib/chef/platform/provider_mapping.rb              |  339 +--
 lib/chef/platform/provider_priority_map.rb         |   89 +-
 lib/chef/platform/query_helpers.rb                 |   87 +-
 lib/chef/platform/rebooter.rb                      |   22 +-
 lib/chef/platform/resource_handler_map.rb          |   29 +
 lib/chef/platform/resource_priority_map.rb         |   36 +-
 lib/chef/platform/service_helpers.rb               |   90 +-
 lib/chef/policy_builder.rb                         |   17 +-
 lib/chef/policy_builder/dynamic.rb                 |  185 ++
 lib/chef/policy_builder/expand_node_object.rb      |   91 +-
 lib/chef/policy_builder/policyfile.rb              |  200 +-
 lib/chef/property.rb                               |  673 ++++++
 lib/chef/provider.rb                               |  318 ++-
 lib/chef/provider/apt_update.rb                    |   79 +
 lib/chef/provider/batch.rb                         |   20 +-
 lib/chef/provider/breakpoint.rb                    |    2 +-
 lib/chef/provider/cookbook_file.rb                 |   10 +-
 lib/chef/provider/cookbook_file/content.rb         |    8 +-
 lib/chef/provider/cron.rb                          |   16 +-
 lib/chef/provider/cron/aix.rb                      |    2 +-
 lib/chef/provider/cron/solaris.rb                  |    2 +-
 lib/chef/provider/cron/unix.rb                     |   13 +-
 lib/chef/provider/deploy.rb                        |   25 +-
 lib/chef/provider/deploy/revision.rb               |   18 +-
 lib/chef/provider/deploy/timestamped.rb            |    2 +-
 lib/chef/provider/directory.rb                     |   35 +-
 lib/chef/provider/dsc_resource.rb                  |  111 +-
 lib/chef/provider/dsc_script.rb                    |   34 +-
 lib/chef/provider/env.rb                           |   16 +-
 lib/chef/provider/env/windows.rb                   |    6 +-
 lib/chef/provider/erl_call.rb                      |   10 +-
 lib/chef/provider/execute.rb                       |   43 +-
 lib/chef/provider/file.rb                          |   53 +-
 lib/chef/provider/file/content.rb                  |    8 +-
 lib/chef/provider/git.rb                           |   68 +-
 lib/chef/provider/group.rb                         |   16 +-
 lib/chef/provider/group/aix.rb                     |   11 +-
 lib/chef/provider/group/dscl.rb                    |   20 +-
 lib/chef/provider/group/gpasswd.rb                 |    7 +-
 lib/chef/provider/group/groupadd.rb                |   16 +-
 lib/chef/provider/group/groupmod.rb                |    4 +-
 lib/chef/provider/group/pw.rb                      |    5 +-
 lib/chef/provider/group/suse.rb                    |    8 +-
 lib/chef/provider/group/usermod.rb                 |   17 +-
 lib/chef/provider/group/windows.rb                 |    8 +-
 lib/chef/provider/http_request.rb                  |   30 +-
 lib/chef/provider/ifconfig.rb                      |   35 +-
 lib/chef/provider/ifconfig/aix.rb                  |    8 +-
 lib/chef/provider/ifconfig/debian.rb               |   10 +-
 lib/chef/provider/ifconfig/redhat.rb               |    5 +-
 lib/chef/provider/link.rb                          |   26 +-
 lib/chef/provider/log.rb                           |    2 +-
 lib/chef/provider/lwrp_base.rb                     |  161 +-
 lib/chef/provider/mdadm.rb                         |    8 +-
 lib/chef/provider/mount.rb                         |   37 +-
 lib/chef/provider/mount/aix.rb                     |   29 +-
 lib/chef/provider/mount/mount.rb                   |   38 +-
 lib/chef/provider/mount/solaris.rb                 |   60 +-
 lib/chef/provider/mount/windows.rb                 |    8 +-
 lib/chef/provider/ohai.rb                          |    5 +-
 lib/chef/provider/osx_profile.rb                   |  256 ++
 lib/chef/provider/package.rb                       |  169 +-
 lib/chef/provider/package/aix.rb                   |   33 +-
 lib/chef/provider/package/apt.rb                   |   31 +-
 lib/chef/provider/package/chocolatey.rb            |  277 +++
 lib/chef/provider/package/dpkg.rb                  |  233 +-
 lib/chef/provider/package/easy_install.rb          |   31 +-
 lib/chef/provider/package/freebsd/base.rb          |   16 +-
 lib/chef/provider/package/freebsd/pkg.rb           |   20 +-
 lib/chef/provider/package/freebsd/pkgng.rb         |   16 +-
 lib/chef/provider/package/freebsd/port.rb          |   12 +-
 lib/chef/provider/package/homebrew.rb              |   35 +-
 lib/chef/provider/package/ips.rb                   |   23 +-
 lib/chef/provider/package/macports.rb              |   13 +-
 lib/chef/provider/package/openbsd.rb               |   38 +-
 lib/chef/provider/package/pacman.rb                |   24 +-
 lib/chef/provider/package/paludis.rb               |   18 +-
 lib/chef/provider/package/portage.rb               |   27 +-
 lib/chef/provider/package/rpm.rb                   |   34 +-
 lib/chef/provider/package/rubygems.rb              |  135 +-
 lib/chef/provider/package/smartos.rb               |   24 +-
 lib/chef/provider/package/solaris.rb               |   33 +-
 lib/chef/provider/package/windows.rb               |  218 +-
 lib/chef/provider/package/windows/exe.rb           |  117 +
 lib/chef/provider/package/windows/msi.rb           |   60 +-
 .../package/windows/registry_uninstall_entry.rb    |   89 +
 lib/chef/provider/package/yum-dump.py              |    2 +-
 lib/chef/provider/package/yum.rb                   |  244 +-
 lib/chef/provider/package/zypper.rb                |  117 +-
 lib/chef/provider/powershell_script.rb             |  219 +-
 lib/chef/provider/reboot.rb                        |   11 +-
 lib/chef/provider/registry_key.rb                  |   44 +-
 lib/chef/provider/remote_directory.rb              |  302 ++-
 lib/chef/provider/remote_file.rb                   |   11 +-
 .../provider/remote_file/cache_control_data.rb     |   58 +-
 lib/chef/provider/remote_file/content.rb           |   21 +-
 lib/chef/provider/remote_file/fetcher.rb           |   34 +-
 lib/chef/provider/remote_file/ftp.rb               |   22 +-
 lib/chef/provider/remote_file/http.rb              |   20 +-
 lib/chef/provider/remote_file/local_file.rb        |   22 +-
 lib/chef/provider/remote_file/network_file.rb      |   48 +
 lib/chef/provider/route.rb                         |  376 +--
 lib/chef/provider/ruby_block.rb                    |    6 +-
 lib/chef/provider/script.rb                        |   11 +-
 lib/chef/provider/service.rb                       |   91 +-
 lib/chef/provider/service/aix.rb                   |   31 +-
 lib/chef/provider/service/aixinit.rb               |   24 +-
 lib/chef/provider/service/arch.rb                  |   10 +-
 lib/chef/provider/service/debian.rb                |   33 +-
 lib/chef/provider/service/freebsd.rb               |   18 +-
 lib/chef/provider/service/gentoo.rb                |   14 +-
 lib/chef/provider/service/init.rb                  |   11 +-
 lib/chef/provider/service/insserv.rb               |   12 +-
 lib/chef/provider/service/invokercd.rb             |   10 +-
 lib/chef/provider/service/macosx.rb                |   42 +-
 lib/chef/provider/service/openbsd.rb               |   33 +-
 lib/chef/provider/service/redhat.rb                |   72 +-
 lib/chef/provider/service/simple.rb                |   23 +-
 lib/chef/provider/service/solaris.rb               |   70 +-
 lib/chef/provider/service/systemd.rb               |   16 +-
 lib/chef/provider/service/upstart.rb               |   29 +-
 lib/chef/provider/service/windows.rb               |  111 +-
 lib/chef/provider/subversion.rb                    |   40 +-
 lib/chef/provider/template.rb                      |   14 +-
 lib/chef/provider/template/content.rb              |   30 +-
 lib/chef/provider/template_finder.rb               |    3 +-
 lib/chef/provider/user.rb                          |   23 +-
 lib/chef/provider/user/aix.rb                      |   10 +-
 lib/chef/provider/user/dscl.rb                     |  264 +-
 lib/chef/provider/user/pw.rb                       |   17 +-
 lib/chef/provider/user/solaris.rb                  |   42 +-
 lib/chef/provider/user/useradd.rb                  |   19 +-
 lib/chef/provider/user/windows.rb                  |   32 +-
 lib/chef/provider/whyrun_safe_ruby_block.rb        |    2 +-
 lib/chef/provider/windows_script.rb                |   18 +-
 lib/chef/provider_resolver.rb                      |  158 +-
 lib/chef/providers.rb                              |  222 +-
 lib/chef/recipe.rb                                 |   44 +-
 lib/chef/request_id.rb                             |    8 +-
 lib/chef/resource.rb                               |  831 +++++--
 lib/chef/resource/action_class.rb                  |   87 +
 lib/chef/resource/apt_package.rb                   |   25 +-
 lib/chef/resource/apt_update.rb                    |   33 +
 lib/chef/resource/bash.rb                          |   11 +-
 lib/chef/resource/batch.rb                         |   10 +-
 lib/chef/resource/bff_package.rb                   |   14 +-
 lib/chef/resource/breakpoint.rb                    |   15 +-
 lib/chef/resource/chef_gem.rb                      |   43 +-
 lib/chef/resource/chocolatey_package.rb            |   39 +
 lib/chef/resource/conditional.rb                   |   16 +-
 .../resource/conditional_action_not_nothing.rb     |    2 +-
 lib/chef/resource/cookbook_file.rb                 |   24 +-
 lib/chef/resource/cron.rb                          |   72 +-
 lib/chef/resource/csh.rb                           |   11 +-
 lib/chef/resource/deploy.rb                        |  172 +-
 lib/chef/resource/deploy_revision.rb               |   16 +-
 lib/chef/resource/directory.rb                     |   30 +-
 lib/chef/resource/dpkg_package.rb                  |   15 +-
 lib/chef/resource/dsc_resource.rb                  |  204 +-
 lib/chef/resource/dsc_script.rb                    |   57 +-
 lib/chef/resource/easy_install_package.rb          |   38 +-
 lib/chef/resource/env.rb                           |   24 +-
 lib/chef/resource/erl_call.rb                      |   36 +-
 lib/chef/resource/execute.rb                       |   69 +-
 lib/chef/resource/file.rb                          |  133 +-
 lib/chef/resource/file/verification.rb             |   22 +-
 lib/chef/resource/freebsd_package.rb               |   24 +-
 lib/chef/resource/gem_package.rb                   |   34 +-
 lib/chef/resource/git.rb                           |   11 +-
 lib/chef/resource/group.rb                         |   43 +-
 lib/chef/resource/homebrew_package.rb              |   27 +-
 lib/chef/resource/http_request.rb                  |   30 +-
 lib/chef/resource/ifconfig.rb                      |   64 +-
 lib/chef/resource/ips_package.rb                   |   24 +-
 lib/chef/resource/ksh.rb                           |   32 +
 lib/chef/resource/link.rb                          |   43 +-
 lib/chef/resource/log.rb                           |   25 +-
 lib/chef/resource/lwrp_base.rb                     |  183 +-
 lib/chef/resource/macosx_service.rb                |   17 +-
 lib/chef/resource/macports_package.rb              |   13 +-
 lib/chef/resource/mdadm.rb                         |   44 +-
 lib/chef/resource/mount.rb                         |   82 +-
 lib/chef/resource/ohai.rb                          |   19 +-
 lib/chef/resource/openbsd_package.rb               |   30 +-
 lib/chef/resource/osx_profile.rb                   |   74 +
 lib/chef/resource/package.rb                       |   90 +-
 lib/chef/resource/pacman_package.rb                |   12 +-
 lib/chef/resource/paludis_package.rb               |   17 +-
 lib/chef/resource/perl.rb                          |   12 +-
 lib/chef/resource/portage_package.rb               |   11 +-
 lib/chef/resource/powershell_script.rb             |   17 +-
 lib/chef/resource/python.rb                        |   12 +-
 lib/chef/resource/reboot.rb                        |   16 +-
 lib/chef/resource/registry_key.rb                  |   41 +-
 lib/chef/resource/remote_directory.rb              |   55 +-
 lib/chef/resource/remote_file.rb                   |   49 +-
 lib/chef/resource/resource_notification.rb         |   19 +-
 lib/chef/resource/route.rb                         |   61 +-
 lib/chef/resource/rpm_package.rb                   |   22 +-
 lib/chef/resource/ruby.rb                          |   13 +-
 lib/chef/resource/ruby_block.rb                    |   21 +-
 lib/chef/resource/scm.rb                           |   80 +-
 lib/chef/resource/script.rb                        |   30 +-
 lib/chef/resource/service.rb                       |   79 +-
 lib/chef/resource/smartos_package.rb               |   16 +-
 lib/chef/resource/solaris_package.rb               |   22 +-
 lib/chef/resource/subversion.rb                    |   18 +-
 lib/chef/resource/template.rb                      |   42 +-
 lib/chef/resource/timestamped_deploy.rb            |    6 +-
 lib/chef/resource/user.rb                          |   69 +-
 lib/chef/resource/whyrun_safe_ruby_block.rb        |    8 +-
 lib/chef/resource/windows_package.rb               |   73 +-
 lib/chef/resource/windows_script.rb                |   25 +-
 lib/chef/resource/windows_service.rb               |   24 +-
 lib/chef/resource/yum_package.rb                   |   54 +-
 lib/chef/resource/zypper_package.rb                |   28 +
 lib/chef/resource_builder.rb                       |   20 +-
 lib/chef/resource_collection.rb                    |   22 +-
 .../resource_collection_serialization.rb           |   10 +-
 lib/chef/resource_collection/resource_list.rb      |   12 +-
 lib/chef/resource_collection/resource_set.rb       |   12 +-
 lib/chef/resource_collection/stepable_iterator.rb  |    8 +-
 lib/chef/resource_definition.rb                    |   15 +-
 lib/chef/resource_definition_list.rb               |   10 +-
 lib/chef/resource_reporter.rb                      |   50 +-
 lib/chef/resource_resolver.rb                      |  192 +-
 lib/chef/resources.rb                              |  144 +-
 lib/chef/rest.rb                                   |   49 +-
 lib/chef/role.rb                                   |   92 +-
 lib/chef/run_context.rb                            |  557 ++++-
 lib/chef/run_context/cookbook_compiler.rb          |   23 +-
 lib/chef/run_list.rb                               |   34 +-
 lib/chef/run_list/run_list_expansion.rb            |   71 +-
 lib/chef/run_list/run_list_item.rb                 |   17 +-
 lib/chef/run_list/versioned_recipe_list.rb         |   48 +-
 lib/chef/run_lock.rb                               |   69 +-
 lib/chef/run_status.rb                             |   12 +-
 lib/chef/runner.rb                                 |   46 +-
 lib/chef/scan_access_control.rb                    |   14 +-
 lib/chef/search/query.rb                           |   64 +-
 lib/chef/server_api.rb                             |   52 +-
 lib/chef/shell.rb                                  |   51 +-
 lib/chef/shell/ext.rb                              |   62 +-
 lib/chef/shell/model_wrapper.rb                    |   15 +-
 lib/chef/shell/shell_rest.rb                       |   28 -
 lib/chef/shell/shell_session.rb                    |   39 +-
 lib/chef/shell_out.rb                              |    4 +-
 lib/chef/tasks/chef_repo.rake                      |  125 +-
 lib/chef/user.rb                                   |   98 +-
 lib/chef/user_v1.rb                                |  330 +++
 lib/chef/util/backup.rb                            |   18 +-
 lib/chef/util/diff.rb                              |   20 +-
 lib/chef/util/dsc/configuration_generator.rb       |   22 +-
 lib/chef/util/dsc/lcm_output_parser.rb             |   16 +-
 lib/chef/util/dsc/local_configuration_manager.rb   |   18 +-
 lib/chef/util/dsc/resource_info.rb                 |   30 +-
 lib/chef/util/dsc/resource_store.rb                |  147 +-
 lib/chef/util/editor.rb                            |    3 +-
 lib/chef/util/file_edit.rb                         |   10 +-
 lib/chef/util/path_helper.rb                       |  210 +-
 lib/chef/util/powershell/cmdlet.rb                 |  238 +-
 lib/chef/util/powershell/cmdlet_result.rb          |   72 +-
 lib/chef/util/powershell/ps_credential.rb          |    7 +-
 lib/chef/util/selinux.rb                           |   12 +-
 lib/chef/util/threaded_job_queue.rb                |    4 +-
 lib/chef/util/windows.rb                           |   34 +-
 lib/chef/util/windows/net_group.rb                 |   90 +-
 lib/chef/util/windows/net_use.rb                   |  110 +-
 lib/chef/util/windows/net_user.rb                  |  199 +-
 lib/chef/util/windows/volume.rb                    |   42 +-
 lib/chef/version.rb                                |   16 +-
 lib/chef/version/platform.rb                       |   10 +-
 lib/chef/version_class.rb                          |   12 +-
 lib/chef/version_constraint.rb                     |   26 +-
 lib/chef/version_constraint/platform.rb            |    6 +-
 lib/chef/whitelist.rb                              |    4 +-
 lib/chef/win32/api.rb                              |   23 +-
 lib/chef/win32/api/crypto.rb                       |  126 +-
 lib/chef/win32/api/error.rb                        |   21 +-
 lib/chef/win32/api/file.rb                         |   97 +-
 lib/chef/win32/api/installer.rb                    |   33 +-
 lib/chef/win32/api/memory.rb                       |    8 +-
 lib/chef/win32/api/net.rb                          |  263 +-
 lib/chef/win32/api/process.rb                      |    8 +-
 lib/chef/win32/api/psapi.rb                        |    8 +-
 lib/chef/win32/api/registry.rb                     |   51 +
 lib/chef/win32/api/security.rb                     |  101 +-
 lib/chef/win32/api/synchronization.rb              |    8 +-
 lib/chef/win32/api/system.rb                       |   31 +-
 lib/chef/win32/api/unicode.rb                      |   51 +-
 lib/chef/win32/crypto.rb                           |   99 +-
 lib/chef/win32/error.rb                            |   33 +-
 lib/chef/win32/eventlog.rb                         |   31 +
 lib/chef/win32/file.rb                             |   56 +-
 lib/chef/win32/file/info.rb                        |    7 +-
 lib/chef/win32/file/version_info.rb                |   93 +
 lib/chef/win32/handle.rb                           |   12 +-
 lib/chef/win32/memory.rb                           |    8 +-
 lib/chef/win32/mutex.rb                            |   11 +-
 lib/chef/win32/net.rb                              |  311 +++
 lib/chef/win32/process.rb                          |   27 +-
 lib/chef/win32/registry.rb                         |  105 +-
 lib/chef/win32/security.rb                         |  153 +-
 lib/chef/win32/security/ace.rb                     |   12 +-
 lib/chef/win32/security/acl.rb                     |   16 +-
 lib/chef/win32/security/securable_object.rb        |   10 +-
 lib/chef/win32/security/security_descriptor.rb     |   10 +-
 lib/chef/win32/security/sid.rb                     |  141 +-
 lib/chef/win32/security/token.rb                   |   12 +-
 lib/chef/win32/system.rb                           |   62 +
 lib/chef/win32/unicode.rb                          |   19 +-
 lib/chef/win32/version.rb                          |   56 +-
 lib/chef/workstation_config_loader.rb              |  163 +-
 metadata.yml                                       | 2053 ----------------
 omnibus/.gitignore                                 |   10 +
 omnibus/.kitchen.local.yml.vmware.example          |    6 +
 omnibus/.kitchen.yml                               |  121 +
 omnibus/Berksfile                                  |   12 +
 omnibus/Gemfile                                    |   21 +
 omnibus/README.md                                  |  144 ++
 omnibus/config/projects/angrychef.rb               |   42 +
 omnibus/config/projects/chef-fips.rb               |   60 +
 omnibus/config/projects/chef.rb                    |   84 +
 omnibus/files/mapfiles/solaris                     |   18 +
 .../openssl-customization/windows/ssl_env_hack.rb  |   34 +
 omnibus/omnibus.rb                                 |   54 +
 omnibus/package-scripts/angrychef/postinst         |  111 +
 omnibus/package-scripts/angrychef/postrm           |   42 +
 omnibus/package-scripts/chef-fips/postinst         |  111 +
 omnibus/package-scripts/chef-fips/postrm           |   42 +
 omnibus/package-scripts/chef/postinst              |  111 +
 omnibus/package-scripts/chef/postrm                |   42 +
 omnibus/resources/chef/dmg/background.png          |  Bin 0 -> 44066 bytes
 omnibus/resources/chef/dmg/icon.png                |  Bin 0 -> 245378 bytes
 omnibus/resources/chef/msi/assets/LICENSE.rtf      |  197 ++
 .../chef/msi/assets/banner_background.bmp          |  Bin 0 -> 114432 bytes
 .../chef/msi/assets/dialog_background.bmp          |  Bin 0 -> 615320 bytes
 omnibus/resources/chef/msi/assets/oc.ico           |  Bin 0 -> 41880 bytes
 omnibus/resources/chef/msi/assets/oc_16x16.ico     |  Bin 0 -> 1286 bytes
 omnibus/resources/chef/msi/assets/oc_32x32.ico     |  Bin 0 -> 4682 bytes
 .../resources/chef/msi/localization-en-us.wxl.erb  |   30 +
 omnibus/resources/chef/msi/parameters.wxi.erb      |    9 +
 omnibus/resources/chef/msi/source.wxs.erb          |  192 ++
 omnibus/resources/chef/pkg/background.png          |  Bin 0 -> 55731 bytes
 omnibus/resources/chef/pkg/license.html.erb        |  202 ++
 omnibus/resources/chef/pkg/welcome.html.erb        |    5 +
 pedant.gemfile                                     |   25 +
 rubygems-pkg/rubygems-update-2.4.6.gem             |  Bin 0 -> 451072 bytes
 .../apt/chef-integration-test-1.0/debian/copyright |    4 +-
 .../apt/chef-integration-test-1.1/debian/copyright |    4 +-
 .../chef-integration-test2-1.0/debian/changelog    |    5 +
 .../debian/chef-integration-test2.debhelper.log    |   45 +
 .../debian/chef-integration-test2.substvars        |    1 +
 .../debian/chef-integration-test2/DEBIAN/conffiles |    1 +
 .../debian/chef-integration-test2/DEBIAN/control   |   10 +
 .../debian/chef-integration-test2/DEBIAN/md5sums   |    1 +
 .../apt/chef-integration-test2-1.0/debian/compat   |    1 +
 .../chef-integration-test2-1.0/debian/conffiles    |    1 +
 .../apt/chef-integration-test2-1.0/debian/control  |   13 +
 .../chef-integration-test2-1.0/debian/copyright    |   34 +
 .../apt/chef-integration-test2-1.0/debian/files    |    1 +
 .../apt/chef-integration-test2-1.0/debian/rules    |   13 +
 .../debian/source/format                           |    1 +
 .../apt/chef-integration-test2_1.0-1.debian.tar.gz |  Bin 0 -> 1369 bytes
 spec/data/apt/chef-integration-test2_1.0-1.dsc     |   18 +
 .../apt/chef-integration-test2_1.0-1_amd64.build   |   91 +
 .../apt/chef-integration-test2_1.0-1_amd64.changes |   31 +
 .../apt/chef-integration-test2_1.0-1_amd64.deb     |  Bin 0 -> 1694 bytes
 .../apt/chef-integration-test2_1.0.orig.tar.gz     |  Bin 0 -> 248 bytes
 .../name-mismatch-versionnumber/recipes/default.rb |    2 +-
 .../openldap/templates/default/helpers.erb         |   14 +
 .../templates/default/nested_openldap_partials.erb |    1 +
 .../openldap/templates/default/nested_partial.erb  |    1 +
 .../supports-platform-constraints/metadata.rb      |    5 +
 spec/data/dsc_lcm.pfx                              |  Bin 0 -> 2597 bytes
 .../incomplete-metadata/recipes/default.rb         |    2 +-
 .../invalid-metadata/metadata.rb                   |    3 +-
 .../invalid-metadata/recipes/default.rb            |    2 +-
 spec/data/lwrp/providers/buck_passer.rb            |   20 +-
 spec/data/lwrp/providers/buck_passer_2.rb          |   20 +-
 .../embedded_resource_accesses_providers_scope.rb  |   16 +-
 spec/data/lwrp_override/resources/foo.rb           |    5 +
 .../cookbooks/include/recipes/default.rb           |   24 +
 .../cookbooks/include/recipes/includee.rb          |    3 +
 spec/data/trusted_certs/opscode.pem                |  109 +-
 spec/functional/application_spec.rb                |   16 +-
 .../assets/chocolatey_feed/test-A.1.0.nupkg        |  Bin 0 -> 2667 bytes
 .../assets/chocolatey_feed/test-A.1.5.nupkg        |  Bin 0 -> 2669 bytes
 .../assets/chocolatey_feed/test-A.2.0.nupkg        |  Bin 0 -> 2667 bytes
 .../assets/chocolatey_feed/test-B.1.0.nupkg        |  Bin 0 -> 2667 bytes
 spec/functional/audit/rspec_formatter_spec.rb      |   16 +-
 spec/functional/audit/runner_spec.rb               |   84 +-
 spec/functional/dsl/reboot_pending_spec.rb         |   89 +-
 spec/functional/dsl/registry_helper_spec.rb        |   18 +-
 .../event_loggers/windows_eventlog_spec.rb         |   49 +-
 .../deploy_strategies_spec.rb                      |   19 +-
 spec/functional/http/simple_spec.rb                |   22 +-
 spec/functional/knife/configure_spec.rb            |   15 +-
 spec/functional/knife/cookbook_delete_spec.rb      |   46 +-
 spec/functional/knife/exec_spec.rb                 |   12 +-
 spec/functional/knife/smoke_test.rb                |   14 +-
 spec/functional/knife/ssh_spec.rb                  |   74 +-
 spec/functional/mixin/powershell_out_spec.rb       |   43 +
 spec/functional/mixin/shell_out_spec.rb            |   24 +-
 spec/functional/notifications_spec.rb              |   83 +-
 .../remote_file/cache_control_data_spec.rb         |   23 +-
 .../provider/whyrun_safe_ruby_block_spec.rb        |    8 +-
 spec/functional/rebooter_spec.rb                   |   28 +-
 spec/functional/resource/aix_service_spec.rb       |   19 +-
 spec/functional/resource/aixinit_service_spec.rb   |   42 +-
 spec/functional/resource/base.rb                   |    4 +-
 spec/functional/resource/bash_spec.rb              |   12 +-
 spec/functional/resource/batch_spec.rb             |   10 +-
 spec/functional/resource/bff_spec.rb               |   22 +-
 .../functional/resource/chocolatey_package_spec.rb |  124 +
 spec/functional/resource/cookbook_file_spec.rb     |   18 +-
 spec/functional/resource/cron_spec.rb              |   26 +-
 spec/functional/resource/deploy_revision_spec.rb   |   38 +-
 spec/functional/resource/directory_spec.rb         |    8 +-
 spec/functional/resource/dpkg_package_spec.rb      |  339 +++
 spec/functional/resource/dsc_resource_spec.rb      |   39 +-
 spec/functional/resource/dsc_script_spec.rb        |  277 ++-
 spec/functional/resource/env_spec.rb               |   60 +-
 spec/functional/resource/execute_spec.rb           |   31 +-
 spec/functional/resource/file_spec.rb              |   44 +-
 spec/functional/resource/git_spec.rb               |   40 +-
 spec/functional/resource/group_spec.rb             |  158 +-
 spec/functional/resource/ifconfig_spec.rb          |   26 +-
 spec/functional/resource/link_spec.rb              |  287 ++-
 spec/functional/resource/mount_spec.rb             |   49 +-
 spec/functional/resource/ohai_spec.rb              |   13 +-
 spec/functional/resource/package_spec.rb           |   26 +-
 spec/functional/resource/powershell_script_spec.rb |  601 +++++
 spec/functional/resource/powershell_spec.rb        |  477 ----
 spec/functional/resource/reboot_spec.rb            |   24 +-
 spec/functional/resource/registry_spec.rb          |  143 +-
 spec/functional/resource/remote_directory_spec.rb  |   46 +-
 spec/functional/resource/remote_file_spec.rb       |   34 +-
 spec/functional/resource/rpm_spec.rb               |   28 +-
 spec/functional/resource/template_spec.rb          |   16 +-
 spec/functional/resource/user/dscl_spec.rb         |    6 +-
 spec/functional/resource/user/useradd_spec.rb      |   96 +-
 spec/functional/resource/user/windows_spec.rb      |  133 ++
 spec/functional/resource/windows_package_spec.rb   |  168 ++
 spec/functional/resource/windows_service_spec.rb   |   20 +-
 spec/functional/rest_spec.rb                       |   11 +-
 spec/functional/run_lock_spec.rb                   |  568 +++--
 spec/functional/shell_spec.rb                      |   52 +-
 spec/functional/tiny_server_spec.rb                |   36 +-
 spec/functional/util/path_helper_spec.rb           |   10 +-
 spec/functional/util/powershell/cmdlet_spec.rb     |   51 +-
 spec/functional/version_spec.rb                    |   12 +-
 spec/functional/win32/crypto_spec.rb               |   17 +-
 spec/functional/win32/registry_helper_spec.rb      |  632 -----
 spec/functional/win32/registry_spec.rb             |  623 +++++
 spec/functional/win32/security_spec.rb             |   34 +-
 spec/functional/win32/service_manager_spec.rb      |   19 +-
 spec/functional/win32/sid_spec.rb                  |   55 +
 spec/functional/win32/version_info_spec.rb         |   50 +
 spec/functional/win32/versions_spec.rb             |   26 +-
 spec/integration/client/client_spec.rb             |  302 ++-
 spec/integration/client/ipv6_spec.rb               |   31 +-
 spec/integration/knife/chef_fs_data_store_spec.rb  |  678 ++++--
 spec/integration/knife/chef_repo_path_spec.rb      |  524 ++--
 .../knife/chef_repository_file_system_spec.rb      |  168 +-
 spec/integration/knife/chefignore_spec.rb          |  164 +-
 spec/integration/knife/common_options_spec.rb      |   82 +-
 spec/integration/knife/cookbook_api_ipv6_spec.rb   |   18 +-
 spec/integration/knife/delete_spec.rb              |  510 ++--
 spec/integration/knife/deps_spec.rb                |  616 +++--
 spec/integration/knife/diff_spec.rb                |  474 ++--
 spec/integration/knife/download_spec.rb            |  928 +++++---
 spec/integration/knife/list_spec.rb                |  434 +++-
 spec/integration/knife/raw_spec.rb                 |   78 +-
 spec/integration/knife/redirection_spec.rb         |   24 +-
 spec/integration/knife/serve_spec.rb               |   24 +-
 spec/integration/knife/show_spec.rb                |  118 +-
 spec/integration/knife/upload_spec.rb              | 1224 +++++-----
 .../recipes/lwrp_inline_resources_spec.rb          |  126 +-
 spec/integration/recipes/lwrp_spec.rb              |   53 +
 spec/integration/recipes/provider_choice.rb        |   37 +
 spec/integration/recipes/recipe_dsl_spec.rb        | 1519 ++++++++++++
 spec/integration/recipes/remote_directory.rb       |   74 +
 spec/integration/recipes/resource_action_spec.rb   |  569 +++++
 .../recipes/resource_converge_if_changed_spec.rb   |  496 ++++
 spec/integration/recipes/resource_load_spec.rb     |  208 ++
 spec/integration/solo/solo_spec.rb                 |   83 +-
 spec/scripts/ssl-serve.rb                          |   29 +-
 spec/spec_helper.rb                                |  125 +-
 spec/stress/win32/file_spec.rb                     |   10 +-
 spec/stress/win32/memory_spec.rb                   |    8 +-
 spec/stress/win32/security_spec.rb                 |   16 +-
 spec/support/chef_helpers.rb                       |   11 +-
 spec/support/key_helpers.rb                        |  104 +
 spec/support/lib/chef/provider/easy.rb             |    4 +-
 .../support/lib/chef/provider/openldap_includer.rb |   29 +
 spec/support/lib/chef/provider/snakeoil.rb         |    4 +-
 spec/support/lib/chef/resource/cat.rb              |    9 +-
 .../lib/chef/resource/one_two_three_four.rb        |   10 +-
 .../support/lib/chef/resource/openldap_includer.rb |   26 +
 spec/support/lib/chef/resource/with_state.rb       |   17 +-
 spec/support/lib/chef/resource/zen_follower.rb     |   13 +-
 spec/support/lib/chef/resource/zen_master.rb       |   18 +-
 spec/support/lib/library_load_order.rb             |    2 -
 spec/support/matchers/leak.rb                      |   12 +-
 spec/support/mock/constant.rb                      |    6 +-
 spec/support/mock/platform.rb                      |   12 +-
 spec/support/pedant/Gemfile                        |    3 -
 spec/support/pedant/pedant_config.rb               |  129 -
 spec/support/pedant/run_pedant.rb                  |   63 -
 spec/support/pedant/stickywicket.pem               |   27 -
 spec/support/platform_helpers.rb                   |   74 +-
 spec/support/platforms/prof/gc.rb                  |    5 +-
 spec/support/platforms/prof/win32.rb               |    7 +-
 spec/support/platforms/win32/spec_service.rb       |    6 +-
 spec/support/shared/context/client.rb              |  285 +++
 spec/support/shared/context/config.rb              |    6 +-
 spec/support/shared/context/win32.rb               |   34 +
 spec/support/shared/examples/client.rb             |   53 +
 spec/support/shared/functional/diff_disabled.rb    |    2 +-
 .../shared/functional/directory_resource.rb        |   16 +-
 spec/support/shared/functional/file_resource.rb    |   47 +-
 spec/support/shared/functional/http.rb             |   67 +-
 spec/support/shared/functional/knife.rb            |    6 +-
 .../shared/functional/securable_resource.rb        |  162 +-
 .../securable_resource_with_reporting.rb           |   28 +-
 spec/support/shared/functional/win32_service.rb    |    7 +-
 spec/support/shared/functional/windows_script.rb   |   99 +-
 .../shared/integration/app_server_support.rb       |   14 +-
 .../shared/integration/integration_helper.rb       |   57 +-
 spec/support/shared/integration/knife_support.rb   |   26 +-
 spec/support/shared/matchers/exit_with_code.rb     |    4 +-
 .../shared/matchers/match_environment_variable.rb  |    4 +-
 spec/support/shared/shared_examples.rb             |    2 +-
 spec/support/shared/unit/api_error_inspector.rb    |    8 +-
 spec/support/shared/unit/api_versioning.rb         |   77 +
 spec/support/shared/unit/execute_resource.rb       |   13 +-
 spec/support/shared/unit/file_system_support.rb    |   25 +-
 spec/support/shared/unit/knife_shared.rb           |   39 +
 spec/support/shared/unit/mock_shellout.rb          |   49 +
 spec/support/shared/unit/platform_introspector.rb  |   69 +-
 spec/support/shared/unit/provider/file.rb          |   98 +-
 .../unit/provider/useradd_based_user_provider.rb   |  101 +-
 .../unit/resource/static_provider_resolution.rb    |    7 +-
 spec/support/shared/unit/script_resource.rb        |   20 +-
 spec/support/shared/unit/user_and_client_shared.rb |  114 +
 .../support/shared/unit/windows_script_resource.rb |   13 +-
 spec/tiny_server.rb                                |   54 +-
 spec/unit/api_client/registration_spec.rb          |   88 +-
 spec/unit/api_client_spec.rb                       |   49 +-
 spec/unit/api_client_v1_spec.rb                    |  455 ++++
 spec/unit/application/apply_spec.rb                |    6 +-
 spec/unit/application/client_spec.rb               |   47 +-
 spec/unit/application/knife_spec.rb                |   90 +-
 spec/unit/application/solo_spec.rb                 |   76 +-
 spec/unit/application_spec.rb                      |  456 ++--
 spec/unit/audit/audit_event_proxy_spec.rb          |   26 +-
 spec/unit/audit/audit_reporter_spec.rb             |   93 +-
 spec/unit/audit/control_group_data_spec.rb         |   33 +-
 spec/unit/audit/logger_spec.rb                     |   42 +
 spec/unit/audit/rspec_formatter_spec.rb            |    8 +-
 spec/unit/audit/runner_spec.rb                     |   27 +-
 spec/unit/chef_class_spec.rb                       |   33 +-
 spec/unit/chef_fs/config_spec.rb                   |   32 +-
 .../chef_fs/data_handler/group_handler_spec.rb     |   34 +-
 spec/unit/chef_fs/diff_spec.rb                     |  150 +-
 spec/unit/chef_fs/file_pattern_spec.rb             |  755 +++---
 .../chef_fs/file_system/cookbook_subdir_spec.rb    |   34 +
 .../file_system/operation_failed_error_spec.rb     |   18 +-
 spec/unit/chef_fs/file_system_spec.rb              |  148 +-
 spec/unit/chef_fs/parallelizer.rb                  |  129 +-
 spec/unit/chef_fs/path_util_spec.rb                |  108 +
 spec/unit/chef_spec.rb                             |    6 +-
 spec/unit/client_spec.rb                           |  550 ++---
 spec/unit/config_fetcher_spec.rb                   |   84 +-
 spec/unit/config_spec.rb                           |  547 +----
 spec/unit/cookbook/chefignore_spec.rb              |   24 +-
 spec/unit/cookbook/cookbook_version_loader_spec.rb |   13 +-
 spec/unit/cookbook/file_vendor_spec.rb             |   17 +-
 spec/unit/cookbook/metadata_spec.rb                |  280 ++-
 spec/unit/cookbook/synchronizer_spec.rb            |   63 +-
 spec/unit/cookbook/syntax_check_spec.rb            |   49 +-
 spec/unit/cookbook_loader_spec.rb                  |   19 +-
 spec/unit/cookbook_manifest_spec.rb                |   55 +-
 spec/unit/cookbook_site_streaming_uploader_spec.rb |   69 +-
 spec/unit/cookbook_spec.rb                         |   15 +-
 spec/unit/cookbook_uploader_spec.rb                |   21 +-
 .../unit/cookbook_version_file_specificity_spec.rb |   99 +-
 spec/unit/cookbook_version_spec.rb                 |  115 +-
 spec/unit/daemon_spec.rb                           |   10 +-
 spec/unit/data_bag_item_spec.rb                    |   61 +-
 spec/unit/data_bag_spec.rb                         |   98 +-
 spec/unit/deprecation_spec.rb                      |   86 +-
 spec/unit/digester_spec.rb                         |   11 +-
 spec/unit/dsl/audit_spec.rb                        |   10 +-
 spec/unit/dsl/data_query_spec.rb                   |   24 +-
 spec/unit/dsl/platform_introspection_spec.rb       |   39 +-
 spec/unit/dsl/reboot_pending_spec.rb               |   50 +-
 spec/unit/dsl/recipe_spec.rb                       |   10 +-
 spec/unit/dsl/regsitry_helper_spec.rb              |   21 +-
 spec/unit/dsl/resources_spec.rb                    |   85 +
 .../check_encrypted_spec.rb                        |   14 +-
 spec/unit/encrypted_data_bag_item_spec.rb          |   22 +-
 spec/unit/environment_spec.rb                      |  108 +-
 spec/unit/event_dispatch/dispatcher_spec.rb        |  122 +
 spec/unit/event_dispatch/dsl_spec.rb               |   83 +
 spec/unit/exceptions_spec.rb                       |   26 +-
 spec/unit/file_access_control_spec.rb              |   64 +-
 spec/unit/file_cache_spec.rb                       |   38 +-
 .../unit/file_content_management/deploy/cp_spec.rb |    8 +-
 .../file_content_management/deploy/mv_unix_spec.rb |    8 +-
 .../deploy/mv_windows_spec.rb                      |   69 +-
 spec/unit/formatters/base_spec.rb                  |   35 +-
 spec/unit/formatters/doc_spec.rb                   |   78 +
 .../error_inspectors/api_error_formatting_spec.rb  |   76 +
 .../compile_error_inspector_spec.rb                |  297 ++-
 .../cookbook_resolve_error_inspector_spec.rb       |   11 +-
 .../cookbook_sync_error_inspector_spec.rb          |    6 +-
 .../node_load_error_inspector_spec.rb              |    7 +-
 .../registration_error_inspector_spec.rb           |    7 +-
 .../resource_failure_inspector_spec.rb             |   17 +-
 .../run_list_expansion_error_inspector_spec.rb     |   12 +-
 .../resource_guard_interpreter_spec.rb             |   26 +-
 spec/unit/guard_interpreter_spec.rb                |    6 +-
 spec/unit/handler/json_file_spec.rb                |   23 +-
 spec/unit/handler_spec.rb                          |   14 +-
 spec/unit/http/authenticator_spec.rb               |   80 +
 spec/unit/http/basic_client_spec.rb                |   22 +-
 spec/unit/http/http_request_spec.rb                |   44 +-
 spec/unit/http/json_input_spec.rb                  |   14 +-
 spec/unit/http/simple_spec.rb                      |    6 +-
 spec/unit/http/socketless_chef_zero_client_spec.rb |    7 +-
 spec/unit/http/ssl_policies_spec.rb                |   37 +-
 spec/unit/http/validate_content_length_spec.rb     |   18 +-
 spec/unit/http_spec.rb                             |  136 +-
 spec/unit/json_compat_spec.rb                      |   30 +-
 spec/unit/key_spec.rb                              |  631 +++++
 .../knife/bootstrap/chef_vault_handler_spec.rb     |   83 +-
 spec/unit/knife/bootstrap/client_builder_spec.rb   |   81 +-
 spec/unit/knife/bootstrap_spec.rb                  |  235 +-
 spec/unit/knife/client_bulk_delete_spec.rb         |   20 +-
 spec/unit/knife/client_create_spec.rb              |  182 +-
 spec/unit/knife/client_delete_spec.rb              |   30 +-
 spec/unit/knife/client_edit_spec.rb                |   27 +-
 spec/unit/knife/client_list_spec.rb                |   12 +-
 spec/unit/knife/client_reregister_spec.rb          |   26 +-
 spec/unit/knife/client_show_spec.rb                |   24 +-
 spec/unit/knife/configure_client_spec.rb           |   39 +-
 spec/unit/knife/configure_spec.rb                  |   76 +-
 spec/unit/knife/cookbook_bulk_delete_spec.rb       |   36 +-
 spec/unit/knife/cookbook_create_spec.rb            |   64 +-
 spec/unit/knife/cookbook_delete_spec.rb            |  158 +-
 spec/unit/knife/cookbook_download_spec.rb          |  169 +-
 spec/unit/knife/cookbook_list_spec.rb              |   52 +-
 .../unit/knife/cookbook_metadata_from_file_spec.rb |   10 +-
 spec/unit/knife/cookbook_metadata_spec.rb          |  110 +-
 spec/unit/knife/cookbook_show_spec.rb              |   67 +-
 spec/unit/knife/cookbook_site_download_spec.rb     |  104 +-
 spec/unit/knife/cookbook_site_install_spec.rb      |   18 +-
 spec/unit/knife/cookbook_site_share_spec.rb        |   84 +-
 spec/unit/knife/cookbook_site_unshare_spec.rb      |   40 +-
 spec/unit/knife/cookbook_test_spec.rb              |   12 +-
 spec/unit/knife/cookbook_upload_spec.rb            |  138 +-
 spec/unit/knife/core/bootstrap_context_spec.rb     |   98 +-
 spec/unit/knife/core/cookbook_scm_repo_spec.rb     |   64 +-
 .../unit/knife/core/custom_manifest_loader_spec.rb |   41 +
 spec/unit/knife/core/gem_glob_loader_spec.rb       |  209 ++
 spec/unit/knife/core/hashed_command_loader_spec.rb |   93 +
 spec/unit/knife/core/node_editor_spec.rb           |  211 ++
 spec/unit/knife/core/object_loader_spec.rb         |   24 +-
 spec/unit/knife/core/subcommand_loader_spec.rb     |  208 +-
 spec/unit/knife/core/ui_spec.rb                    |  102 +-
 spec/unit/knife/data_bag_create_spec.rb            |   28 +-
 spec/unit/knife/data_bag_edit_spec.rb              |   24 +-
 spec/unit/knife/data_bag_from_file_spec.rb         |   20 +-
 spec/unit/knife/data_bag_secret_options_spec.rb    |   12 +-
 spec/unit/knife/data_bag_show_spec.rb              |   38 +-
 spec/unit/knife/environment_compare_spec.rb        |   64 +-
 spec/unit/knife/environment_create_spec.rb         |    4 +-
 spec/unit/knife/environment_delete_spec.rb         |    4 +-
 spec/unit/knife/environment_edit_spec.rb           |    4 +-
 spec/unit/knife/environment_from_file_spec.rb      |   12 +-
 spec/unit/knife/environment_list_spec.rb           |    8 +-
 spec/unit/knife/environment_show_spec.rb           |    4 +-
 spec/unit/knife/index_rebuild_spec.rb              |   31 +-
 spec/unit/knife/key_create_spec.rb                 |  223 ++
 spec/unit/knife/key_delete_spec.rb                 |  133 ++
 spec/unit/knife/key_edit_spec.rb                   |  264 ++
 spec/unit/knife/key_helper.rb                      |   74 +
 spec/unit/knife/key_list_spec.rb                   |  216 ++
 spec/unit/knife/key_show_spec.rb                   |  126 +
 spec/unit/knife/knife_help.rb                      |    4 +-
 spec/unit/knife/node_bulk_delete_spec.rb           |   23 +-
 spec/unit/knife/node_delete_spec.rb                |    8 +-
 spec/unit/knife/node_edit_spec.rb                  |   35 +-
 spec/unit/knife/node_environment_set_spec.rb       |    8 +-
 spec/unit/knife/node_from_file_spec.rb             |   10 +-
 spec/unit/knife/node_list_spec.rb                  |   11 +-
 spec/unit/knife/node_run_list_add_spec.rb          |   13 +-
 spec/unit/knife/node_run_list_remove_spec.rb       |   59 +-
 spec/unit/knife/node_run_list_set_spec.rb          |    8 +-
 spec/unit/knife/node_show_spec.rb                  |   12 +-
 spec/unit/knife/osc_user_create_spec.rb            |   93 +
 spec/unit/knife/osc_user_delete_spec.rb            |   44 +
 spec/unit/knife/osc_user_edit_spec.rb              |   52 +
 spec/unit/knife/osc_user_list_spec.rb              |   37 +
 spec/unit/knife/osc_user_reregister_spec.rb        |   58 +
 spec/unit/knife/osc_user_show_spec.rb              |   46 +
 spec/unit/knife/raw_spec.rb                        |   12 +-
 spec/unit/knife/role_bulk_delete_spec.rb           |    8 +-
 spec/unit/knife/role_create_spec.rb                |    8 +-
 spec/unit/knife/role_delete_spec.rb                |    8 +-
 spec/unit/knife/role_edit_spec.rb                  |   10 +-
 spec/unit/knife/role_env_run_list_add_spec.rb      |   18 +-
 spec/unit/knife/role_env_run_list_clear_spec.rb    |   82 +-
 spec/unit/knife/role_env_run_list_remove_spec.rb   |   98 +-
 spec/unit/knife/role_env_run_list_replace_spec.rb  |  101 +-
 spec/unit/knife/role_env_run_list_set_spec.rb      |   37 +-
 spec/unit/knife/role_from_file_spec.rb             |   14 +-
 spec/unit/knife/role_list_spec.rb                  |   12 +-
 spec/unit/knife/role_run_list_add_spec.rb          |   14 +-
 spec/unit/knife/role_run_list_clear_spec.rb        |   62 +-
 spec/unit/knife/role_run_list_remove_spec.rb       |   78 +-
 spec/unit/knife/role_run_list_replace_spec.rb      |   87 +-
 spec/unit/knife/role_run_list_set_spec.rb          |   15 +-
 spec/unit/knife/role_show_spec.rb                  |   28 +-
 spec/unit/knife/ssh_spec.rb                        |  113 +-
 spec/unit/knife/ssl_check_spec.rb                  |   28 +-
 spec/unit/knife/ssl_fetch_spec.rb                  |   20 +-
 spec/unit/knife/status_spec.rb                     |   36 +-
 spec/unit/knife/tag_create_spec.rb                 |    2 +-
 spec/unit/knife/tag_delete_spec.rb                 |    2 +-
 spec/unit/knife/tag_list_spec.rb                   |    4 +-
 spec/unit/knife/user_create_spec.rb                |  230 +-
 spec/unit/knife/user_delete_spec.rb                |   52 +-
 spec/unit/knife/user_edit_spec.rb                  |   55 +-
 spec/unit/knife/user_list_spec.rb                  |   18 +-
 spec/unit/knife/user_reregister_spec.rb            |   69 +-
 spec/unit/knife/user_show_spec.rb                  |   56 +-
 spec/unit/knife_spec.rb                            |  178 +-
 spec/unit/lib_backcompat_spec.rb                   |   34 +
 spec/unit/log/syslog_spec.rb                       |   53 +
 spec/unit/log/winevt_spec.rb                       |   55 +
 spec/unit/log_spec.rb                              |   10 +-
 spec/unit/lwrp_spec.rb                             |  497 +++-
 spec/unit/mash_spec.rb                             |   16 +-
 .../mixin/api_version_request_handling_spec.rb     |  126 +
 spec/unit/mixin/checksum_spec.rb                   |   11 +-
 spec/unit/mixin/command_spec.rb                    |   21 +-
 spec/unit/mixin/convert_to_class_name_spec.rb      |    4 +-
 spec/unit/mixin/deep_merge_spec.rb                 |  214 +-
 spec/unit/mixin/deprecation_spec.rb                |   10 +-
 .../enforce_ownership_and_permissions_spec.rb      |   30 +-
 spec/unit/mixin/homebrew_user_spec.rb              |   26 +-
 spec/unit/mixin/params_validate_spec.rb            |  144 +-
 spec/unit/mixin/path_sanity_spec.rb                |   36 +-
 spec/unit/mixin/powershell_out_spec.rb             |   70 +
 spec/unit/mixin/powershell_type_coercions_spec.rb  |   57 +-
 spec/unit/mixin/properties_spec.rb                 |   97 +
 spec/unit/mixin/proxified_socket_spec.rb           |   94 +
 spec/unit/mixin/securable_spec.rb                  |   74 +-
 spec/unit/mixin/shell_out_spec.rb                  |  136 +-
 spec/unit/mixin/subclass_directive_spec.rb         |   45 +
 spec/unit/mixin/template_spec.rb                   |   37 +-
 spec/unit/mixin/unformatter_spec.rb                |   61 +
 spec/unit/mixin/uris_spec.rb                       |   57 +
 .../unit/mixin/windows_architecture_helper_spec.rb |   42 +-
 spec/unit/mixin/xml_escape_spec.rb                 |    6 +-
 spec/unit/monkey_patches/uri_spec.rb               |    6 +-
 spec/unit/monologger_spec.rb                       |    8 +-
 spec/unit/node/attribute_spec.rb                   |  451 ++--
 spec/unit/node/immutable_collections_spec.rb       |   41 +-
 spec/unit/node_map_spec.rb                         |   27 +-
 spec/unit/node_spec.rb                             |  496 +++-
 spec/unit/org_spec.rb                              |   34 +-
 spec/unit/platform/query_helpers_spec.rb           |  165 +-
 spec/unit/platform_spec.rb                         |   96 +-
 spec/unit/policy_builder/dynamic_spec.rb           |  273 +++
 .../unit/policy_builder/expand_node_object_spec.rb |  105 +-
 spec/unit/policy_builder/policyfile_spec.rb        |  371 ++-
 spec/unit/policy_builder_spec.rb                   |    8 +-
 spec/unit/property/state_spec.rb                   |  508 ++++
 spec/unit/property/validation_spec.rb              |  704 ++++++
 spec/unit/property_spec.rb                         | 1227 ++++++++++
 spec/unit/provider/apt_update_spec.rb              |  113 +
 spec/unit/provider/breakpoint_spec.rb              |    5 +-
 spec/unit/provider/cookbook_file/content_spec.rb   |   19 +-
 spec/unit/provider/cookbook_file_spec.rb           |   22 +-
 spec/unit/provider/cron/unix_spec.rb               |   14 +-
 spec/unit/provider/cron_spec.rb                    |  134 +-
 spec/unit/provider/deploy/revision_spec.rb         |   15 +-
 spec/unit/provider/deploy/timestamped_spec.rb      |    4 +-
 spec/unit/provider/deploy_spec.rb                  |   63 +-
 spec/unit/provider/directory_spec.rb               |  373 +--
 spec/unit/provider/dsc_resource_spec.rb            |  110 +-
 spec/unit/provider/dsc_script_spec.rb              |   99 +-
 spec/unit/provider/env/windows_spec.rb             |   42 +-
 spec/unit/provider/env_spec.rb                     |   10 +-
 spec/unit/provider/erl_call_spec.rb                |    7 +-
 spec/unit/provider/execute_spec.rb                 |  131 +-
 spec/unit/provider/file/content_spec.rb            |    8 +-
 spec/unit/provider/file_spec.rb                    |   17 +-
 spec/unit/provider/git_spec.rb                     |  129 +-
 spec/unit/provider/group/dscl_spec.rb              |   14 +-
 spec/unit/provider/group/gpasswd_spec.rb           |    6 +-
 spec/unit/provider/group/groupadd_spec.rb          |   18 +-
 spec/unit/provider/group/groupmod_spec.rb          |   24 +-
 spec/unit/provider/group/pw_spec.rb                |    6 +-
 spec/unit/provider/group/usermod_spec.rb           |   12 +-
 spec/unit/provider/group/windows_spec.rb           |    6 +-
 spec/unit/provider/group_spec.rb                   |   32 +-
 spec/unit/provider/http_request_spec.rb            |   14 +-
 spec/unit/provider/ifconfig/aix_spec.rb            |    9 +-
 spec/unit/provider/ifconfig/debian_spec.rb         |   22 +-
 spec/unit/provider/ifconfig/redhat_spec.rb         |    6 +-
 spec/unit/provider/ifconfig_spec.rb                |   34 +-
 spec/unit/provider/link_spec.rb                    |   24 +-
 spec/unit/provider/log_spec.rb                     |    4 +-
 spec/unit/provider/mdadm_spec.rb                   |   24 +-
 spec/unit/provider/mount/aix_spec.rb               |   17 +-
 spec/unit/provider/mount/mount_spec.rb             |   46 +-
 spec/unit/provider/mount/solaris_spec.rb           |   52 +-
 spec/unit/provider/mount/windows_spec.rb           |   24 +-
 spec/unit/provider/mount_spec.rb                   |   28 +-
 spec/unit/provider/ohai_spec.rb                    |   26 +-
 spec/unit/provider/osx_profile_spec.rb             |  249 ++
 spec/unit/provider/package/aix_spec.rb             |   52 +-
 spec/unit/provider/package/apt_spec.rb             |   98 +-
 spec/unit/provider/package/chocolatey_spec.rb      |  504 ++++
 spec/unit/provider/package/dpkg_spec.rb            |  296 ++-
 spec/unit/provider/package/easy_install_spec.rb    |   26 +-
 spec/unit/provider/package/freebsd/pkg_spec.rb     |   36 +-
 spec/unit/provider/package/freebsd/pkgng_spec.rb   |   39 +-
 spec/unit/provider/package/freebsd/port_spec.rb    |   35 +-
 spec/unit/provider/package/homebrew_spec.rb        |  278 +--
 spec/unit/provider/package/ips_spec.rb             |   65 +-
 spec/unit/provider/package/macports_spec.rb        |   26 +-
 spec/unit/provider/package/openbsd_spec.rb         |  100 +-
 spec/unit/provider/package/pacman_spec.rb          |   17 +-
 spec/unit/provider/package/paludis_spec.rb         |   19 +-
 spec/unit/provider/package/portage_spec.rb         |    4 +-
 spec/unit/provider/package/rpm_spec.rb             |  480 +++-
 spec/unit/provider/package/rubygems_spec.rb        |  699 +++---
 spec/unit/provider/package/smartos_spec.rb         |   98 +-
 spec/unit/provider/package/solaris_spec.rb         |   30 +-
 spec/unit/provider/package/windows/exe_spec.rb     |  187 ++
 spec/unit/provider/package/windows/msi_spec.rb     |  114 +-
 spec/unit/provider/package/windows_spec.rb         |  366 ++-
 spec/unit/provider/package/yum_spec.rb             |  541 +++--
 spec/unit/provider/package/zypper_spec.rb          |  248 +-
 spec/unit/provider/package_spec.rb                 |  881 ++++---
 spec/unit/provider/package_spec.rbe                |    0
 spec/unit/provider/powershell_script_spec.rb       |  106 +
 spec/unit/provider/powershell_spec.rb              |   38 -
 spec/unit/provider/registry_key_spec.rb            |   18 +-
 spec/unit/provider/remote_directory_spec.rb        |   99 +-
 .../remote_file/cache_control_data_spec.rb         |  115 +-
 spec/unit/provider/remote_file/content_spec.rb     |   11 +-
 spec/unit/provider/remote_file/fetcher_spec.rb     |   27 +-
 spec/unit/provider/remote_file/ftp_spec.rb         |    6 +-
 spec/unit/provider/remote_file/http_spec.rb        |   22 +-
 spec/unit/provider/remote_file/local_file_spec.rb  |   35 +-
 .../unit/provider/remote_file/network_file_spec.rb |   45 +
 spec/unit/provider/remote_file_spec.rb             |   20 +-
 spec/unit/provider/route_spec.rb                   |   53 +-
 spec/unit/provider/ruby_block_spec.rb              |    9 +-
 spec/unit/provider/script_spec.rb                  |   26 +-
 spec/unit/provider/service/aix_service_spec.rb     |   48 +-
 spec/unit/provider/service/aixinit_service_spec.rb |   49 +-
 spec/unit/provider/service/arch_service_spec.rb    |   30 +-
 spec/unit/provider/service/debian_service_spec.rb  |   74 +-
 spec/unit/provider/service/freebsd_service_spec.rb |   30 +-
 spec/unit/provider/service/gentoo_service_spec.rb  |   14 +-
 spec/unit/provider/service/init_service_spec.rb    |   18 +-
 spec/unit/provider/service/insserv_service_spec.rb |    6 +-
 .../provider/service/invokercd_service_spec.rb     |   18 +-
 spec/unit/provider/service/macosx_spec.rb          |   56 +-
 spec/unit/provider/service/openbsd_service_spec.rb |   68 +-
 spec/unit/provider/service/redhat_spec.rb          |  118 +-
 spec/unit/provider/service/simple_service_spec.rb  |   10 +-
 .../provider/service/solaris_smf_service_spec.rb   |  159 +-
 spec/unit/provider/service/systemd_service_spec.rb |    8 +-
 spec/unit/provider/service/upstart_service_spec.rb |   61 +-
 spec/unit/provider/service/windows_spec.rb         |  454 ++--
 spec/unit/provider/service_spec.rb                 |    5 +-
 spec/unit/provider/subversion_spec.rb              |  100 +-
 spec/unit/provider/template/content_spec.rb        |  117 +-
 spec/unit/provider/template_spec.rb                |   31 +-
 spec/unit/provider/user/dscl_spec.rb               |   89 +-
 spec/unit/provider/user/pw_spec.rb                 |   24 +-
 spec/unit/provider/user/solaris_spec.rb            |   83 +-
 spec/unit/provider/user/useradd_spec.rb            |   20 +-
 spec/unit/provider/user/windows_spec.rb            |   22 +-
 spec/unit/provider/user_spec.rb                    |   54 +-
 spec/unit/provider/whyrun_safe_ruby_block_spec.rb  |    7 +-
 spec/unit/provider_resolver_spec.rb                | 1230 ++++++----
 spec/unit/provider_spec.rb                         |   37 +-
 spec/unit/pure_application_spec.rb                 |    6 +-
 spec/unit/recipe_spec.rb                           |  154 +-
 spec/unit/registry_helper_spec.rb                  |  376 ---
 spec/unit/resource/apt_package_spec.rb             |    8 +-
 spec/unit/resource/apt_update_spec.rb              |   38 +
 spec/unit/resource/bash_spec.rb                    |    6 +-
 spec/unit/resource/batch_spec.rb                   |    9 +-
 spec/unit/resource/breakpoint_spec.rb              |    8 +-
 spec/unit/resource/chef_gem_spec.rb                |   16 +-
 spec/unit/resource/chocolatey_package_spec.rb      |   67 +
 .../conditional_action_not_nothing_spec.rb         |    4 +-
 spec/unit/resource/conditional_spec.rb             |   24 +-
 spec/unit/resource/cookbook_file_spec.rb           |   47 +-
 spec/unit/resource/cron_spec.rb                    |   10 +-
 spec/unit/resource/csh_spec.rb                     |    6 +-
 spec/unit/resource/deploy_revision_spec.rb         |    6 +-
 spec/unit/resource/deploy_spec.rb                  |   55 +-
 spec/unit/resource/directory_spec.rb               |   10 +-
 spec/unit/resource/dpkg_package_spec.rb            |   10 +-
 spec/unit/resource/dsc_resource_spec.rb            |   41 +-
 spec/unit/resource/dsc_script_spec.rb              |   38 +-
 spec/unit/resource/easy_install_package_spec.rb    |    6 +-
 spec/unit/resource/env_spec.rb                     |   12 +-
 spec/unit/resource/erl_call_spec.rb                |    8 +-
 spec/unit/resource/execute_spec.rb                 |    8 +-
 spec/unit/resource/file/verification_spec.rb       |   52 +-
 spec/unit/resource/file_spec.rb                    |   22 +-
 spec/unit/resource/freebsd_package_spec.rb         |   15 +-
 spec/unit/resource/gem_package_spec.rb             |    8 +-
 spec/unit/resource/git_spec.rb                     |    6 +-
 spec/unit/resource/group_spec.rb                   |   10 +-
 spec/unit/resource/homebrew_package_spec.rb        |   26 +-
 spec/unit/resource/http_request_spec.rb            |   10 +-
 spec/unit/resource/ifconfig_spec.rb                |   22 +-
 spec/unit/resource/ips_package_spec.rb             |    8 +-
 spec/unit/resource/ksh_spec.rb                     |   40 +
 spec/unit/resource/link_spec.rb                    |   14 +-
 spec/unit/resource/log_spec.rb                     |    6 +-
 spec/unit/resource/macports_package_spec.rb        |    6 +-
 spec/unit/resource/mdadm_spec.rb                   |    8 +-
 spec/unit/resource/mount_spec.rb                   |   16 +-
 spec/unit/resource/ohai_spec.rb                    |    7 +-
 spec/unit/resource/openbsd_package_spec.rb         |   11 +-
 spec/unit/resource/osx_profile_spec.rb             |   61 +
 spec/unit/resource/package_spec.rb                 |   12 +-
 spec/unit/resource/pacman_package_spec.rb          |    6 +-
 spec/unit/resource/perl_spec.rb                    |    6 +-
 spec/unit/resource/portage_package_spec.rb         |    4 +-
 spec/unit/resource/powershell_script_spec.rb       |  136 ++
 spec/unit/resource/powershell_spec.rb              |  131 -
 spec/unit/resource/python_spec.rb                  |    6 +-
 spec/unit/resource/registry_key_spec.rb            |   44 +-
 spec/unit/resource/remote_directory_spec.rb        |    6 +-
 spec/unit/resource/remote_file_spec.rb             |   41 +-
 spec/unit/resource/resource_notification_spec.rb   |   95 +-
 spec/unit/resource/route_spec.rb                   |    6 +-
 spec/unit/resource/rpm_package_spec.rb             |    8 +-
 spec/unit/resource/ruby_block_spec.rb              |   12 +-
 spec/unit/resource/ruby_spec.rb                    |    6 +-
 spec/unit/resource/scm_spec.rb                     |   16 +-
 spec/unit/resource/script_spec.rb                  |    8 +-
 spec/unit/resource/service_spec.rb                 |   13 +-
 spec/unit/resource/smartos_package_spec.rb         |    6 +-
 spec/unit/resource/solaris_package_spec.rb         |    6 +-
 spec/unit/resource/subversion_spec.rb              |   14 +-
 spec/unit/resource/template_spec.rb                |   17 +-
 spec/unit/resource/timestamped_deploy_spec.rb      |   11 +-
 spec/unit/resource/user_spec.rb                    |   10 +-
 spec/unit/resource/windows_package_spec.rb         |   24 +-
 spec/unit/resource/windows_service_spec.rb         |    6 +-
 spec/unit/resource/yum_package_spec.rb             |   21 +-
 .../unit/resource_collection/resource_list_spec.rb |   14 +-
 spec/unit/resource_collection/resource_set_spec.rb |   18 +-
 .../resource_collection/stepable_iterator_spec.rb  |   12 +-
 spec/unit/resource_collection_spec.rb              |   19 +-
 spec/unit/resource_definition_spec.rb              |    6 +-
 spec/unit/resource_reporter_spec.rb                |  125 +-
 spec/unit/resource_resolver_spec.rb                |   52 +
 spec/unit/resource_spec.rb                         |  826 ++++---
 spec/unit/rest/auth_credentials_spec.rb            |  110 +-
 spec/unit/rest_spec.rb                             |  200 +-
 spec/unit/role_spec.rb                             |  136 +-
 spec/unit/run_context/child_run_context_spec.rb    |  133 ++
 spec/unit/run_context/cookbook_compiler_spec.rb    |   12 +-
 spec/unit/run_context_spec.rb                      |   93 +-
 spec/unit/run_list/run_list_expansion_spec.rb      |   59 +-
 spec/unit/run_list/run_list_item_spec.rb           |   56 +-
 spec/unit/run_list/versioned_recipe_list_spec.rb   |  179 +-
 spec/unit/run_list_spec.rb                         |   80 +-
 spec/unit/run_lock_spec.rb                         |   20 +-
 spec/unit/run_status_spec.rb                       |    9 +-
 spec/unit/runner_spec.rb                           |   16 +-
 spec/unit/scan_access_control_spec.rb              |    9 +-
 spec/unit/search/query_spec.rb                     |  110 +-
 spec/unit/shell/model_wrapper_spec.rb              |   25 +-
 spec/unit/shell/shell_ext_spec.rb                  |   10 +-
 spec/unit/shell/shell_session_spec.rb              |   17 +-
 spec/unit/shell_out_spec.rb                        |    2 +-
 spec/unit/shell_spec.rb                            |   26 +-
 spec/unit/user_spec.rb                             |   50 +-
 spec/unit/user_v1_spec.rb                          |  583 +++++
 spec/unit/util/backup_spec.rb                      |   35 +-
 spec/unit/util/diff_spec.rb                        |   15 +-
 spec/unit/util/dsc/configuration_generator_spec.rb |   96 +-
 spec/unit/util/dsc/lcm_output_parser_spec.rb       |   44 +-
 .../util/dsc/local_configuration_manager_spec.rb   |   61 +-
 spec/unit/util/dsc/resource_store.rb               |   44 +-
 spec/unit/util/editor_spec.rb                      |  130 +-
 spec/unit/util/file_edit_spec.rb                   |   14 +-
 spec/unit/util/path_helper_spec.rb                 |  255 --
 spec/unit/util/powershell/cmdlet_spec.rb           |   54 +-
 spec/unit/util/powershell/ps_credential_spec.rb    |   27 +-
 spec/unit/util/selinux_spec.rb                     |   17 +-
 spec/unit/util/threaded_job_queue_spec.rb          |    4 +-
 spec/unit/version/platform_spec.rb                 |   11 +-
 spec/unit/version_class_spec.rb                    |   17 +-
 spec/unit/version_constraint/platform_spec.rb      |    7 +-
 spec/unit/version_constraint_spec.rb               |   38 +-
 spec/unit/win32/registry_spec.rb                   |  394 +++
 spec/unit/windows_service_spec.rb                  |  125 +-
 spec/unit/workstation_config_loader_spec.rb        |  283 ---
 tasks/cbgb.rb                                      |   84 +
 tasks/external_tests.rb                            |   64 +
 tasks/maintainers.rb                               |  210 ++
 tasks/rspec.rb                                     |   44 +-
 1641 files changed, 78026 insertions(+), 36858 deletions(-)

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..bb9914a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,6 @@
+# git config merge.ignore.name 'ignore changes merge driver'
+# git config merge.ignore.driver 'touch %A'
+distro/common/html/* merge=ignore
+distro/common/man/man1/* merge=ignore
+distro/common/man/man8/* merge=ignore
+lib/chef/version.rb merge=ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ddd269b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,61 @@
+.autotest
+coverage
+.DS_Store
+pkg/*
+tags
+*/tags
+*~
+.chef
+
+# You should check in your Gemfile.lock in applications, and not in gems
+# This also matches Berksfile.lock
+external_tests/*.lock
+acceptance/Gemfile.lock
+omnibus/Gemfile.lock
+/*.lock
+/Gemfile.local
+
+# Do not check in the .bundle directory, or any of the files inside it. Those
+# files are specific to each particular machine, and are used to persist
+# installation options between runs of the bundle install command.
+.bundle
+
+# ignore some common Bundler 'binstubs' directory names
+# http://gembundler.com/man/bundle-exec.1.html
+b/
+binstubs/
+bin
+!bin/chef-apply
+!bin/chef-client
+!bin/chef-service-manager
+!bin/chef-shell
+!bin/chef-solo
+!bin/chef-windows-service
+!bin/knife
+# RVM and RBENV ruby version files
+.rbenv-version
+.rvmrc
+.ruby-version
+.ruby-gemset
+
+# IDE files
+.project
+
+# Documentation
+_site/*
+.yardoc/
+doc/
+
+# Test Kitchen
+.kitchen/
+
+# Vagrant
+Vagrantfile
+.vagrant/
+
+# Kitchen Tests Local Mode Data
+kitchen-tests/nodes/*
+
+# Temporary files present during spec runs
+spec/data/test-dir
+/config/
diff --git a/.kitchen.yml b/.kitchen.yml
new file mode 100644
index 0000000..ed49eb3
--- /dev/null
+++ b/.kitchen.yml
@@ -0,0 +1,82 @@
+driver:
+  name: vagrant
+  forward_agent: yes
+  customize:
+    cpus: 4
+    memory: 4096
+  synced_folders:
+    - ['.', '/home/vagrant/chef']
+
+provisioner:
+  name: chef_zero
+  require_chef_omnibus: 12.0.0.rc.1
+
+platforms:
+  - name: centos-5.10
+    run_list:
+  - name: centos-6.5
+    run_list:
+  - name: debian-7.2.0
+    run_list:
+  - name: debian-7.4
+    run_list:
+  - name: debian-6.0.8
+    run_list:
+  - name: freebsd-9.2
+    run_list:
+  - name: freebsd-10.0
+    run_list:
+  - name: ubuntu-10.04
+    run_list:
+  - name: ubuntu-12.04
+    run_list:
+  - name: ubuntu-12.10
+    run_list:
+  - name: ubuntu-13.04
+    run_list:
+  - name: ubuntu-13.10
+    run_list:
+  - name: ubuntu-14.04
+    run_list:
+  # The following boxes are shared via VagrantCloud. Until kitchen-vagrant
+  # is updated you'll need to add the box manually:
+  #
+  #   vagrant box add chef/windows-8.1-professional
+  #
+  # Please note this may require a `vagrant login` if the box is private.
+  #
+  # The following boxes are VMware only also. You can enable VMware Fusion
+  # as the default provider by copying `.kitchen.local.yml.vmware.example`
+  # over to `.kitchen.local.yml`.
+  #
+  - name: macosx-10.8
+    driver:
+      box: chef/macosx-10.8 # private
+  - name: macosx-10.9
+    driver:
+      box: chef/macosx-10.9 # private
+  - name: macosx-10.10
+    driver:
+      box: chef/macosx-10.10 # private
+  # - name: windows-7-professional
+  #   provisioner:
+  #     name: windows_chef_zero
+  #     require_chef_omnibus: 11.12.4
+  #   driver:
+  #     box: chef/windows-7-professional # private
+  # - name: windows-8.1-professional
+  #   provisioner:
+  #     name: windows_chef_zero
+  #     require_chef_omnibus: 11.12.4
+  #   driver:
+  #     box: chef/windows-8.1-professional # private
+  # - name: windows-2008r2-standard
+  #   provisioner:
+  #     name: windows_chef_zero
+  #     require_chef_omnibus: 11.12.4
+  #   driver:
+  #     box: chef/windows-server-2008r2-standard # private
+
+suites:
+  - name: chef
+    run_list:
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..a7b6b6b
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,117 @@
+# Daniel DeLeo
+Daniel DeLeo <dan at chef.io> Daniel DeLeo <dan at opscode.com>
+Daniel DeLeo <dan at chef.io> Dan DeLeo <danielsdeleo at mac.com>
+Daniel DeLeo <dan at chef.io> Dan DeLeo <dan at kallistec.com>
+Daniel DeLeo <dan at chef.io> danielsdeleo <dan at getchef.com>
+Daniel DeLeo <dan at chef.io> danielsdeleo <dan at opscode.com>
+Daniel DeLeo <dan at chef.io> Daniel DeLeo <danielsdeleo at mac.com>
+
+# Adam Jacob
+Adam Jacob <adam at chef.io> Adam Jacob <adam at opscode.com>
+Adam Jacob <adam at chef.io> Adam Jacob <adam at hjksolutions.com>
+Adam Jacob <adam at chef.io> Adam Jacob <adam at latte.(none)>
+Adam Jacob <adam at chef.io> Adam Jacob <adam at ubuntu-apache1.(none)>
+
+# Bryan McLellan
+Bryan McLellan <btm at chef.io> Bryan McLellan <btm at getchef.com>
+Bryan McLellan <btm at chef.io> Bryan McLellan <bryan.mclellan at webtrends.com>
+Bryan McLellan <btm at chef.io> Bryan McLellan <btm at opscode.com>
+Bryan McLellan <btm at chef.io> Bryan McLellan <btm at loftninjas.org>
+Bryan McLellan <btm at chef.io> Bryan McLellan <bryanm at widemile.com>
+
+# Lamont Granquist
+Lamont Granquist <lamont at chef.io> Lamont Granquist <lamont at getchef.com>
+Lamont Granquist <lamont at chef.io> lamont-opscode <lamont at opscode.com>
+Lamont Granquist <lamont at chef.io> Lamont Granquist <lamont at opscode.com>
+Lamont Granquist <lamont at chef.io> Lamont Granquist <lamont at scriptkiddie.org>
+Lamont Granquist <lamont at chef.io> lamont-granquist <lamont at scriptkiddie.org>
+
+# Serdar Sutay
+Serdar Sutay <serdar at chef.io> Serdar Sutay <serdar at opscode.com>
+Serdar Sutay <serdar at chef.io> sersut <serdar at opscode.com>
+Serdar Sutay <serdar at chef.io> ssutay <serdar at opscode.com>
+
+# Claire McQuin
+Claire McQuin <claire at chef.io> Claire McQuin <claire at getchef.com>
+Claire McQuin <claire at chef.io> Claire McQuin <mcquin at users.noreply.github.com>
+Claire McQuin <claire at chef.io> Claire McQuin <claire at opscode.com>
+Claire McQuin <claire at chef.io> Claire McQuin <clairemcquin at seamcquin01.local>
+
+# John Keiser
+John Keiser <jkeiser at chef.io> John Keiser <jkeiser at opscode.com>
+John Keiser <jkeiser at chef.io> jkeiser <jkeiser at opscode.com>
+John Keiser <jkeiser at chef.io> John Keiser <john at johnkeiser.com>
+John Keiser <jkeiser at chef.io> John Keiser <johnkeiser at John-Keisers-MacBook-Pro.local>
+
+# Seth Chisamore
+Seth Chisamore <schisamo at chef.io> Seth Chisamore <schisamo at getchef.com>
+Seth Chisamore <schisamo at chef.io> Seth Chisamore <schisamo at opscode.com>
+
+# Joshua Timberman
+Joshua Timberman <joshua at chef.io> jtimberman <joshua at chef.io>
+Joshua Timberman <joshua at chef.io> Joshua Timberman <joshua at opscode.com>
+Joshua Timberman <joshua at chef.io> Joshua Timberman <jtimberman at cider.local>
+Joshua Timberman <joshua at chef.io> Joshua Timberman <jtimberman at users.noreply.github.com>
+Joshua Timberman <joshua at chef.io> jtimberman <joshua.timberman at gmail.com>
+Joshua Timberman <joshua at chef.io> jtimberman <joshua at opscode.com>
+Joshua Timberman <joshua at chef.io> jtimberman <jtimberman at www1test.housepub.org>
+
+# Nuo Yan
+Nuo Yan <nuo at opscode.com>
+Nuo Yan <nuo at opscode.com> Nuo Yan <nuoyan at nuo-yans-macbook-pro.(none)>
+Nuo Yan <nuo at opscode.com> Nuo Yan <nuoyan at nuo-yans-macbook-pro.local>
+
+# Thom May
+Thom May <thom at clearairturbulence.org>
+Thom May <thom at clearairturbulence.org> Thom May <thom.may at betfair.com>
+Thom May <thom at clearairturbulence.org> Thom May <thom at digital-science.com>
+Thom May <thom at clearairturbulence.org> Thom May <thom at virelais.nyc.joostas.com>
+Thom May <thom at clearairturbulence.org> Thom May <tmay at expedia.com>
+
+# Stephen Delano
+Stephen Delano <stephen at chef.io> Stephen Delano <stephen at opscode.com>
+Stephen Delano <stephen at chef.io> Stephen Delano <stephen at opscode-stephen.(none)>
+Stephen Delano <stephen at chef.io> Stephen Delano <stephen at opscode-stephen.local>
+Stephen Delano <stephen at chef.io> sdelano <stephen at opscode.com>
+
+# AJ Christensen
+AJ Christensen <aj at opscode.com>
+AJ Christensen <aj at opscode.com> AJ Christensen <aj at junglist.gen.nz>
+
+# Seth Falcon
+Seth Falcon <seth at chef.io> Seth Falcon <seth at opscode.com>
+Seth Falcon <seth at chef.io> Seth Falcon <sethfalcon at gmail.com>
+
+# Adam Edwards
+Adam Edwards <adamed at chef.io> Adam Edwards <adamed at opscode.com>
+Adam Edwards <adamed at chef.io> adamedx <adamed at getchef.com>
+Adam Edwards <adamed at chef.io> adamedx <adamed at opscode.com>
+Adam Edwards <adamed at chef.io> adamedx <admed at opscode.com>
+
+# Prajakta Purohit
+Prajakta Purohit <prajakta at chef.io> Prajakta Purohit <prajakta at opscode.com>
+Prajakta Purohit <prajakta at chef.io> PrajaktaPurohit <prajakta at opscode.com>
+
+kaustubh-d <kaustubh at clogeny.com>
+kaustubh-d <kaustubh at clogeny.com> kaustubh <kaustubh.deo at gmail.com>
+kaustubh-d <kaustubh at clogeny.com> kaustubh-d <kausubh at clogeny.com>
+
+# Xabier de Zuazo
+Xabier de Zuazo <xabier at onddo.com>
+Xabier de Zuazo <xabier at onddo.com> Xabier de Zuazo <xabier.zuazo at evandti.com>
+Xabier de Zuazo <xabier at onddo.com> Xabier de Zuazo <xabier at zuazo.org>
+
+# Tim Hinderliter
+Tim Hinderliter <tim at opscode.com>
+Tim Hinderliter <tim at opscode.com> tim at opscode.com <tim at opscode.com>
+Tim Hinderliter <tim at opscode.com> timh <tim at opscode.com>
+
+# Mark Paradise
+Marc Paradise <marc at chef.io> Marc Paradise <marc at opscode.com>
+Marc Paradise <marc at chef.io> marc at opscode.com <marc at opscode.com>
+
+# Tyler Ball
+Tyler Ball <tyleraball at gmail.com> tyler-ball <tyleraball at gmail.com>
+
+# Steven Danna
+Steven Danna <steve at chef.io> Steven Danna <steve at opscode.com>
\ No newline at end of file
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..eb3ef03
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+-fd
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..3c2a48e
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,6 @@
+AllCops:
+  Exclude:
+    - "spec/data/**/*"
+    - "vendor/**/*"
+    - "pkg/**/*"
+    - "chef-config/pkg/**/*"
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..ea58b9b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,165 @@
+language: ruby
+cache: bundler
+
+sudo: false
+# Early warning system to catch if Rubygems breaks something
+before_install:
+  - gem update --system
+  - gem install bundler
+
+branches:
+  only:
+  - master
+  - 10-stable
+  - 11-stable
+
+# do not run expensive spec tests on PRs, only on branches
+script: "
+set -e;
+echo '--color\n-fp' > .rspec;
+sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers;
+sudo -E $(which bundle) exec rake spec;
+bundle exec rake style;
+bundle exec bundle-audit check --update;
+"
+
+env:
+  global:
+    - FORCE_FFI_YAJL=ext
+
+matrix:
+  include:
+  - rvm: 2.1
+    sudo: true
+    bundler_args: --without server docgen maintenance
+  - rvm: 2.2
+    sudo: true
+    bundler_args: --without server docgen maintenance
+  - rvm: rbx
+    sudo: true
+    bundler_args: --without server docgen maintenance ruby_prof
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'chef-zero', github: 'chef/chef-zero'\""
+    script: bundle exec rake chef_zero_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'cheffish', github: 'chef/cheffish'\""
+    script: bundle exec rake cheffish_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'chef-provisioning', github: 'chef/chef-provisioning'\""
+    script: bundle exec rake chef_provisioning_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'chef-provisioning-aws', github: 'chef/chef-provisioning-aws'\""
+    script: bundle exec rake chef_provisioning_aws_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'chefspec'\""
+    script: bundle exec rake chefspec_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'chef-sugar'\""
+    script: bundle exec rake chef_sugar_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'knife-windows', github: 'chef/knife-windows'\""
+    script: bundle exec rake knife_windows_spec
+  # Requires vagrant
+  # - rvm: 2.2
+  #   cache:
+  #   env: "GEMFILE_MOD=\"gem 'chef-rewind'\""
+  #   script: bundle exec rake chef_rewind_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'foodcritic', github: 'acrmp/foodcritic', branch: 'v5.0.0'\""
+    script: bundle exec rake foodcritic_spec
+  - rvm: 2.2
+    before_install:
+    env: "GEMFILE_MOD=\"gem 'halite', github: 'poise/halite'\""
+    script: bundle exec rake halite_spec
+  - rvm: 2.2
+    env: "GEMFILE_MOD=\"gem 'poise', github: 'poise/poise'\""
+    script: bundle exec rake poise_spec
+  ### START TEST KITCHEN ONLY ###
+  - rvm: 2.2
+    gemfile: kitchen-tests/Gemfile
+    before_install:
+    - echo -n $DO_KEY_CHUNK_{0..30} >> ~/.ssh/id_aws.base64
+    - cat ~/.ssh/id_aws.base64 | tr -d ' ' | base64 --decode > ~/.ssh/id_aws.pem
+    before_script:
+    - cd kitchen-tests
+    script:
+# FIXME: we should fix centos-6 against AWS and then enable it here
+    - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then bundle exec kitchen test ubuntu; fi
+    after_failure:
+    - cat .kitchen/logs/kitchen.log
+    after_script:
+    - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then bundle exec kitchen destroy ubuntu; fi
+    env:
+    - KITCHEN_YAML=.kitchen.travis.yml
+    - EC2_SSH_KEY_PATH=~/.ssh/id_aws.pem
+    - secure: VAauyVnAMWhqvnhJOJ/tCDn3XAdWqzbWiDVQPNBkqtm2SBIvhmZl2hlrusvw6YLU31Prdf8fSFhOSysVQQs/rJYrmD/1BfV79p6M7cGXYZ0nGWwldF81N296lyFoZLyrqtmG4G0cx3Pw2ojADFgFe+B5eTGlqJFD+z371g4RF/Y=
+    - secure: A+qtUF2LPJGkUAdvt04AwZMt69rzaeTyR0/1XEOAuntBKKXSCzddUzr5ePDc9QQ/57AWywKxhVLpnxk3QzKN7r7zerDxyIJBgklNDpNAKkeQjP3T6FpaKEIN9ROcpPtsM6FJ5Agb+bEQoRJF7s+ampO3wLV3XpTiWNuWkcAhv9A=
+    - secure: J8JIg15trrPgc8X/1DsaUWDQCdDWTvN/AorXzZ/ReudHS6G/KpoynZ5lTmKjlgFiFNE/TGMDv486pStGtIcarTKTuIEmNADdEWlAVH7bxclpayMjtppVuapRCkZWccs5gz5CJyhX7yhQCFTYoqVox9Y4qHGCluF3oqCcPRtCOOw=
+    - secure: NJYn0blTMwIoFxZlsoMWK8hPO/fi45rgWOqEImnjvSRk++5WL+GgjLBgLvEi7wCMkBijhIMWtnva60ojd4MrxeS7evrmGRjJKXnPuSKEsrGbArZPskBjCAcg+3PlnQQUkFf6hvbGD3HZlJtcbs4hrx8tbDT2Ie7bmQfqpsawKY4=
+    - secure: FipoX1VzZkzPUP6Gxd05DEva7cX6xKK2Wdq+Y18nNkyW2afPLXCNl5kCsNrgvbqAzbjKaP2M8+b0zwKjrFzNebqmmx1RRfZUJWUkNRF1EgE+tHytmMZW6tNcQlTlvA0KqXi4Dt6SIQ0l/DhwwNKZ80jmpiyYi/ErxIXzbVgVtYA=
+    - secure: T2MbE9twIkdaor796/lDioCgb2+FP3G8lXq+lIqnjaL22WMP8yKtkjNo8ggSlvQZE7MAQHqi5LISw5MU2MI6ImTU50/pgdWreM5Cx37WWYqntcbJ0Sz7v396KGJzeqbDql1fGolHDlykfi+OJzzbIGC8cjz7iAD2RUZU95wEC5s=
+    - secure: hWEQInvuanQavFCE3m6/q9BjNEFZQmLc94EWnBKTMiwUAdYgQQMLohN7K1Gc8irxYKp86F+P+XWE4lfDZNK3sqmxyk51TtT2EfmKWs+jSLq4+NBYQwXCpRELC5Irpm0GRCYthhsQSuarpVWss/0s0o7iJQaHxrSPcQiwDouIpwU=
+    - secure: OllJUaR/WUu+H0FIjU7vQxU10JT4d+/FZuTqnX6ZTcXN3dXCirnabYp/j+r5OBY3QeOojOyzGfHUWYEUGH/PTxcxYjrohtFTWht9N9x+SxfX2fLqieH/kRKyDmIidsY8qKChf/LD9f+SwpXRXND/PctKhNR4C5BH57fGUEqE9FU=
+    - secure: KgKnGtM4e+cVYfLn78eTWJ1q4ORv128abB72QBc/xiSh0rvxSIojVKZCXmRetQPXIl7NoIzU2IyjR1ABEZ+vA83PayTEsOr2KDRDgolSIgZSSiDFt4U2phQsxl4fX7wFv/jWlbxM2fysKBSIRAF57CwBjGhLjmpUO+5PdoR7N2s=
+    - secure: IgOx4STauKnJWENQGcn2iBp32XcNd2anNR0Fua0ugjudu1+CV+IxcIhI8ohOfZEXyVK4MGTF8uXWrYtoiwyExG4mTXqpRWJCgIkncqiWlfT+8BoAGWxCQhUYub3MaNZANPgebKPJhTPQ8OwNz09gPMNkewRfAqNF05eb8FU2kGA=
+    - secure: CPXP6g3c1FH4Zm4U19XaPvq9nnyNsQCXRkxiPcGqsJZsGG2QMgzPQyjiAuPqnWxxZHit/6NgzUszJC+skSgcTzDTeD6rOA0Wcxtbr/Un4RRxRnTcRc6mSEZqSu9RbAZMYur/mSQ9HDHnjFe1ok85He4s9jM1iFdgjtg1ToelEmA=
+    - secure: fp9pzNe09PIyZ/8NjbMPGW1zdG3Q/KhJ+stUKqA+FRopAMX/Hh24gFIVJhFOmfr4Vhn0J8sF7RsFaR1mdzcPewliOzKxknWhGEGMcG9LFCZcv+vVK0Fxs4nUzCRtaXUt08FpsRofG0iBvfapZ7YBhK7lslqGVI+fxCd3ZXmayG8=
+    - secure: NT/6qcecxmuKYOnw1Atc6hsyJlfB6XI2Z1lg7dE0PhlEVW2EpkckHjAc+5hgg8Zt7TifYm2qDQWJwblwPP0mMj3ra4ZIMaZAiG2kzQoZ5kthqwjAV9fatZvrDXi+jd9wBF2hPyiCokAQiTLmKTYjzY2FBqPO3VDLWdf9qZqRmxw=
+    - secure: MjIWyfquKANh/YeoyHGksdvAUQ4wc2tBCQmq1QcRhKwb7Sy6wcDk1nujDmnGE7HFpZUS6CyoZF7AMzJGFkCzrChpsLQYUP4hc7VjkXOLzi90vJUl+ANq7KPOmxC0MjKpgeHqCysRbTYbUsnJZfbbZbIZjCAjY0YCY2pGniXpvQc=
+    - secure: AsZLOiFrHkGsY6jp2ShI5kYz78V6PEUyizgtPCWTgevTRGWpdCq9csIEoqUBY+vMUxmQPC6IY4fwHkrRCbv/rJyhwRl/Rnwa3aw8bdD+YD17IxnpXKGXXUyXdTZmF7HzAkVgStehL+qWZ3x9TBdExIV37KVgrVw/b+S0QqBUlQo=
+    - secure: jwEnSquLreMM1M6N3gGpgTGHd8VtjBUTLDdkrokhiH1jHLpz7Hmr6xeajhZws+2sLtLiB7hYi6WsZBE5VcymBoObh9MeodO9Ve5/1z06lFmx1DyYV6euyo9WUkU2WpoVfu8k7O+eAvyrXXZVqm8Oz1p7Isb6Bh5+fJH2H8rhed4=
+    - secure: HOAK620U6mlS11XK+JtXTBk26Tt2vWO4shA/6Zit/y0/kAz7JnbXtup7FSysXliBoSv4YsxA6IbgZ8V0tuIXj+q7EcqtHMmQhqzMJG5jRKVhtGiFIhDmwmxJvdfIvwtZOO3mMk0OspLz24sWp8wCciYZMPj0hZJR04R9aWEO3cE=
+    - secure: DfTRP74UWWxA460XfLoJFgRLwoKbHWNIueL6qr982AnuAxeZFofsxCqxSxcSJmu67TxuPc+b201+BmanHKYmSauGS31t0F4QXk7lCTaT/x38mAPsWvMFkY8HEl56JhmzEp2hAKDB/t0/HItwmvxT1vd5WvNRSSojEVzChftV/zE=
+    - secure: JoCWsJzTgj+epgzmgbvV7/bdAPHwUGXZA7Jdvv9vIJ5lCo6h9WwCw6/KCvH+bHtrT/RfZmUmxouCxJCLKwts1ZrMmedTIXpMrQJo/YgWRp7ziFnLyZ8jG8bD7rep3ngq1x/cRGc3cZvYN6IK3GS6C27OviYLFsTw74AUnWTaFSo=
+    - secure: iXfl0WnAnfKurZUrMeV1yOoFiiZ+MKx/Zj6ZVP2++A9EOxxIxb/fS/gIOzSjBQwzrR+fJVHIlX0g42CiBKDQWUvIl5I8kZCVIP6AHa1jyzlmZE9lqSlojz3k5RPS7pW6nIX+z1NHMvtb3e5xeLv8y4J5kwZErqZ+YDJmBRtPxPU=
+    - secure: RhAW5kABDPB3GWKD+NCg05Kcd92F/+kg+0icXXN166DWQYUut3MLrSY80xNzkz5nXTI9EFU4fUqlKLDiF/kelr0Zp/zpCQAB54o4cu5FkZz0Bgs9k7yUdCRyz6Vt2ChV5cYI4JTn9bMaeXEaGlOjP1iE51rYT6KO6kKlwsEnjUc=
+    - secure: jy/3fC+UtrDcE/X6/IxkyT2SrYMKkiEMP1ht4d5mxvNA0Xxn43E16c6FNP0JWPpWRGRIP38vnQRB4yOPU9BXvRmmswVL9Ge4e/6flJvKwD5Rlqb2dfaGaHRYV9v8Nkdzl2FvZ9eBH5KHxgG19gCG6L3RXP/+zYwrr4AQdm0fpfw=
+    - secure: RYEwBWYVXRTEdUWhQxdWXo6tldlVx8pha9zB0rgafcUQxaatAefnRc4X4HXTQnqr2n9TZ2TQGpM8vte/wr6Pjc85VZbimWGzgrvn0kg4MwPR8ZYiEM5qQ/pUpj4+93rpA91PhCGvZoZTqOrXHm4kMPuKro5I6qA4BFUXuANeC/s=
+    - secure: gHSicpqkqcZT04QurSgszrAiI6HOCw1DBlfIIi9KAJj7mG5GijD/4AQ6HCmcRMbCDJ0nUuvm/kckASnRtF5+3xvIJnuoyyEfCZWxt1lhK2UbS87VU+pVdws/VzwpisXuKsh3H0uT8DDVkWPH/ZWDgfVa74eYDEHiQFjo+2xx5ZA=
+    - secure: Q42bco3JXEpyVbL2akiOsaCHnAagAFIb3TF6H5qJfaLLqmGs/XrrgxliNaVMfWVSwPT2wpQvg9UGF9x37No9bZBv33DgYcWExmXb/lvGPpkctX37+FTMzECQHxOuUbYPQA7ZEuJ4AA7bwgpMISUeSyz5XXz44KcXIrZK2GWH+X4=
+    - secure: hugd8NVukJc3redDvlOt6zhaqa63XLNMp/eIIlNllW8VfQ6CJ1P7KJPwgxH24sDyrw7rLzOkBl6R4kaVWsCLCFp+NE6yFFHl9wDkSdLC1OX1DMrJnDsogwUqqe+jX8dxePSy26MSTfG8eo9/NxN9uXr+tKaHoi6G7BRXDHtQ8dQ=
+    - secure: TRkW9pIuIYHXJmPlDYoddxIp2M2W2f7qBGNJKEMB5xrOezES7w9XTg2eQXrD8jBO+fUUmMnAaDAXZuU58nMysPXx3vhtZKncg8w5CyuXJk2P8nkdPh0u5nmRhEpWrLKtLwJrX48xmJhNQvQqDAyL5c9WUzlWJ4WJFgoP5IDWmLc=
+    - secure: QHuMdtFCvttiIOx6iS+lH4bKXZMwsgVQ6FPsUW5zJ7uw6mAEWKEil9xNk4aYV9FywinwUs4fnFlnIW/Gj1gLkUjm4DtxdmRZIlRXIbgsNch6H916TCPg4Q2oPsW2nVdXPjW/2jhkfLUiSnuhL+ylami1NF8Up7vokXknh/jFNZU=
+    - secure: GTfrUVmMQSxho3Ia4Y1ONqKvVMD34GHF2/TJb8UdQV7iH+nVxVXpy3nWaCXa9ri7lRzMefkoVLy0gKK13YoVd7w3d2S3/IfNakC85XfN6VuOzK/FDkA0WoPrgKjcQ64I+3dQ6cgrMWWTieKwRZy+Ve24iRbnN055Hk+VRMu6OGw=
+    - secure: SOMYGVfHLkHsH6koxpw68YQ4ydEo6YXPhHbrYGQbehUbFa6+OZzBcAJRJbKjyhD2AZRvNr2jB8XnjYKvVyDGQRpkWhGYZ7CpHqINpDsqKBsbiMe3/+KmKQqS+UKxNGefquoOvyQ1N8Xy77dkWYokRtGMEuR12RkZLonxiDW8Qyg=
+    - secure: bSsDg+dJnPFdFiC/tbb61HdLh/Q0z2RVVAReT1wvV1BN4fN4NydvkUGbQmyFNyyunLulEs+X0oFma9L0497nUlTnan8UOg9sIleTSybPX6E9xSKKCItH1GgDw8bM9Igez5OOrrePBD3altVrH+FmGx0dlTQgM/KZMN50BJ79cXw=
+    ### END TEST KITCHEN ONLY ###
+  - rvm: 2.2
+    sudo: required
+    dist: trusty
+    before_install:
+      - gem install bundler
+      - sudo apt-get update
+      - sudo apt-get -y install squid3 git curl
+    env:
+      - PROXY_TESTS_DIR=proxy_tests/files/default/scripts
+      - PROXY_TESTS_REPO=$PROXY_TESTS_DIR/repo
+    script:
+      - bundle exec chef-client --version
+      - git clone https://github.com/chef/proxy_tests.git
+      - rvmsudo -E bundle exec bash $PROXY_TESTS_DIR/run_tests.sh chef_client \* \* /tmp/out.txt
+    after_script:
+      - cat /tmp/out.txt
+      - sudo cat /var/log/squid3/cache.log
+      - sudo cat /var/log/squid3/access.log
+
+  allow_failures:
+    - rvm: rbx
+notifications:
+  on_change: true
+  on_failure: true
+  on_success: change
+  on_pull_requests: false
+  irc:
+    channels:
+    - chat.freenode.net#chef-hacking
+  webhooks:
+    urls:
+    # Gitter IM
+    - secure: HmMKr/ysKVyKUJ24PRCHcA8QCmlFoukrYumY0GRLzvaFWO8PknHO1t/0RbrKRb2ed/hgkFd+RKNCYvSvcE8Ahr2vlMrBeGHGfVeOGkWtbhLgNqo1b50Ll9CqvTM8X2ZIq6hIWraanwoYRQu/8uGL29yH4lBi7DhpTkFwBMLulhQ=
+  hipchat:
+    rooms:
+    # Build Statuses
+    - secure: G8MNo94L8bmWWwkH2/ViB2QaZnZHZscYM/mEjDbOGd15sqrruwckeARyBoUcRI7P1C6AFmS4IKCNVXa6KzX4Pbh51gQWM92zRpRTZpplwtXz53/1l8ajLFLLMLvEMTlBFAANUKEUFAQPY4dMa14V3Qc5oijfIncN61k4nZNTKpY=
+    # Open Source
+    - secure: hmcex4PpG5dn8WvjndONO4xCUKOC5kPU/bUEGRrfVbe2YKJE7t0XXbNDC96W/xBgzgnJzvf1Er0zJKDrNf4qEDEWFoozdN00WLcqREgaLLS3Seto2FjR/BpBk5q+sCV0rwwEMms2P4Qk+VSnDCnm9EaeM55hOabqNuOrRzoZLBQ=
diff --git a/.yardopts b/.yardopts
new file mode 100644
index 0000000..a4541be
--- /dev/null
+++ b/.yardopts
@@ -0,0 +1 @@
+-m markdown
diff --git a/CBGB.md b/CBGB.md
new file mode 100644
index 0000000..2ce26fc
--- /dev/null
+++ b/CBGB.md
@@ -0,0 +1,40 @@
+<!-- This is a generated file. Please do not edit directly -->
+<!-- Modify CBGB.toml file and run `rake cbgb:generate` to regenerate -->
+
+# Chef Board of Governance (CBGB)
+
+  Chef was designed from the outset to have a very open structure, including open design, open contribution, and consistent use of tools across the project. Given the large numbers of contributors, users, and companies with a stake in the future of the project, Chef leadership has established an advisory board, as part of its long term commitment to open governance.
+
+  The Chef Board of Governance (CBGB) shall advise the Leadership on matters related to supporting the long-term governance, structure, and roadmap of the Project.
+
+More information can be found in the [Chef Board of Governance RFC](Chef Board of Governance).
+
+# Board of Governors
+
+## Project Lead
+
+* [Adam Jacob](https://github.com/adamhjk)
+
+### Users/Contributors (4)
+
+* [Ranjib Dey](https://github.com/ranjib)
+* [Doug Ireton](https://github.com/dougireton)
+* [Noah Kantrowitz](https://github.com/coderanger)
+* [Charity Majors](https://github.com/charity)
+
+
+### Corporate Contributors (4)
+
+* Etsy - Katherine Daniels
+* Facebook - Phil Dibowitz
+* Nordstrom - Mark Ayers
+* PagerDuty - Evan Gilman
+
+
+### Lieutenants (3)
+
+* [Jon Cowie](https://github.com/jonlives)
+* [Joshua Timberman](https://github.com/jtimberman)
+* [Seth Vargo](https://github.com/sethvargo)
+
+
diff --git a/CBGB.toml b/CBGB.toml
new file mode 100644
index 0000000..07e9c9a
--- /dev/null
+++ b/CBGB.toml
@@ -0,0 +1,96 @@
+#
+# This file is structured to be consumed by both humans and computers.
+# It is a TOML document containing Markdown
+#
+[Preamble]
+  title = "Chef Board of Governance (CBGB)"
+  text = """
+  Chef was designed from the outset to have a very open structure, including open design, open contribution, and consistent use of tools across the project. Given the large numbers of contributors, users, and companies with a stake in the future of the project, Chef leadership has established an advisory board, as part of its long term commitment to open governance.
+
+  The Chef Board of Governance (CBGB) shall advise the Leadership on matters related to supporting the long-term governance, structure, and roadmap of the Project.
+
+More information can be found in the [Chef Board of Governance RFC](Chef Board of Governance).
+"""
+
+[Org]
+  [Org.Lead]
+    title = "Project Lead"
+    person = "adamhjk"
+
+  [Org.Contributors]
+    title = "Users/Contributors (4)"
+    governers = [
+      "ranjibdey",
+      "dougireton",
+      "coderanger",
+      "charitymajors"
+    ]
+
+  [Org.Corporate-Contributors]
+    title = "Corporate Contributors (4)"
+    governers = [
+      "etsy",
+      "facebook",
+      "nordstrom",
+      "pagerduty"
+    ]
+
+  [Org.Lieutenants]
+    title = "Lieutenants (3)"
+    governers = [
+      "jonlives",
+      "jtimberman",
+      "sethvargo"
+    ]
+
+[people]
+  [people.adamhjk]
+    Name = "Adam Jacob"
+    GitHub = "adamhjk"
+    IRC = "holoway"
+
+  [people.jonlives]
+    Name = "Jon Cowie"
+    GitHub = "jonlives"
+    IRC = "jonlives"
+
+  [people.coderanger]
+    Name = "Noah Kantrowitz"
+    GitHub = "coderanger"
+
+  [people.jtimberman]
+    Name = "Joshua Timberman"
+    GitHub = "jtimberman"
+
+  [people.ranjibdey]
+    Name = "Ranjib Dey"
+    GitHub = "ranjib"
+
+  [people.sethvargo]
+    Name = "Seth Vargo"
+    GitHub = "sethvargo"
+
+  [people.dougireton]
+    Name = "Doug Ireton"
+    GitHub = "dougireton"
+
+  [people.charitymajors]
+    Name = "Charity Majors"
+    GitHub = "charity"
+
+[corporations]
+  [corporations.etsy]
+    Name = "Etsy"
+    Person = "Katherine Daniels"
+
+  [corporations.facebook]
+    Name = "Facebook"
+    Person = "Phil Dibowitz"
+
+  [corporations.nordstrom]
+    Name = "Nordstrom"
+    Person = "Mark Ayers"
+
+  [corporations.pagerduty]
+    Name = "PagerDuty"
+    Person = "Evan Gilman"
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..baf46a2
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,923 @@
+## 12.7.2
+
+* [pr#4559](https://github.com/chef/chef/pull/4559) Remove learnchef acceptance tests until we make them more reliable
+* [pr#4545](https://github.com/chef/chef/pull/4545) Removing rm -rf in chef-solo recipe_url
+
+## 12.7.1
+* [**Daniel Steen**](https://github.com/dansteen)
+  * [pr#3183](https://github.com/chef/chef/pull/3183) Provide more helpful error message when accidentally using --secret instead of --secret-file
+
+* [pr#4532](https://github.com/chef/chef/pull/4532) Bump Bundler + Rubygems
+* [pr#4550](https://github.com/chef/chef/pull/4550) Use a streaming request to download cookbook
+
+## 12.7.0
+
+* [**Nate Walck**](https://github.com/natewalck)
+  * [pr#4078](https://github.com/chef/chef/pull/4078) Add `osx_profile` resource for OS X
+* [**Timothy Cyrus**](https://github.com/tcyrus)
+  * [pr#4420](https://github.com/chef/chef/pull/4420) Update code climate badge and code climate blocks in README.md
+* [**Jordan Running**](https://github.com/jrunning)
+  * [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save policy_name and policy_group with `knife node edit`
+* [**Brian Goad**](https://github.com/bbbco)
+  * [pr#4315](https://github.com/chef/chef/pull/4315) Add extra tests around whether to skip with multiple guards
+
+* [pr#4516](https://github.com/chef/chef/pull/4516) Return propper error messages when using windows based `mount`, `user` and `group` resources
+* [pr#4500](https://github.com/chef/chef/pull/4500) Explicitly declare directory permissions of chef install on windows to restrict rights on Windows client versions
+* [pr#4498](https://github.com/chef/chef/pull/4498) Correct major and minor OS versions for Windows 10 and add versions for Windows 2016 Server
+* [pr#4375](https://github.com/chef/chef/pull/4375) No longer try to auto discover package version of `exe` based windows packages
+* [pr#4369](https://github.com/chef/chef/pull/4396) Import omnibus-chef chef project definition and history
+* [pr#4399](https://github.com/chef/chef/pull/4399) Correctly save `policy_name` and `policy_group` with `knife node edit`
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4479](https://github.com/chef/chef/pull/4479) Remove incorrect cookbook artifact normalization
+* [pr#4470](https://github.com/chef/chef/pull/4470) Fix sh spacing issues
+* [pr#4434](https://github.com/chef/chef/pull/4434) adds EOFError message to handlers
+* [pr#4422](https://github.com/chef/chef/pull/4422) Add an apt_update resource
+* [pr#4287](https://github.com/chef/chef/pull/4287) Default Chef with FIPS OpenSSL to use sign v1.3
+* [pr#4461](https://github.com/chef/chef/pull/4461) debian-6 is EOL next month
+* [pr#4460](https://github.com/chef/chef/pull/4460) Set range of system user/group id to max of 200
+* [pr#4231](https://github.com/chef/chef/pull/4231) zypper multipackage patch
+* [pr#4459](https://github.com/chef/chef/pull/4459) use require_paths and not path so bundler grabs all paths from a git reference
+* [pr#4450](https://github.com/chef/chef/pull/4450) don't warn about ambiguous property usage
+* [pr#4445](https://github.com/chef/chef/pull/4445) Add CBGB to the repository
+* [pr#4423](https://github.com/chef/chef/pull/4423) Add deprecation warnings to Chef::REST and all json_creates
+* [pr#4439](https://github.com/chef/chef/pull/4439) Sometimes chocolately doesn't appear on the path
+* [pr#4432](https://github.com/chef/chef/pull/4432) add get_rest etc calls to ServerAPI
+* [pr#4435](https://github.com/chef/chef/pull/4435) add nokogiri to omnibus-chef
+* [pr#4419](https://github.com/chef/chef/pull/4419) explicitly adding .bat to service executable called by service in case users remove .bat from PATHEXT
+* [pr#4413](https://github.com/chef/chef/pull/4413) configure chef client windows service to the correct chef directory
+* [pr#4377](https://github.com/chef/chef/pull/4377) fixing candidate filtering and adding functional tests for chocolatey_package
+* [pr#4406](https://github.com/chef/chef/pull/4406) Updating to the latest release of net-ssh to consume https://github.com/net-ssh/net-ssh/pull/280
+* [pr#4405](https://github.com/chef/chef/pull/4405) ServerAPI will return a raw hash, so do that
+* [pr#4400](https://github.com/chef/chef/pull/4400) inflate an environment after loading it
+* [pr#4396](https://github.com/chef/chef/pull/4396) Remove duplicate initialization of @password in user_v1
+* [pr#4344](https://github.com/chef/chef/pull/4344) Warn (v. info) when reloading resources
+* [pr#4369](https://github.com/chef/chef/pull/4369) Migrate omnibus-chef project/software definitions for chef in here
+* [pr#4106](https://github.com/chef/chef/pull/4106) add chocolatey_package to core chef
+* [pr#4321](https://github.com/chef/chef/pull/4321) fix run_as_user of windows_service
+* [pr#4333](https://github.com/chef/chef/pull/4333) no longer wait on node search to refresh vault but pass created ApiCient instead
+* [pr#4325](https://github.com/chef/chef/pull/4325) Pin win32-eventlog to 0.6.3 to avoid clashing CreateEvent definition
+* [pr#4312](https://github.com/chef/chef/pull/4312) Updates the template to use omnitruck-direct.chef.io
+* [pr#4277](https://github.com/chef/chef/pull/4277) non msi packages must explicitly provide a source attribute on install
+* [pr#4309](https://github.com/chef/chef/pull/4309) tags always an array; fix set_unless
+* [pr#4278](https://github.com/chef/chef/pull/4278) make file resource use properties
+* [pr#4288](https://github.com/chef/chef/pull/4288) Fix no_proxy setting in chef-config
+* [pr#4273](https://github.com/chef/chef/pull/4273) Use signing protocol 1.1 by default
+* [pr#4520](https://github.com/chef/chef/pull/4520) Fix a few `dsc_resource` bugs
+
+## 12.6.0
+
+* [**Dave Eddy**](https://github.com/bahamas10)
+  [pr#3187](https://github.com/chef/chef/pull/3187) overhaul solaris SMF service provider
+* [**Mikhail Zholobov**](https://github.com/legal90)
+  - [pr#3192](https://github.com/chef/chef/pull/3192) provider/user/dscl: Set default gid to 20
+  - [pr#3193](https://github.com/chef/chef/pull/3193) provider/user/dscl: Set "comment" default value
+* [**Jordan Evans**](https://github.com/jordane)
+  - [pr#3263](https://github.com/chef/chef/pull/3263) `value_for_platform` should use `Chef::VersionConstraint::Platform`
+  - [pr#3633](https://github.com/chef/chef/pull/3633) add the word group to `converge_by` call for group provider
+* [**Scott McGillivray**](https://github.com/thechile)
+  [pr#3450](https://github.com/chef/chef/pull/3450) Fix 'knife cookbook show' to work on root files
+* [**Aubrey Holland**](https://github.com/aub)
+  [pr#3986](https://github.com/chef/chef/pull/3986) fix errors when files go away during chown
+* [**James Michael DuPont**](https://github.com/h4ck3rm1k3)
+  [pr#3973](https://github.com/chef/chef/pull/3973) better error reporting
+* [**Michael Pereira**](https://github.com/MichaelPereira)
+  [pr#3968](https://github.com/chef/chef/pull/3968) Fix cookbook installation from supermarket on windows
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly)
+  - [pr#3941](https://github.com/chef/chef/pull/3941) allow reboot by reboot resource with chef-apply
+  - [pr#3900](https://github.com/chef/chef/pull/3900) Add new option json attributes file to bootstraping
+* [**permyakovsv**](https://github.com/permyakovsv)
+  [pr#3901](https://github.com/chef/chef/pull/3901) Add tmux-split parameter to knife ssh
+* [**Evan Gilman**](https://github.com/evan2645)
+  [pr#3864](https://github.com/chef/chef/pull/3864) Knife `bootstrap_environment` should use Explicit config before Implicit
+* [**Ranjib Dey**](https://github.com/ranjib)
+  [pr#3834](https://github.com/chef/chef/pull/3834) Dont spit out stdout and stderr for execute resource failure, if its declared sensitive
+* [**Jeff Blaine**](https://github.com/jblaine)
+  - [pr#3776](https://github.com/chef/chef/pull/3776) Changes --hide-healthy to --hide-by-mins MINS
+  - [pr#3848](https://github.com/chef/chef/pull/3848) Migrate to --ssh-identity-file instead of --identity-file
+* [**dbresson**](https://github.com/dbresson)
+  [pr#3650](https://github.com/chef/chef/pull/3650) Define == for node objects
+* [**Patrick Connolly**](https://github.com/patcon)
+  [pr#3529](https://github.com/chef/chef/pull/3529) Allow user at hostname format for knife-bootstrap
+* [**Justin Seubert**](https://github.com/dude051)
+  [pr#4160](https://github.com/chef/chef/pull/4160) Correcting regex for upstart_state
+* [**Sarah Michaelson**](https://github.com/skmichaelson)
+  [pr#3810](https://github.com/chef/chef/pull/3810) GH-1909 Add validation for chef_server_url
+* [**Maxime Brugidou**](https://github.com/brugidou)
+  [pr#4052](https://github.com/chef/chef/pull/4052) Add make_child_entry in ChefFS CookbookSubdir
+* [**Nathan Williams**](https://github.com/nathwill)
+  [pr#3836](https://github.com/chef/chef/pull/3836) simplify service helpers
+* [**Paul Welch**](https://github.com/pwelch)
+  [pr#4066](https://github.com/chef/chef/pull/4066) Fix chef-apply usage banner
+* [**Mat Schaffer**](https://github.com/matschaffer)
+  [pr#4153](https://github.com/chef/chef/pull/4153) Require ShellOut before Knife::SSH definition
+* [**Donald Guy**](https://github.com/donaldguy)
+  [pr#4158](https://github.com/chef/chef/pull/4158) Allow named_run_list to be loaded from config
+* [**Jos Backus**](https://github.com/josb)
+  [pr#4064](https://github.com/chef/chef/pull/4064) Ensure that tags are properly initialized
+* [**John Bellone**](https://github.com/johnbellone)
+  [pr#4101](https://github.com/chef/chef/pull/4101) Adds alias method upgrade_package for solaris package
+* [**Nolan Davidson**](https://github.com/nsdavidson)
+  [pr#4014](https://github.com/chef/chef/pull/4014) Adding ksh resource
+
+* [pr#4193](https://github.com/chef/chef/pull/4196) support for inno, nsis, wise and installshield installer types in windows_package resource
+* [pr#4196](https://github.com/chef/chef/pull/4196) multipackage dpkg_package and bonus fixes
+* [pr#4185](https://github.com/chef/chef/pull/4185) dpkg provider cleanup
+* [pr#4165](https://github.com/chef/chef/pull/4165) Multipackage internal API improvements
+* [pr#4081](https://github.com/chef/chef/pull/4081) RFC-037: add `chef_version` and `ohai_version` metadata
+* [pr#3530](https://github.com/chef/chef/pull/3530) Allow using --sudo option with user's home folder in knife bootstrap
+* [pr#3858](https://github.com/chef/chef/pull/3858) Remove duplicate 'Accept' header in spec
+* [pr#3911](https://github.com/chef/chef/pull/3911) Avoid subclassing Struct.new
+* [pr#3990](https://github.com/chef/chef/pull/3990) Use SHA256 instead of MD5 for `registry_key` when data is not displayable
+* [pr#4034](https://github.com/chef/chef/pull/4034) add optional ruby-profiling with --profile-ruby
+* [pr#3119](https://github.com/chef/chef/pull/3119) allow removing user, even if their GID isn't resolvable
+* [pr#4068](https://github.com/chef/chef/pull/4068) update messaging from LWRP to Custom Resource in logging and spec
+* [pr#4021](https://github.com/chef/chef/pull/4021) add missing requires for Chef::DSL::Recipe to LWRPBase
+* [pr#3597](https://github.com/chef/chef/pull/3597) print STDOUT from the powershell_script
+* [pr#4091](https://github.com/chef/chef/pull/4091) Allow downloading of root_files in a chef repository
+* [pr#4112](https://github.com/chef/chef/pull/4112) Update knife bootstrap command to honor --no-color flag in chef-client run that is part of the bootstrap process.
+* [pr#4090](https://github.com/chef/chef/pull/4090) Improve detection of ChefFS-based commands in `knife rehash`
+* [pr#3991](https://github.com/chef/chef/pull/3991) Modify remote_file cache_control_data to use sha256 for its name
+* [pr#4079](https://github.com/chef/chef/pull/4079) add logger to windows service shellout
+* [pr#3966](https://github.com/chef/chef/pull/3966) Report expanded run list json tree to reporting
+* [pr#4080](https://github.com/chef/chef/pull/4080) Make property modules possible
+* [pr#4069](https://github.com/chef/chef/pull/4069) Improvements to log messages
+* [pr#4049](https://github.com/chef/chef/pull/4049) Add gemspec files to allow bundler to run from the gem
+* [pr#4029](https://github.com/chef/chef/pull/4029) Fix search result pagination
+* [pr#4048](https://github.com/chef/chef/pull/4048) Accept coercion as a way to accept nil values
+* [pr#4046](https://github.com/chef/chef/pull/4046) ignore gid in the user resource on windows
+* [pr#4118](https://github.com/chef/chef/pull/4118) Make Property.derive create derived properties of the same type
+* [pr#4133](https://github.com/chef/chef/pull/4133) Add retries to `Chef::HTTP` for transient SSL errors
+* [pr#4135](https://github.com/chef/chef/pull/4135) Windows service uses log file location from config if none is given on commandline
+* [pr#4142](https://github.com/chef/chef/pull/4142) Use the proper python interpretor for yum-dump.py on Fedora 21
+* [pr#4149](https://github.com/chef/chef/pull/4149) Handle nil run list option in knife bootstrap
+* [pr#4040](https://github.com/chef/chef/pull/4040) Implement live streaming for execute resources
+* [pr#4167](https://github.com/chef/chef/pull/4167) Add `reboot_action` to `dsc_resource`
+* [pr#4167](https://github.com/chef/chef/pull/4167) Allow `dsc_resource` to run with the LCM enabled
+* [pr#4188](https://github.com/chef/chef/pull/4188) Update `dsc_resource` to use verbose stream output
+* [pr#4200](https://github.com/chef/chef/pull/4200) Prevent inspect of PsCredential from printing out plain text password
+* [pr#4237](https://github.com/chef/chef/pull/4237) Enabling 'knife ssl check/fetch' commands to respect proxy environment variables and moving proxy environment variables export to Chef::Config
+## 12.5.1
+
+* [**Ranjib Dey**](https://github.com/ranjib):
+  [pr#3588](https://github.com/chef/chef/pull/3588) Count skipped resources among total resources in doc formatter
+* [**John Kerry**](https://github.com/jkerry):
+  [pr#3539](https://github.com/chef/chef/pull/3539) Fix issue: registry\_key resource is case sensitive in chef but not on windows
+* [**David Eddy**](https://github.com/bahamas10):
+  - [pr#3443](https://github.com/chef/chef/pull/3443) remove extraneous space
+  - [pr#3091](https://github.com/chef/chef/pull/3091) fix locking/unlocking users on SmartOS
+* [**margueritepd**](https://github.com/margueritepd):
+  [pr#3693](https://github.com/chef/chef/pull/3693) Interpolate `%{path}` in verify command
+* [**Jeremy Fleischman**](https://github.com/jfly):
+  [pr#3383](https://github.com/chef/chef/pull/3383) gem\_package should install to the systemwide Ruby when using ChefDK
+* [**Stefano Rivera**](https://github.com/stefanor):
+  [pr#3657](https://github.com/chef/chef/pull/3657) fix upstart status\_commands
+* [**ABE Satoru**](https://github.com/polamjag):
+  [pr#3764](https://github.com/chef/chef/pull/3764) uniquify chef\_repo\_path
+* [**Renan Vicente**](https://github.com/renanvicente):
+  [pr#3771](https://github.com/chef/chef/pull/3771) add depth property for deploy resource
+* [**James Belchamber**](https://github.com/JamesBelchamber):
+  [pr#1796](https://github.com/chef/chef/pull/1796): make mount options aware
+* [**Nate Walck**](https://github.com/natewalck):
+  - [pr#3594](https://github.com/chef/chef/pull/3594): Update service provider for OSX 10.11
+  - [pr#3704](https://github.com/chef/chef/pull/3704): Add SIP (OS X 10.11) support
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  [pr#3805](https://github.com/chef/chef/pull/3805) LWRP parameter validators should use truthiness
+* [**Igor Shpakov**](https://github.com/Igorshp):
+  [pr#3743](https://github.com/chef/chef/pull/3743) speed improvement for `remote_directory` resource
+* [**James FitzGibbon**](https://github.com/jf647):
+  [pr#3027](https://github.com/chef/chef/pull/3027) Add warnings to 'knife node run list remove ...'
+* [**Backslasher**](https://github.com/backslasher):
+  [pr#3172](https://github.com/chef/chef/pull/3172) Migrated deploy resource to use shell\_out instead of run\_command
+* [**Sean Walberg**](https://github.com/swalberg):
+  [pr#3190](https://github.com/chef/chef/pull/3190) Allow tags to be set on a node during bootstrap
+* [**ckaushik**](https://github.com/ckaushik) and [**Sam Dunne**](https://github.com/samdunne):
+  [pr#3510](https://github.com/chef/chef/pull/3510) Fix broken rendering
+of partial templates.
+* [**Simon Detheridge**](https://github.com/gh2k):
+  [pr#3806](https://github.com/chef/chef/pull/3806) Replace output\_of\_command with shell\_out! in subversion provider
+* [**Joel Handwell**](https://github.com/joelhandwell):
+  [pr#3821](https://github.com/chef/chef/pull/3821) Human friendly elapsed time in log
+
+* [pr#3985](https://github.com/chef/chef/pull/3985) Simplify the regex which determines the rpm version to resolve issue #3671
+* [pr#3928](https://github.com/chef/chef/pull/3928) Add named run list support when using policyfiles
+* [pr#3913](https://github.com/chef/chef/pull/3913) Add `policy_name`and `policy_group` fields to the node object
+* [pr#3875](https://github.com/chef/chef/pull/3875) Patch Win32::Registry#delete_key, #delete_value to use wide (W) APIs
+* [pr#3850](https://github.com/chef/chef/pull/3850) Patch Win32::Registry#write to fix encoding errors
+* [pr#3837](https://github.com/chef/chef/pull/3837) refactor remote_directory provider for mem+perf improvement
+* [pr#3799](https://github.com/chef/chef/pull/3799) fix supports hash issues in service providers
+* [pr#3797](https://github.com/chef/chef/pull/3797) Fix dsc_script spec failure on 64-bit Ruby
+* [pr#3817](https://github.com/chef/chef/pull/3817) Remove now-useless forcing of ruby Garbage Collector run
+* [pr#3775](https://github.com/chef/chef/pull/3775) Enable 64-bit support for Powershell and Batch scripts
+* [pr#3774](https://github.com/chef/chef/pull/3774) Add support for yum-deprecated in yum provider
+* [pr#3793](https://github.com/chef/chef/pull/3793) CHEF-5372: Support specific `run_levels` for RedHat service
+* [pr#2460](https://github.com/chef/chef/pull/2460) add privacy flag
+* [pr#1259](https://github.com/chef/chef/pull/1259) CHEF-5012: add methods for template breadcrumbs
+* [pr#3656](https://github.com/chef/chef/pull/3656) remove use of self.provides?
+* [pr#3455](https://github.com/chef/chef/pull/3455) powershell\_script: do not allow suppression of syntax errors
+* [pr#3519](https://github.com/chef/chef/pull/3519) The wording seemed odd.
+* [pr#3208](https://github.com/chef/chef/pull/3208) Missing require (require what you use).
+* [pr#3449](https://github.com/chef/chef/pull/3449) correcting minor typo in user\_edit knife action
+* [pr#3572](https://github.com/chef/chef/pull/3572) Use windows paths without case-sensitivity.
+* [pr#3666](https://github.com/chef/chef/pull/3666) Support SNI in `knife ssl check`.
+* [pr#3667](https://github.com/chef/chef/pull/3667) Change chef service to start as 'Automatic delayed start'.
+* [pr#3683](https://github.com/chef/chef/pull/3683) Correct Windows reboot command to delay in minutes, per the property.
+* [pr#3698](https://github.com/chef/chef/pull/3698) Add ability to specify dependencies in chef-service-manager.
+* [pr#3728](https://github.com/chef/chef/pull/3728) Rewrite NetLocalGroup things to use FFI
+* [pr#3754](https://github.com/chef/chef/pull/3754) Fix functional tests for group resource - fix #3728
+* [pr#3498](https://github.com/chef/chef/pull/3498) Use dpkg-deb directly rather than regex
+* [pr#3759](https://github.com/chef/chef/pull/3759) Repair service convergence test on AIX
+* [pr#3329](https://github.com/chef/chef/pull/3329) Use ifconfig target property
+* [pr#3652](https://github.com/chef/chef/pull/3652) Fix explanation for configuring audit mode in client.rb
+* [pr#3687](https://github.com/chef/chef/pull/3687) Add formatter and force-logger/formatter options to chef-apply
+* [pr#3768](https://github.com/chef/chef/pull/3768) Make reboot\_pending? look for CBS RebootPending
+* [pr#3815](https://github.com/chef/chef/pull/3815) Fix `powershell_script` validation to use correct architecture
+* [pr#3772](https://github.com/chef/chef/pull/3772) Add `ps_credential` dsl method to `dsc_script`
+* [pr#3462](https://github.com/chef/chef/pull/3462) Fix issue where `ps_credential` does not work over winrm
+
+## 12.4.1
+
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+  [pr#3605](https://github.com/chef/chef/pull/3605) Rework `Resource#action` to match 12.3 API
+
+* [pr#3586](https://github.com/chef/chef/issues/3586) Fix bug preventing light weight resources from being used with heavy weight providers
+* [Issue #3593](https://github.com/chef/chef/issues/3593) Fix bug where provider priority map did not take into consideration a provided block
+* [pr#3630](https://github.com/chef/chef/pull/3630) Restore Chef::User and Chef::ApiClient namespace to API V0 functionality and move new functionality into Chef::UserV1 and Chef::ApiClientV1 until Chef 13.
+* [pr#3611](https://github.com/chef/chef/pull/3611) Call `provides?` even if `provides` is not called
+* [pr#3589](https://github.com/chef/chef/pull/3589) Fix errant bashisms
+* [pr#3620](https://github.com/chef/chef/pull/3620) Fix issue where recipe names in run list mutate when version constaints are present
+* [pr#3623](https://github.com/chef/chef/pull/3623) Allow LWRPs to access the real class when accessed through `Chef::Resource` and `Chef::Provider`
+* [pr#3627](https://github.com/chef/chef/pull/3627) Separate priority map and DSL handler map so that `provides` has veto power over priority
+* [pr#3638](https://github.com/chef/chef/pull/3638) Deprecate passing more than 1 argument to create a resource
+
+## 12.4.0
+
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  Fix multipackage and architectures
+* [**Igor Shpakov**](https://github.com/Igorshp):
+  Always run exception handlers
+  Prioritise manual ssh attribute over automatic ones for knife
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+  Cache service\_resource\_providers for the duration of the run. #2953
+* [**Slava Kardakov**](https://github.com/ojab):
+  Fix installation of yum packages with version constraints #3155
+* [**Dave Eddy**](https://github.com/bahamas10):
+  fix smartos\_package for new "pkgin" output, fixes #3112 #3165
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly):
+  Show Chef version on chef shell prompt
+* [**Jacob Minshall**](https://github.com/minshallj):
+  Ensure suid bit is preserved if group or owner changes
+* [**Tim Smith**](https://github.com/tas50):
+  Convert wiki links to point to docs.chef.io
+* [**SAWANOBORI Yukihiko**](https://github.com/sawanoboly):
+  Add Chef::Log::Syslog class for integrating sending logs to syslog
+* [**Pavel Yudin**](https://github.com/Kasen):
+  Ensure LWRP and HWRP @action variable is consistent #3156
+* [**Dan Bjorge**](https://github.com/dbjorge):
+  Fix bad Windows securable\_resource functional spec assumptions for default file owners/groups #3266
+* [**Yukihiko SAWANOBORI**](https://github.com/sawanoboly): Pass name by
+  knife cil attribute [pr#3195](https://github.com/chef/chef/pull/3195)
+* [**Torben Knerr**](https://github.com/tknerr):
+  Allow knife sub-command loader to match platform specific gems. [pr#3281](https://github.com/chef/chef/pull/3281)
+* [**Steve Lowe**](https://github.com/SteveLowe):
+  Fix copying ntfs dacl and sacl when they are nil. [pr#3066](https://github.com/chef/chef/pull/3066)
+
+* [pr#3339](https://github.com/chef/chef/pull/3339): Powershell command wrappers to make argument passing to knife/chef-client etc. easier.
+* [pr#3720](https://github.com/chef/chef/pull/3270): Extract chef's configuration to a separate gem. Code stays in the Chef git repo.
+* [pr#3321](https://github.com/chef/chef/pull/3321): Add an integration test of chef-client with empty ENV.
+* [pr#3278](https://github.com/chef/chef/pull/3278): Switch over Windows builds to universal builds.
+* [pr#2877](https://github.com/chef/chef/pull/2877): Convert bootstrap template to use sh.
+* [Issue #3316](https://github.com/chef/chef/issues/3316): Fix idempotency issues with the `windows_package` resource
+* [pr#3295](https://github.com/chef/chef/pull/3295): Stop mutating `new_resource.checksum` in file providers.  Fixes some ChecksumMismatch exceptions like [issue#3168](https://github.com/chef/chef/issues/3168)
+* [pr#3320](https://github.com/chef/chef/pull/3320): Sanitize non-UTF8 characters in the node data before doing node.save().  Works around many UTF8 exception issues reported on node.save().
+* Implemented X-Ops-Server-API-Version with a API version of 0, as well as error handling when the Chef server does not support the API version that the client supports.
+* [pr#3327](https://github.com/chef/chef/pull/3327): Fix unreliable AIX service group parsing mechanism.
+* [pr#3333](https://github.com/chef/chef/pull/3333): Fix SSL errors when connecting to private Supermarkets
+* [pr#3340](https://github.com/chef/chef/pull/3340): Allow Event dispatch subscribers to be inspected.
+* [Issue #3055](https://github.com/chef/chef/issues/3055): Fix regex parsing for recipe failures on Windows
+* [pr#3345](https://github.com/chef/chef/pull/3345): Windows Event log logger
+* [pr#3336](https://github.com/chef/chef/pull/3336): Remote file understands UNC paths
+* [pr#3269](https://github.com/chef/chef/pull/3269): Deprecate automatic recipe DSL for classes in `Chef::Resource`
+* [pr#3360](https://github.com/chef/chef/pull/3360): Add check_resource_semantics! lifecycle method to provider
+* [pr#3344](https://github.com/chef/chef/pull/3344): Rewrite Windows user resouce code to use ffi instead of win32-api
+* [pr#3318](https://github.com/chef/chef/pull/3318): Modify Windows package provider to allow for url source
+* [pr#3381](https://github.com/chef/chef/pull/3381): warn on cookbook self-deps
+* [pr#2312](https://github.com/chef/chef/pull/2312): fix `node[:recipes]` duplication, add `node[:cookbooks]` and `node[:expanded_run_list]`
+* [pr#3325](https://github.com/chef/chef/pull/3325): enforce passing a node name with validatorless bootstrapping
+* [pr#3398](https://github.com/chef/chef/pull/3398): Allow spaces in files for the `remote_file` resource
+* [Issue #3010](https://github.com/chef/chef/issues/3010) Fixed `knife user` for use with current and future versions of Chef Server 12, with continued backwards compatible support for use with Open Source Server 11.
+* [pr#3438](https://github.com/chef/chef/pull/3438) Server API V1 support. Vast improvements to and testing expansion for Chef::User, Chef::ApiClient, and related knife commands. Deprecated Open Source Server 11 user support to the Chef::OscUser and knife osc_user namespace, but with backwards compatible support via knife user.
+* [Issue #2247](https://github.com/chef/chef/issues/2247): `powershell_script` returns 0 for scripts with syntax errors
+* [pr#3080](https://github.com/chef/chef/pull/3080): Issue 2247: `powershell_script` exit status should be nonzero for syntax errors
+* [pr#3441](https://github.com/chef/chef/pull/3441): Add `powershell_out` mixin to core chef
+* [pr#3448](https://github.com/chef/chef/pull/3448): Fix `dsc_resource` to work with wmf5 april preview
+* [pr#3392](https://github.com/chef/chef/pull/3392): Comment up `Chef::Client` and privatize/deprecate unused things
+* [pr#3419](https://github.com/chef/chef/pull/3419): Fix cli issue with `chef_repo_path` when ENV variable is unset
+* [pr#3358](https://github.com/chef/chef/pull/3358): Separate audit and converge failures
+* [pr#3431](https://github.com/chef/chef/pull/3431): Fix backups on windows for the file resource
+* [pr#3397](https://github.com/chef/chef/pull/3397): Validate owner exists in directory resources
+* [pr#3418](https://github.com/chef/chef/pull/3418): Add `shell_out` mixin to Chef::Resource class for use in `not_if`/`only_if` conditionals, etc.
+* [pr#3406](https://github.com/chef/chef/pull/3406): Add wide-char 'Environment' to `broadcast_env_change` mixin for setting windows environment variables
+* [pr#3442](https://github.com/chef/chef/pull/3442): Add `resource_name` to top-level Resource class to make defining resources easier.
+* [pr#3447](https://github.com/chef/chef/pull/3447): Add `allowed_actions` and `default_action` to top-level Resource class.
+* [pr#3475](https://github.com/chef/chef/pull/3475): Fix `shell_out` timeouts in all package providers to respect timeout property on the resource.
+* [pr#3477](https://github.com/chef/chef/pull/3477): Update `zypper_package` to look like the rest of our package classes.
+* [pr#3483](https://github.com/chef/chef/pull/3483): Allow `include_recipe` from LWRP providers.
+* [pr#3495](https://github.com/chef/chef/pull/3495): Make resource name automatically determined from class name, and provide DSL for it.
+* [pr#3497](https://github.com/chef/chef/pull/3497): Issue 3485: Corruption of node's run\_context when non-default guard\_interpreter is evaluated
+* [pr#3299](https://github.com/chef/chef/pull/3299): Remove experimental warning on audit mode
+
+## 12.3.0
+
+* [pr#3160](https://github.com/chef/chef/pull/3160): Use Chef Zero in
+  socketless mode for local mode, add `--no-listen` flag to disable port
+  binding
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+  Removed after_created and added test to recipe_spec
+* [**Tim Sogard**](https://github.com/drags):
+  Reset $HOME to user running chef-client when running via sudo
+* [**Torben Knerr**](https://github.com/tknerr):
+  Allow for the chef gem installation to succeed without elevated privileges #3126
+* [**Mike Dodge**](https://github.com/mikedodge04)
+  MacOSX services: Load LaunchAgents as console user, adding plist and
+  session_type options.
+* [**Eric Herot**](https://github.com/eherot)
+  Ensure knife ssh doesn't use a non-existant field for hostname #3131
+* [**Tom Hughes**](https://github.com/tomhughes)
+  Ensure searches progress in the face of incomplete responses #3135
+
+* [pr#3162](https://github.com/chef/chef/pull/3162): Add
+  `--minimal-ohai` flag to client/solo/apply; restricts ohai to only the
+  bare minimum of plugins.
+* Ensure link's path attribute works with delayed #3130
+* gem_package, chef_gem should not shell out to using https://rubygems.org #2867
+* Add dynamic resource resolution similar to dynamic provider resolution
+* Add Chef class fascade to internal structures
+* Fix nil pointer for windows event logger #3200
+* Use partial search for knife status
+* Ensure chef/knife properly honours proxy config
+
+## 12.2.1
+* [Issue 3153](https://github.com/chef/chef/issues/3153): Fix bug where unset HOME would cause chef to crash
+
+## 12.2.0
+* Update policyfile API usage to match forthcoming Chef Server release
+* `knife ssh` now has an --exit-on-error option that allows users to
+  fail-fast rather than moving on to the next machine.
+* migrate macosx, windows, openbsd, and netbsd resources to dynamic resolution
+* migrate cron and mdadm resources to dynamic resolution
+* [Issue 3096](https://github.com/chef/chef/issues/3096) Fix OpenBSD package provider installation issues
+* New `dsc_resource` resource to invoke Powershell DSC resources
+
+## 12.1.2
+* [Issue 3022](https://github.com/chef/chef/issues/3022): Homebrew Cask install fails
+  FIXME (remove on 12.2.0 release): 3022 was only merged to 12-stable and #3077 or its descendant should fix this
+* [Issue 3059](https://github.com/chef/chef/issues/3059): Chef 12.1.1 yum_package silently fails
+* [Issue 3078](https://github.com/chef/chef/issues/3078): Compat break in audit-mode changes
+
+## 12.1.1
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  [Issue 3008](https://github.com/chef/chef/issues/3008) Allow people to pass in `source` to package
+* [Issue 3011](https://github.com/chef/chef/issues/3011) `package` provider base should include
+  `Chef::Mixin::Command` as there are still providers that use it.
+* [**Ranjib Dey**](https://github.com/ranjib):
+  [Issue 3019](https://github.com/chef/chef/issues/3019) Fix data fetching when explicit attributes are passed
+
+## 12.1.0
+
+* [**Andre Elizondo**](https://github.com/andrewelizondo)
+  Typo fixes
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+  cleanup cookbook path from stale files (when using chef-solo with a tarball url)
+* [**Nathan Cerny**](https://github.com/ncerny):
+  Fix rubygems provider to use https instead of http.
+* [**Anshul Sharma**](https://github.com/justanshulsharma)
+  removed securerandom patch
+* [**Scott Bonds**](https://github.com/bonds)
+  add package support for OpenBSD
+* [**Lucy Wyman**](https://github.com/lucywyman)
+  Added support for handling empty version strings to rubygems provider.
+* [**Yulian Kuncheff**](https://github.com/Daegalus)
+  Correctly set the pre-release identifier during knife bootstrap.
+* [**Anshul Sharma**](https://github.com/justanshulsharma)
+  `knife node run_list remove` now accepts run_list options in the same form as add
+* [**Veres Lajos**](https://github.com/vlajos)
+  Typo fixes
+* [**Tim Smith**](https://github.com/tas50)
+  Typo fixes
+* [Pull 2505](https://github.com/opscode/chef/pull/2505) Make Chef handle URIs in a case-insensitive manner
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  Drop SSL warnings now that we have a safe default
+* [Pull 2684](https://github.com/chef/chef/pull/2684) Remove ole_initialize/uninitialize which cause problems with Ruby >= 2
+* [**BinaryBabel**](https://github.com/binarybabel)
+  Make knife cookbook site share prefer gnutar when packaging
+* [**Dave Eddy**](https://github.com/bahamas10)
+  Support arrays for not_if and only_if
+* [**Scott Bonds**](https://github.com/bonds)
+  Add service provider for OpenBSD
+* [**Alex Slynko**](https://github.com/alex-slynko-wonga)
+  Change env provider to preserve ordering
+* [**Rob Redpath**](https://github.com/robredpath)
+  Add --lockfile opt for chef-client and chef-solo
+* [**Josh Murphy**](https://github.com/jdmurphy)
+  Check cookbooks exist in path(s) before attempting to upload them with --all
+* [**Vasiliy Tolstov**](https://github.com/vtolstov)
+  add ability to fetch recipes like in chef-solo when using local-mode
+* [**Jan**](https://github.com/habermann24)
+  FIX data_bag_item.rb:161: warning: circular argument reference - data_bag
+* [**David Radcliffe**](https://github.com/dwradcliffe)
+  add banner for knife serve command
+* [**Yukihiko Sawanobori**](https://github.com/sawanoboly)
+  use Chef::JSONCompat.parse for file_contents
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+  Remove some simple Ruby 1.8 and 1.9 code
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+  Remove all RSpec test filters related to Ruby 1.8 and 1.9
+* [**Xabier de Zuazo**] (https://github.com/zuazo)
+  Fix knife cookbook upload messages
+* [**David Crowder**] (https://github.com/david-crowder)
+  refactor to use shell_out in rpm provider
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  Multi-package support
+* [**Naotoshi Seo**](https://github.com/sonots):
+  Support HTTP/FTP source on rpm_package
+  add json_attribs option for chef-apply command
+  allow_downgrade in rpm_package
+* [**AJ Christensen**](https://github.com/fujin):
+  Isolate/fix the no-fork fault. [Issue 2709](https://github.com/chef/chef/issues/2709)
+* [**Cory Stephenson**](https://github.com/Aevin1387):
+  Remove comments of a service being enabled/disabled in FreeBSD. [Fixes #1791](https://github.com/chef/chef/issues/1791)
+* [**Will Albenzi**](https://github.com/walbenzi):
+  CHEF-4591: Knife commands to manipulate env_run_list on nodes
+* [**Jon Cowie**](https://github.com/jonlives):
+  CHEF-2911: Fix yum_package provider to respect version requirements in package name and version attribute
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+  * Node::Attribute to_s should print merged attributes [Issue 1526](https://github.com/chef/chef/issues/1562)
+  * Access keys attribute in `knife show` list incorrect information [Issue 1974](https://github.com/chef/chef/issues/1974)
+  * Guard interpreter loading incorrect resource [Issue 2683](https://github.com/chef/chef/issues/2683)
+
+### Chef Contributions
+* ruby 1.9.3 support is dropped
+* Update Chef to use RSpec 3.2
+* Cleaned up script and execute provider + specs
+* Added deprecation warnings around the use of command attribute in script resources
+* Audit mode feature added - see the RELEASE_NOTES for details
+* shell_out now sets `LANGUAGE` and `LANG` to the `Chef::Config[:internal_locale]` in addition to `LC_ALL` forcing
+* chef_gem supports a compile_time flag and will warn if it is not set (behavior will change in the future)
+* suppress CHEF-3694 warnings on the most trivial resource cloning
+* fixed bugs in the deep_merge_cache logic introduced in 12.0.0 around `node['foo']` vs `node[:foo]` vs. `node.foo`
+* add `include_recipe "::recipe"` sugar to reference a recipe in the current cookbook
+* Add --proxy-auth option to `knife raw`
+* added Chef::Org model class for Chef Organizations in Chef 12 Server
+* `powershell_script` should now correctly get the exit code for scripts that it runs. See [Issue 2348](https://github.com/chef/chef/issues/2348)
+* Useradd functional tests fail randomly
+* Add comments to trusted_certs_content
+* fixes a bug where providers would not get defined if a top-level ruby constant with the same name was already defined (ark cookbook, chrome cookbook)
+* Fix a bug in `reboot`, `ips_package`, `paludis_package`, `windows_package` resources where `action :nothing` was not permitted
+* Use Chef::ApiClient#from_hash in `knife client create` to avoid json_class requirement. [Issue 2542](https://github.com/chef/chef/issues/2542)
+* Add support for policyfile native API (preview). These APIs are unstable, and you may be forced to delete data uploaded to them in a
+  future release, so only use them for demonstration purposes.
+* Deprecation warning for 'knife cookbook test'
+* dsc_script should now correctly honor timeout. See [Issue 2831](https://github.com/chef/chef/issues/2831)
+* Added an `imports` attribute to dsc_script. This attribute allows you to specify DSC resources that need to be imported for your script.
+* Fixed error where guard resources (using :guard_interpreter) were not ran in `why_run` mode [Issue 2694](https://github.com/chef/chef/issues/2694)
+* Add `verify` method to File resource per RFC027
+* Move supermarket.getchef.com to supermarket.chef.io
+* Check with AccessCheck for permission to write to directory on Windows
+* Add declare_resource/build_resource comments, fix faulty ||=
+* Knife bootstrap creates a client and ships it to the node to implement validatorless bootstraps
+* Knife bootstrap can use the client it creates to setup chef-vault items for the node
+* windows service now has a configurable timeout
+
+## 12.0.3
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+[Issue 2594](https://github.com/opscode/chef/issues/2594) Restore missing require in `digester`.
+
+## 12.0.2
+* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider
+* [Issue 2609](https://github.com/opscode/chef/issues/2609) Resolve the circular dependency between ProviderResolver and Resource.
+* [Issue 2596](https://github.com/opscode/chef/issues/2596) Fix nodes not writing to disk
+* [Issue 2580](https://github.com/opscode/chef/issues/2580) Make sure the relative paths are preserved when using link resource.
+* [Pull 2630](https://github.com/opscode/chef/pull/2630) Improve knife's SSL error messaging
+* [Issue 2606](https://github.com/opscode/chef/issues/2606) chef 12 ignores default_release for apt_package
+* [Issue 2602](https://github.com/opscode/chef/issues/2602) Fix `subscribes` resource notifications.
+* [Issue 2578](https://github.com/opscode/chef/issues/2578) Check that `installed` is not empty for `keg_only` formula in Homebrew provider.
+* [**gh2k**](https://github.com/gh2k):
+  [Issue 2625](https://github.com/opscode/chef/issues/2625) Fix missing `shell_out!` for `windows_package` resource
+* [**BackSlasher**](https://github.com/BackSlasher):
+  [Issue 2634](https://github.com/opscode/chef/issues/2634) Fix `option ':command' is not a valid option` error in subversion provider.
+* [**Seth Vargo**](https://github.com/sethvargo):
+  [Issue 2345](https://github.com/opscode/chef/issues/2345) Allow knife to install cookbooks with metadata.json.
+
+## 12.0.1
+
+* [Issue 2552](https://github.com/opscode/chef/issues/2552) Create constant for LWRP before calling `provides`
+* [Issue 2545](https://github.com/opscode/chef/issues/2545) `path` attribute of `execute` resource is restored to provide backwards compatibility with Chef 11.
+* [Issue 2565](https://github.com/opscode/chef/issues/2565) Fix `Chef::Knife::Core::BootstrapContext` constructor for knife-windows compat.
+* [Issue 2566](https://github.com/opscode/chef/issues/2566) Make sure Client doesn't raise error when interval is set on Windows.
+* [Issue 2560](https://github.com/opscode/chef/issues/2560) Fix `uninitialized constant Windows::Constants` in `windows_eventlog`.
+* [Issue 2563](https://github.com/opscode/chef/issues/2563) Make sure the Chef Client rpm packages are signed with GPG keys correctly.
+
+## 12.0.0
+
+* [**Jesse Hu**](https://github.com/jessehu):
+  retry on HTTP 50X Error when calling Chef REST API
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+  The chef-apply command now prints usage information when called without arguments
+* [**Kazuki Saito**](https://github.com/sakazuki):
+  CHEF-4933: idempotency fixes for ifconfig provider
+* [**Kirill Shirinkin**](https://github.com/Fodoj):
+  The knife bootstrap command expands the path of the secret-file
+* [**Malte Swart**](https://github.com/mswart):
+  [CHEF-4101] DeepMerge - support overwriting hash values with nil
+* [**James Belchamber**](https://github.com/JamesBelchamber):
+  Mount provider remount action now honours options
+* [**Mark Gibbons**](https://github.com/MarkGibbons):
+  Fix noauto support in Solaris Mount Provider
+* [**Jordan Evans**](https://github.com/jordane):
+  support version constraints in value_for_platform
+* [**Yukihiko Sawanobori**](https://github.com/sawanoboly):
+  Add environment resource attribute to scm resources
+* [**Grzesiek Kolodziejczyk**](https://github.com/grk):
+  Use thread-safe OpenSSL::Digest instead of Digest
+* [**Grzesiek Kolodziejczyk**](https://github.com/grk):
+  Chef::Digester converted to thread-safe Singleton mixin.
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+  Reload systemd service only if it's running, otherwise start.
+* [**Chris Jerdonek**](https://github.com/cjerdonek):
+  knife diagnostic messages sent to stdout instead of stderr
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+  Remove the unused StreamingCookbookUploader class (CHEF-4586)
+* [**Jacob Vosmaer**](https://github.com/jacobvosmaer):
+  Fix creation of non-empty FreeBSD groups (#1698)
+* [**Nathan Huff**](https://github.com/nhuff):
+  Check local repository for ips package installs (#1703)
+* [**Sean Clemmer**](https://github.com/sczizzo):
+  Fix "cron" resource handling of special strings (e.g. @reboot, @yearly) (#1708)
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  'group' provider on OSX properly uses 'dscl' to determine existing groups
+* [**Hugo Lopes Tavares**](https://github.com/hltbra):
+  Catch StandardError in Chef::ResourceReporter#post_reporting_data (Issue 1550).
+* [**Daniel O'Connor**](https://github.com/CloCkWeRX):
+  Fix regex causing DuplicateRole error (Issue 1739).
+* [**Xeron**](https://github.com/xeron):
+  Ability to specify an array for data_bag_path. (CHEF-3399, CHEF-4753)
+* [**Jordan**](https://github.com/jordane):
+  Use Systemd for recent Fedora and RHEL 7.
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+  Encrypted data bags should use different HMAC key and include the IV in the HMAC (CHEF-5356).
+* [**Pierre Ynard**](https://github.com/linkfanel):
+  Don't modify variable passed to env resource when updating.
+* [**Chris Aumann**](https://github.com/chr4):
+  Add "force" attribute to resource/user, pass "-f" to userdel. (Issue 1601)
+* [**Brian Cobb**](https://github.com/bcobb):
+  Chef::VersionConstraint#to_s should accurately reflect constraint's behavior.
+* [**Kevin Graham**](https://github.com/kgraham):
+  Do not override ShellOut:live_stream if already set.
+* [**Mike Heijmans**](https://github.com/parabuzzle):
+  Change knife option --force to --delete-validators. (Issue 1652)
+* [**Pavel Yudin**](https://github.com/Kasen):
+  Add Parallels Cloud Server (PCS) platform support.
+* [**tbe**](https://github.com/tbe):
+  Minor fixes for the Paludis package provider:
+  * only search for non-masked packages,
+  * increase command timeout length for package installation.
+* [**sawanoboly**](https://github.com/sawanoboly):
+  Use shared_path for deploy resource.
+* [**Victor Hahn**](https://github.com/victorhahncastell):
+  Add template syntax check to files in the templates/ dir only.
+* [**Jordan**](https://github.com/jordane):
+  Allow git provider to checkout existing branch names.
+* [**Eric Herot**](https://github.com/eherot):
+  Add whitespace boundaries to some mount point references in mount provider.
+* [**Dave Eddy**](https://github.com/bahamas10):
+  Improve the regex for /etc/rc.conf for the FreeBSD service provider
+* [**Stanislav Bogatyrev**](https://github.com/realloc):
+  Fetch recipe_url before loading json_attribs in chef-solo (CHEF-5075)
+* [**Mal Graty**](https://github.com/mal):
+  Workaround for a breaking change in git's shallow-clone behavior. (Issue 1563)
+* [**Dave Eddy**](https://github.com/bahamas10):
+  Fix version detection in FreeBSD pkgng provider. (PR 1980)
+* [**Dan Rathbone**](https://github.com/rathers):
+  Fixed gem_package resource to be able to upgrade gems when version is not set.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+  Made Chef Client load library folder recursively.
+* [**Eric Saxby**](https://github.com/sax):
+  Made Chef Client read the non-root crontab entries as the user specified in the resource.
+* [**sawanoboly**](https://github.com/sawanoboly):
+  Added `--dry-run` option to `knife cookbook site share` which displays the files that are to be uploaded to Supermarket.
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+  Fixed `Chef::HTTP` to be able to follow relative redirects.
+* [**Cory Stephenson**](https://github.com/Aevin1387):
+  Fixed FreeBSD port package provider to interpret FreeBSD version 10 correctly.
+* [**Brett Chalupa**](https://github.com/brettchalupa):
+  Added `source_url` and `issues_url` options to metadata to be used by Supermarket.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+  Fixed Chef Client to use the `:client_name` instead of `:node_name` during initial client registration.
+* [**tbe**](https://github.com/tbe):
+  Fixed Paludis package provider to be able to interpret the package category.
+* [**David Workman**](https://github.com/workmad3):
+  Added a more clear error message to chef-apply when no recipe is given.
+* [**Joe Nuspl**](https://github.com/nvwls):
+  Added support for `sensitive` property to the execute resource.
+* [**Nolan Davidson**](https://github.com/nsdavidson):
+  Added an error message to prevent unintentional running of `exec()` in recipes.
+* [**wacky612**](https://github.com/wacky612):
+  Fixed a bug in pacman package provider that was preventing the installation of `bind` package.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+  Changed the default service provider to systemd on SLES versions 12 and higher.
+* [**Ionuț Arțăriși**](https://github.com/mapleoin):
+  Changed the default group provider to gpasswd on SLES versions 12 and higher.
+* [**Noah Kantrowitz**](https://github.com/coderanger):
+  Implemented [RFC017 - File Specificity Overhaul](https://github.com/opscode/chef-rfc/blob/master/rfc017-file-specificity.md).
+* [**James Bence**](https://github.com/jbence):
+  Improved the reliability of Git provider by making it to be more specific when selecting tags.
+* [**Jean Mertz**](https://github.com/JeanMertz):
+  Changed knife upload not to validate the ruby files under files & templates directories.
+* [**Alex Pop**](https://github.com/alexpop):
+  Made `knife cookbook create` to display the directory of the cookbook that is being created.
+* [**Alex Pop**](https://github.com/alexpop):
+  Fixed the information debug output for the configuration file being used when running knife.
+* [**Martin Smith**](https://github.com/martinb3):
+  Changed `knife cookbook site share` to make category an optional parameter when uploading cookbooks.
+    It is still required when the cookbook is being uploaded for the first time but on the consequent
+    uploads existing category of the cookbook will be used.
+* [**Nicolas DUPEUX**](https://github.com/vaxvms):
+  Added JSON output to `knife status` command. `--medium` and `--long` output formatting parameters are now supported in knife status.
+* [**Trevor North**](https://github.com/trvrnrth):
+  Removed dead code from `knife ssh`.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+  Fixed a bug preventing mounting of cgroup type devices in the mount provider.
+* [**Anshul Sharma**](https://github.com/justanshulsharma):
+  Fixed inconsistent globbing in `knife from file` command.
+* [**Nicolas Szalay**](https://github.com/rottenbytes):
+  Made user prompts in knife more beautiful by adding a space after Y/N prompts.
+* [**Ivan Larionov**](https://github.com/xeron):
+  Made empty run_list to produce an empty array when using node.to_hash.
+* [**Siddheshwar More**](https://github.com/siddheshwar-more):
+  Fixed a bug in knife bootstrap that caused config options to override command line options.
+* [**Thiago Oliveira**](https://github.com/chilicheech):
+  Fixed a bug in Mac OSX group provider and made it idempotent.
+* [**liseki**](https://github.com/liseki):
+  Fixed a bug in why-run mode for freebsd service resources without configured init scripts.
+* [**liseki**](https://github.com/liseki):
+  Fixed a bug in freebsd service providers to load the status correctly.
+
+
+### Chef Contributions
+
+* ruby 1.9.3 support is dropped
+* Added RFC-023 Chef 12 Attribute Changes (https://github.com/opscode/chef-rfc/blob/master/rfc023-chef-12-attributes-changes.md)
+* Added os/platform_family options to provides syntax on the Chef::Resource DSL
+* Added provides methods to the Chef::Provider DSL
+* Added supported?(resource, action) class method to all Providers for late-evaluation if a provider can handle a
+  resource
+* Added ProviderResolver feature to handle late resolution of providers based on what kinds of support is in the
+  base operating system.
+* Partial Deprecation of Chef::Platform provider mapping.  The static mapping will be removed as Chef-12 progresses
+  and the hooks will be completely dropped in Chef-13.
+* Default `guard_interpreter` for `powershell_script` resource set to `:powershell_script`, for `batch` to `:batch`
+* Recipe definition now returns the retval of the definition
+* Add support for Windows 10 to version helper.
+* `dsc_script` resource should honor configuration parameters when `configuration_data_script` is not set (Issue #2209)
+* Ruby has been updated to 2.1.3 along with rubygems update to 2.4.2
+* Removed shelling out to erubis/ruby for syntax checks (>= 1.9 has been able
+  to do this in the ruby vm itself for awhile now and we've dropped 1.8.7 which
+  could not do this and had to shell_out)
+* Report the request and response when a non-200 error code happens
+* [FEATURE] Upgrade `knife upload` and `knife download` to download
+  **everything** in an organization, now including the organization definition
+  itself (`knife download /org.json`) and the invitations and member list
+  (`knife download /invitations.json` and `knife download /members.json`).
+  Should be compatible with knife-ec-backup.
+* Make default Windows paths more backslashy
+* `knife` now prefers to load `config.rb` in preference to `knife.rb`;
+`knife.rb` will be used if `config.rb` is not found.
+* Fixed Config[:cache_path] to use path_join()
+* Updated chef-zero to 3.0, so that client tests can be run against Enterprise
+  Chef as well as Open Source.
+* knife cookbook site download/list/search/share/show/unshare now uses
+  supermerket.getchef.com urls
+* added Chef::ResourceCollection#insert_at API to the ResourceCollection
+* http_proxy and related config vars no longer clobber already set ENV vars
+* all http_proxy configs now set lowercase + uppercase versions of ENV vars
+* https_proxy/ftp_proxy support setting `http://` URLs (and whatever mix and match makes sense)
+* End-to-end tests for Ubuntu 12.04
+* Only run end-to-end tests when secure environment variables are present.
+* Remove recipe DSL from base provisioner (Issue 1446).
+* Enable client-side key generation by default. (Issue 1711)
+* CookbookSiteStreamingUploader now uses ssl_verify_mode config option (Issue 1518).
+* chef/json_compat now throws its own exceptions not JSON gem exceptions
+* Modify action for env raises Chef::Exceptions::Env exception on Windows (Chef Issues 1754)
+* Fix a bug in the experimental Policyfile mode that caused errors when
+  using templates.
+* Disable JSON encoding of request body when non-JSON content type is
+  specified.
+* Clean up FileVendor and CookbookUploader internal APIs
+* log resource now marks itself as supporting why-run
+* http_request no longer appends "?message=" query string to GET and HEAD requests
+* added shell_out commands directly to the recipe DSL
+* cookbook synchronizer deletes old files from cookbooks
+* do not clear file cache when override run list is set (CHEF-3684)
+* ruby 1.8.7/1.9.1/1.9.2 support is dropped
+* set no_lazy_load to true (CHEF-4961)
+* set file_stating_uses_destdir config option default to true (CHEF-5040)
+* remove dependency on rest-client gem
+* Add method shell_out_with_systems_locale to ShellOut.
+* chef-repo rake tasks are deprecated; print relevant information for
+  each one.
+* Fix RPM package version detection (Issue 1554)
+* Don't override :default provider map if :default passed as platform (OC-11667).
+* Fix SuSE package removal failure (Issue 1732).
+* Enable Travis to run Test Kitchen with Kitchen EC2.
+* Fix a bug in reporting not to post negative duration values.
+* Add password setting support for Mac 10.7, 10.8 and 10.9 to the dscl user provider.
+* ChefSpec can find freebsd_package resource correctly when a package resource is declared on Freebsd.
+* Autodetect/decrypt encrypted data bag items with data_bag_item dsl method. (Issue 1837, Issue 1849)
+* windows_user: look up username instead of resource name (Issue #1705)
+* Remove the unused bootstrap templates that install chef from rubygems
+* Remove the Chef 10 functionality from bootstrap.
+* Deprecate --distro / --template_file options in favor of --boostrap-template
+* Add `:node_ssl_verify_mode` & `:node_verify_api_cert` options to bootstrap
+  to be able to configure these settings on the bootstrapped node.
+* Add partial_search dsl method to Chef::Search::Query, add result filtering to search.
+* Transfer trusted certificates under :trusted_certs_dir during bootstrap.
+* Set :ssl_verify_mode to :verify_peer by default.
+* Add homebrew provider for package resource, use it by default on OS X (Issue #1709)
+* Add escape_glob method to PathHelper, update glob operations.
+* Verify x509 properties of certificates in the :trusted_certs_dir during knife ssl check.
+* Disable unforked interval chef-client runs.
+* Removed dependencies on the 'json' gem, replaced with ffi-yajl.  Use Chef::JSONCompat library for parsing and printing.
+* Restore the deprecation logic of #valid_actions in LWRPs until Chef 13.
+* Now that we don't allow unforked chef-client interval runs, remove the reloading of previously defined LWRPs.
+* Use shell_out to determine Chef::Config[:internal_locale], fix CentOS locale detection bug.
+* `only_if` and `not_if` attributes of `execute` resource now inherits the parent resource's
+  attributes when set to a `String`.
+* Retain the original value of `retries` for resources and display the original value when the run fails.
+* Added service provider for AIX.
+* The Windows env provider will delete elements even if they are only in ENV (and not in the registry)
+* Allow events to be logged to Windows Event Log
+* Fixed bug in env resource where a value containing the delimiter could never correctly match the existing values
+* More intelligent service check for systemd on Ubuntu 14.10.
+
+## 11.16.4
+
+* Windows omnibus installer security updates for redistributed bash.exe / sh.exe
+  vulnerabilities ("Shellshock") CVE-2014-6271, CVE-2014-6271, CVE-2014-6278,
+  CVE-2014-7186, CVE-2014-7187.
+* Fix bug on Windows where using the env resource on path could render the path unusable.
+* Chef Client now retries when it gets 50X from Chef Server.
+* Chef Client 11.16.4 can use the policyfiles generated with Chef DK 0.3.0.
+
+## 11.16.2
+
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  Fix a regression in whyrun_safe_ruby_block.
+
+## 11.16.0
+
+* Fix a bug in user dscl provider to enable managing password and other properties at the same time.
+* Add `dsc_script` resource to Chef for PowerShell DSC support on Windows
+
+## 11.14.6:
+
+* Modify action for env raises Chef::Exceptions::Env exception on Windows (Chef Issues 1754)
+* Fix RPM package version detection (Issue 1554)
+* Fix a bug in reporting not to post negative duration values.
+* Add password setting support for Mac 10.7, 10.8 and 10.9 to the dscl user provider.
+* ChefSpec can find freebsd_package resource correctly when a package resource is declared on Freebsd.
+* http_proxy and related config vars no longer clobber already set ENV vars
+* all http_proxy configs now set lowercase + uppercase versions of ENV vars
+* https_proxy/ftp_proxy support setting `http://` URLs (and whatever mix and match makes sense)
+
+## 11.14.2
+
+* [**Jess Mink**](https://github.com/jmink):
+  Symlinks to directories should be swingable on windows (CHEF-3960)
+* [**Phil Dibowitz**](https://github.com/jaymzh):
+  SIGTERM will once-more kill a non-daemonized chef-client (CHEF-5172)
+* [**Pierre Ynard**](https://github.com/linkfanel):
+  chef-service-manager should run as a non-interactive service (CHEF-5150)
+* [**Tensibai Zhaoying**](https://github.com/Tensibai):
+  Fix file:// URI support in remote\_file on windows (CHEF-4472)
+* [**John Dyer**](https://github.com/johntdyer):
+  Catch HTTPServerException for 404 in remote_file retry (CHEF-5116)
+* [**Pavel Yudin**](https://github.com/Kasen):
+  Providers are now set correctly on CloudLinux. (CHEF-5182)
+* [**Joe Richards**](https://github.com/viyh):
+  Made -E option to work with single lettered environments. (CHEF-3075)
+* [**Jimmy McCrory**](https://github.com/JimmyMcCrory):
+  Added a 'knife node environment set' command. (CHEF-1910)
+* [**Hongbin Lu**](https://github.com/hongbin):
+  Made bootstrap report authentication exceptions. (CHEF-5161)
+* [**Richard Manyanza**](https://github.com/liseki):
+  Made `freebsd_package` resource use the brand new "pkgng" package
+  manager when available.(CHEF-4637)
+* [**Nikhil Benesch**](https://github.com/benesch):
+  Implemented a threaded download queue for synchronizing cookbooks. (CHEF-4423)
+* [**Chulki Lee**](https://github.com/chulkilee):
+  Raise an error when source is accidentally passed to apt_package (CHEF-5113)
+* [**Cam Cope**](https://github.com/ccope):
+  Add an open_timeout when opening an http connection (CHEF-5152)
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+  Allow environment variables set on Windows to be used immediately (CHEF-5174)
+* [**Luke Amdor**](https://github.com/rubbish):
+  Add an option to configure the chef-zero port (CHEF-5228)
+* [**Ricardo Signes**](https://github.com/rjbs):
+  Added support for the usermod provider on OmniOS
+* [**Anand Suresh**](https://github.com/anandsuresh):
+  Only modify password when one has been specified. (CHEF-5327)
+* [**Stephan Renatus**](https://github.com/srenatus):
+  Add exception when JSON parsing fails. (CHEF-5309)
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+  OK to exclude space in dependencies in metadata.rb. (CHEF-4298)
+* [**Łukasz Jagiełło**](https://github.com/ljagiello):
+  Allow cookbook names with leading underscores. (CHEF-4562)
+* [**Michael Bernstein**](https://github.com/mrb):
+  Add Code Climate badge to README.
+* [**Phil Sturgeon**](https://github.com/philsturgeon):
+  Documentation that -E is not respected by knife ssh [search]. (CHEF-4778)
+* [**Stephan Renatus**](https://github.com/srenatus):
+  Fix resource_spec.rb.
+* [**Sander van Harmelen**](https://github.com/svanharmelen):
+  Ensure URI compliant urls. (CHEF-5261)
+* [**Robby Dyer**](https://github.com/robbydyer):
+  Correctly detect when rpm_package does not exist in upgrade action. (CHEF-5273)
+* [**Sergey Sergeev**](https://github.com/zhirafovod):
+  Hide sensitive data output on chef-client error (CHEF-5098)
+* [**Mark Vanderwiel**](https://github.com/kramvan1):
+  Add config option :yum-lock-timeout for yum-dump.py
+* [**Peter Fern**](https://github.com/pdf):
+  Convert APT package resource to use `provides :package`, add timeout parameter.
+* [**Xabier de Zuazo**](https://github.com/zuazo):
+  Fix Chef::User#list API error when inflate=true. (CHEF-5328)
+* [**Raphaël Valyi**](https://github.com/rvalyi):
+  Use git resource status checking to reduce shell_out system calls.
+* [**Eric Krupnik**](https://github.com/ekrupnik):
+  Added .project to git ignore list.
+* [**Ryan Cragun**](https://github.com/ryancragun):
+  Support override_runlist CLI option in shef/chef-shell. (CHEF-5314)
+* [**Cam Cope**](https://github.com/ccope):
+  Fix updating user passwords on Solaris. (CHEF-5247)
+* [**Ben Somers**](https://github.com/bensomers):
+  Enable storage of roles in subdirectories for chef-solo. (CHEF-4193)
+* [**Robert Tarrall**](https://github.com/tarrall):
+  Fix Upstart provider with parameters. (CHEF-5265)
+* [**Klaas Jan Wierenga**](https://github.com/kjwierenga):
+  Don't pass on default HTTP port(80) in Host header. (CHEF-5355)
+* [**MarkGibbons**](https://github.com/MarkGibbons):
+  Allow for undefined solaris services in the service resource. (CHEF-5347)
+* [**Allan Espinosa**](https://github.com/aespinosa):
+  Properly knife bootstrap on ArchLinux. (CHEF-5366)
+* [**Matt Hoyle**](https://github.com/deployable):
+  Made windows service resource to handle transitory states. (CHEF-5319, CHEF-4791)
+* [**Brett cave**](https://github.com/brettcave):
+  Add Dir.pwd as fallback for default user_home if home directory is not set. (CHEF-5365)
+* [**Caleb Tennis**](https://github.com/ctennis):
+  Add support for automatically using the Systemd service provider when available. (CHEF-3637)
+* [**Matt Hoyle**](https://github.com/deployable):
+  Add timeout for Chef::Provider::Service::Windows. (CHEF-1165)
+* [**Jesse Hu**](https://github.com/jessehu):
+  knife[:attribute] in knife.rb should not override --attribute (CHEF-5158)
+* [**Vasiliy Tolstov**](https://github.com/vtolstov):
+  Added the initial exherbo linux support for Chef providers.
+
+* Fix knife cookbook site share on windows (CHEF-4994)
+* YAJL Allows Invalid JSON File Sending To The Server (CHEF-4899)
+* YAJL Silently Ingesting Invalid JSON and "Normalizing" Incorrectly (CHEF-4565)
+* Update rpm provider checking regex to allow for special characters (CHEF-4893)
+* Allow for spaces in selinux controlled directories (CHEF-5095)
+* Windows batch resource run action fails: " TypeError: can't convert nil into String" (CHEF-5287)
+* Log resource always triggers notifications (CHEF-4028)
+* Prevent tracing? from throwing an exception when first starting chef-shell.
+* Use Upstart provider on Ubuntu 13.10+. (CHEF-5276)
+* Cleaned up mount provider superclass
+* Added "knife serve" to bring up local mode as a server
+* Print nested LWRPs with indentation in doc formatter output
+* Make local mode stable enough to run chef-pedant
+* Wrap code in block context when syntax checking so `return` is valid
+  (CHEF-5199)
+* Quote git resource rev\_pattern to prevent glob matching files (CHEF-4940)
+* User resource now only prints the name during why-run runs. (CHEF-5180)
+* Set --run-lock-timeout to wait/bail if another client has the runlock (CHEF-5074)
+* remote\_file's source attribute does not support DelayedEvaluators (CHEF-5162)
+* `option` attribute of mount resource now supports lazy evaluation. (CHEF-5163)
+* `force_unlink` now only unlinks if the file already exists. (CHEF-5015)
+* `chef_gem` resource now uses omnibus gem binary. (CHEF-5092)
+* chef-full template gets knife options to override install script url, add wget/curl cli options, and custom install commands (CHEF-4697)
+* knife now bootstraps node with the latest current version of chef-client. (CHEF-4911)
+* Add config options for attribute whitelisting in node.save. (CHEF-3811)
+* Use user's .chef as a fallback cache path if /var/chef is not accessible. (CHEF-5259)
+* Fixed Ruby 2.0 Windows compatibility issues around ruby-wmi gem by replacing it with wmi-lite gem.
+* Set proxy environment variables if preset in config. (CHEF-4712)
+* Automatically enable verify_api_cert when running chef-client in local-mode. (Chef Issues 1464)
+* Add helper to warn for broken [windows] paths. (CHEF-5322)
+* Send md5 checksummed data for registry key if data type is binary, dword, or qword. (Chef-5323)
+* Add warning if host resembles winrm command and knife-windows is not present.
+* Use FFI binders to attach :SendMessageTimeout to avoid DL deprecation warning. (ChefDK Issues 69)
+* Use 'guest' user on AIX for RSpec tests. (OC-9954)
+* Added DelayedEvaluator support in LWRP using the `lazy {}` key
+* Fixed a bug where nested resources that inherited from Resource::LWRPBase
+  would not share the same actions/default_action as their parent
+* Raise error if a guard_interpreter is specified and a block is passed to a guard (conditional)
+* Allow specifying a guard_interpreter after a conditional on a resource (Fixes #1943)
+* Windows package type should be a symbol (Fixes #1997)
diff --git a/CHEF_MVPS.md b/CHEF_MVPS.md
new file mode 100644
index 0000000..dd46ea9
--- /dev/null
+++ b/CHEF_MVPS.md
@@ -0,0 +1,108 @@
+### Chef is proud of our community!
+
+Every release of Chef we pick someone from the community to name as the Most Valuable Player for that release. It could be someone who provided a big feature, reported a security vulnerability, or someone doing great things in the community that we want to highlight.
+
+In addition to the Hall of Fame and MVP recipients, three individuals are awarded the distinction of "Awesome Community Chef" each year at ChefConf.
+
+#### Hall of Fame
+
+After receiving three MVP awards, we add someone to the hall of fame. We want to express our gratitude to their continuing participation and give newer community members the opportunity to be recognized.
+
+* Matthew Kent
+* Doug MacEachern
+* Tollef Fog Heen
+* Thom May
+* Bryan Berry
+* Bryan McLellan
+* Jeff Blaine
+
+#### The MVP recipients
+
+| Release | Date | MVP |
+|---------|------|-----|
+| [Client 11.16.0](https://www.chef.io/blog/2014/09/08/release-chef-client-11-16-0-ohai-7-4-0/) | 2014-09-08 | Jesse Hu |
+| [Client 11.14.2](https://www.chef.io/blog/2014/08/01/release-chef-client-11-14-2/) | 2014-08-01 | Nikhil Benesch |
+| [Client 11.12.0](https://www.chef.io/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Chris Bandy |
+| [Client 11.10.4](https://www.chef.io/blog/2014/02/20/chef-client-patch-release-11-10-4/) | 2014-02-20 | Jon Cowie |
+| [Client 11.10.2](https://www.chef.io/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Eric Tucker |
+| [Client 11.10.0](https://www.chef.io/blog/2014/02/06/chef-client-11-10-0-release/) | 2014-02-06 | Nikhil Benesch |
+| [Client 11.8.2](https://www.chef.io/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | James Ogden |
+| [Client 11.8.0](https://www.chef.io/blog/2013/10/31/release-chef-client-11-8-0-ohai-6-20-0/) | 2013-10-31 | Eric Saxby |
+| [Client 11.6.2](https://www.chef.io/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
+| [Client 11.6.0](https://www.chef.io/blog/2013/07/23/chef-client-11-6-0-ohai-6-18-0-and-more/) | 2013-07-23 | Jesse Campbell |
+| [Client 11.4.0](https://www.chef.io/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Vaidas Jablonskis |
+| [Client 11.2.0](https://www.chef.io/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Mike Javorski |
+| [Chef 11.0.0](https://www.chef.io/blog/2013/02/04/chef-11-released/) | 2013-02-04 | Andrea Campi, Bryan Berry |
+| [Chef 10.32.2](https://www.chef.io/blog/2014/04/08/release-chef-client-11-12-0-10-32-2/) | 2014-04-08 | Phil Dibowitz |
+| [Chef 10.30.4](https://www.chef.io/blog/2014/02/18/chef-client-release-11-10-2-10-30-4/) | 2014-02-18 | Christopher Laco |
+| [Chef 10.30.2](https://www.chef.io/blog/2013/12/06/release-chef-client-10-30-2-11-8-2-mixlib-shellout-1-3-0/) | 2013-12-06 | Phil Dibowitz |
+| [Chef 10.28.2](https://www.chef.io/blog/2013/10/08/release-chef-client-11-6-2-10-28-2/) | 2013-10-08 | Jeff Blaine |
+| [Chef 10.28.0](https://www.chef.io/blog/2013/09/03/chef-10-28-0-released/) | 2013-09-03 | Jeff Blaine |
+| [Chef 10.26.0](https://www.chef.io/blog/2013/05/08/chef-10-26-0-released/) | 2013-05-08 | Ranjib Dey |
+| [Chef 10.24.0](https://www.chef.io/blog/2013/02/15/chef-server-11-0-6-and-10-24-0-released/) | 2013-02-15 | Anthony Goddard |
+| [Chef 10.22.0](https://www.chef.io/blog/2013/02/13/chef-client-11-4-0-10-22-0-released/) | 2013-02-13 | Brian Bianco |
+| [Chef 10.20.0](https://www.chef.io/blog/2013/02/07/chef-client-11-2-0-10-20-0-released/) | 2013-02-06 | Chris Roberts |
+| [Chef 10.18.2](https://www.chef.io/blog/2013/01/18/chef-10-18-2-bugfix-release/) | 2013-01-18 | Fletcher Nichol |
+| [Chef 10.18.0](https://www.chef.io/blog/2013/01/16/chef-10-18-0-released/) | 2013-01-16 | Xabier de Zuazo |
+| [Chef 10.16.6](https://www.chef.io/blog/2013/01/11/chef-10-16-6-security-release/) | 2013-01-11 | Dan Kubb |
+| [Chef 10.16.4](https://www.chef.io/blog/2012/12/26/chef-10-16-4-released/) | 2012-12-26 | Avishai Ish-Shalom |
+| [Chef 10.16.2](https://www.chef.io/blog/2012/10/26/chef-10-16-2-released/) | 2012-10-26 | Jamie Winsor |
+| [Chef 10.16.0](https://www.chef.io/blog/2012/10/22/chef-10-16-0-released/) | 2012-10-22 | John Dewey |
+| [Chef 10.14.4](https://www.chef.io/blog/2012/09/28/chef-10-14-4-released/) | 2012-09-27 | Kendrick Martin |
+| [Chef 10.14.2](https://www.chef.io/blog/2012/09/11/chef-10-14-2-released/) | 2012-09-10 | Phil Dibowitz, Tim Smith |
+| [Chef 10.14.0](https://www.chef.io/blog/2012/09/07/chef-10-14-0-released/) | 2012-09-07 | Xabier de Zuazo |
+| [Chef 10.12.0](https://www.chef.io/blog/2012/06/19/chef-10-12-0-released/) | 2012-06-18 | Chris Roberts |
+| [Chef 0.10.10](https://www.chef.io/blog/2012/05/11/chef-0-10-10-released/) | 2012-05-11 | Juanje Ojeda, Igor Afonov |
+| [Chef 0.10.8](https://www.chef.io/blog/2011/12/15/chef-0-10-8-released/) | 2011-12-15 | Bryan Berry |
+| [Chef 0.10.6](https://www.chef.io/blog/2011/12/14/chef-0-10-6-released/) | 2011-12-13 | Andrea Campi |
+| [Chef 0.10.4](https://www.chef.io/blog/2011/08/11/chef-0-10-4-released/) | 2011-08-11 | Matthew Kent |
+| [Chef 0.10.2](https://www.chef.io/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Daniel Oliver |
+| [Chef 0.10.0](https://www.chef.io/blog/2011/05/02/chef-0-10-0-released/) | 2011-05-02 | Grace Mollison, Darrin Eden |
+| [Chef 0.9.18](https://www.chef.io/blog/2011/06/29/chef-0-10-2-and-0-9-18-released/) | 2011-06-29 | Jesai Langenbach |
+| [Chef 0.9.16](https://www.chef.io/blog/2011/04/15/chef-0-9-16-released/) | 2011-04-15 | Michael Leinartas |
+| [Chef 0.9.14](https://www.chef.io/blog/2011/03/04/chef-0-9-14-released/) | 2011-03-04 | Gilles Devaux |
+| [Chef 0.9.12](https://www.chef.io/blog/2010/10/22/chef-0-9-12-released/) | 2010-10-22 | Laurent Désarmes |
+| [Chef 0.9.10](https://www.chef.io/blog/2010/10/19/chef-0-9-10-ohai-0-5-8-and-mixliblog-1-2-0-released/) | 2010-10-19 | Toomas Pelberg, Tommy Bishop |
+| [Chef 0.9.8](https://www.chef.io/blog/2010/08/05/chef-0-9-8-and-mixlib-authentication-1-1-4-released/) | 2010-08-05 | Joe Williams |
+| [Chef 0.9.6](https://www.chef.io/blog/2010/07/03/chef-0-9-6-released/) | 2010-07-03 | Caleb Tennis |
+| [Chef 0.9.4](https://www.chef.io/blog/2010/06/30/chef-0-9-4-released/) | 2010-06-30 | Ian Meyer |
+| [Chef 0.9.0](https://www.chef.io/blog/2010/06/21/chef-0-9-0-and-ohai-0-5-6-released/) | 2010-06-21 | Doug MacEachern |
+| [Chef 0.8.16](https://www.chef.io/blog/2010/05/11/chef-0-8-16-and-ohai-0-5-4-release/) | 2010-05-11 | Akzhan Abdulin |
+| [Chef 0.8.14](https://www.chef.io/blog/2010/05/07/chef-0-8-14-release/) | 2010-05-07 | Renaud Chaput |
+| [Chef 0.8.10](https://www.chef.io/blog/2010/04/02/chef-0-8-10-release/) | 2010-04-02 | Thom May, Tollef Fog Heen |
+| [Chef 0.8.8](https://www.chef.io/blog/2010/03/18/chef-0-8-8-release/) | 2010-03-18 | Eric Hankins |
+| [Chef 0.8.6](https://www.chef.io/blog/2010/03/05/chef-0-8-6-release/) | 2010-03-05 | Ian Meyer |
+| [Chef 0.8.4](https://www.chef.io/blog/2010/03/02/chef-0-8-4-release/) | 2010-03-02 | Tollef Fog Heen |
+| [Chef 0.8.2](https://www.chef.io/blog/2010/03/01/chef-0-8-2-release/) | 2010-03-01 | Scott M. Likens |
+| [Chef 0.7.16](https://www.chef.io/blog/2009/12/22/chef-0-7-16-release/) | 2009-12-22 | Bryan McLellan |
+| [Chef 0.7.14](https://www.chef.io/blog/2009/10/26/chef-0-7-14-ohai-0-3-6-releases/) | 2009-10-16 | Thom May |
+| [Chef 0.7.12](https://www.chef.io/blog/2009/10/06/chef-0-7-12rc0-ohai-0-3-4rc0-releases/) | 2009-10-06 | Diego Algorta |
+| [Chef 0.7.10](https://www.chef.io/blog/2009/09/04/chef-0-7-10-release/) | 2009-09-04 | Dan DeLeo |
+| [Chef 0.7.8](https://www.chef.io/blog/2009/08/13/chef-0-7-8-release/) | 2009-08-13 | Jeppe Nejsum Madsen |
+| [Chef 0.7.6](https://www.chef.io/blog/2009/08/08/chef-0-7-6-release/) | 2009-08-08 | Grant Zanetti |
+| [Chef 0.7.4](https://www.chef.io/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Hongli Lai |
+| [Chef 0.7.2](https://www.chef.io/blog/2009/06/26/back-to-back-chef-0-7-2-and-chef-0-7-4-released/) | 2009-06-26 | Joshua Sierles |
+| [Chef 0.7.0](https://www.chef.io/blog/2009/06/10/chef-0-7-0-release/) | 2009-06-10 | Matthew Kent |
+| [Chef 0.6.2](https://www.chef.io/blog/2009/04/29/chef-0-6-2-release/) | 2009-04-29 | David Balatero |
+| [Chef 0.6.0](https://www.chef.io/blog/2009/04/29/chef-0-6-0-release/) | 2009-04-29 | Matthew Kent |
+| [Chef 0.5.6](https://www.chef.io/blog/2009/03/06/chef-0-5-6/) | 2009-03-06 | Sean Cribbs |
+| [Chef 0.5.4](https://www.chef.io/blog/2009/02/13/chef-0-5-4/) | 2009-02-13 | Arjuna Christensen |
+| [Chef 0.5.2](https://www.chef.io/blog/2009/02/01/chef-0-5-2-and-ohai-0-1-4/) | 2009-02-01 | Bryan McLellan |
+
+#### Awesome Community Chefs
+
+Each year at ChefConf, three individuals are awarded the Awesome Community Chef award. The Awesome Community Chef awards are a way for the community to recognize a few of the individuals who have made a dramatic impact and have helped further the cause.
+
+* 2013
+  * [Bryan Berry](https://github.com/bryanwb)
+  * [Fletcher Nichol](https://github.com/fnichol)
+  * [Jamie Winsor](https://github.com/reset)
+* 2014
+  * [Ranjib Dey](https://github.com/ranjib)
+  * [Miah Johnson](https://github.com/miah)
+  * [Seth Vargo](https://github.com/sethvargo)
+  * [Eric Wolfe](https://github.com/atomic-penguin)
+* 2015
+  * [Jon Cowie](https://github.com/jonlives)
+  * [Noah Kantrowitz](https://github.com/coderanger)
+  * [Matt Wrock](https://github.com/mwrock)
\ No newline at end of file
diff --git a/CLA_ARCHIVE.md b/CLA_ARCHIVE.md
new file mode 100644
index 0000000..2593a71
--- /dev/null
+++ b/CLA_ARCHIVE.md
@@ -0,0 +1,2510 @@
+
+Corporate CLAs
+
+The list of Corporate CLAs allowed to contribute to Opscode projects. Only contributions from approved employees of these companies are acceptable.
+
+Employees get approved by being listed on the schedule A of the Corporate CLA.
+
+| **Number:** | **Company:**                           | **Date:** |
+|:------------|:---------------------------------------|:----------|
+|  1          |  Opscode                               |           |
+|  2          |  Engine Yard                           |  1/7/09   |
+|  3          |  Wikia                                 |           |
+|  4          |  Aptana                                |  2/12/09  |
+|  5          |  CleanOffer                            |  3/2/09   |
+|  6          |  37signals                             |  3/4/09   |
+|  7          |  Nomitor                               |  3/9/09   |
+|  8          |  We Go To 12                           |  4/30/09  |
+|  9          |  Plus2 Pty                             |  5/8/09   |
+|  10         |  Phusion                               |  6/22/09  |
+|  11         |  Rightscale                            |  6/30/09  |
+|  12         |  Rubaidh                               |  7/27/09  |
+|  13         |  Peritor GmbH                          |  8/12/09  |
+|  14         |  Heroku                                |  8/13/09  |
+|  15         |  Internet Exchange                     |  9/22/09  |
+|  16         |  Betfair                               |  9/30/09  |
+|  17         |  Sojern                                |  11/2/09  |
+|  18         |  Runa                                  |  12/20/09 |
+|  19         |  MaxMedia                              |  1/11/10  |
+|  20         |  Quantifind                            |  2/11/10  |
+|  21         |  VMware                                |  2/11/10  |
+|  22         |  Rackspace                             |  2/26/10  |
+|  23         |  Leaway Enterprise                     |  3/16/10  |
+|  24         |  Bueda                                 |  3/30/10  |
+|  25         |  Divergent Logic                       |  5/3/10   |
+|  26         |  Basho Technologies                    |  5/4/10   |
+|  27         |  Seven Scale                           |  5/13/10  |
+|  28         |  IglooNET                              |  5/21/10  |
+|  29         |  Freistil Consulting                   |  5/25/10  |
+|  30         |  Promet Solutions                      |  5/25/10  |
+|  31         |  Mint Digital                          |  6/16/10  |
+|  32         |  Picklive                              |  6/16/10  |
+|  33         |  42 Lines                              |  6/27/10  |
+|  34         |  Wildfire Interactiv                   |  7/9/10   |
+|  35         |  Dynamic Network Services              |  7/21/10  |
+|  36         |  PeerPong                              |  8/4/10   |
+|  37         |  domainfactory GmbH                    |  8/16/10  |
+|  38         |  Tecnh                                 |  8/17/10  |
+|  39         |  9Summer                               |  9/9/10   |
+|  40         |  Wixpress                              |  9/13/10  |
+|  41         |  Blue Box Group                        |  9/29/10  |
+|  42         |  FindsYou Limited                      |  10/6/10  |
+|  43         |  Highgroove Studios                    |  10/25/10 |
+|  44         |  ZeStuff                               |  10/28/10 |
+|  45         |  Worlize                               |  10/28/10 |
+|  46         |  Automated Labs                        |  11/3/10  |
+|  47         |  Estately                              |  11/4/10  |
+|  48         |  Kapoq                                 |  11/10/10 |
+|  49         |  Openminds                             |  11/10/10 |
+|  50         |  MobileCause                           |  11/10/10 |
+|  51         |  Atalanta Systems                      |  11/14/10 |
+|  52         |  Menue Americas                        |  11/17/10 |
+|  53         |  Sociable Limited                      |  12/1/10  |
+|  54         |  Nine Summer                           |  12/6/10  |
+|  55         |  Neo Technology                        |  1/27/11  |
+|  56         |  Moriz GmbH                            |  2/2/11   |
+|  57         |  AegisCo                               |  2/14/11  |
+|  58         |  SetJam                                |  2/15/11  |
+|  59         |  Tippr                                 |  2/18/11  |
+|  60         |  Ning                                  |  2/24/11  |
+|  61         |  Workday                               |  3/12/11  |
+|  62         |  7digital                              |  3/3/11   |
+|  63         |  PagerDuty                             |  3/17/11  |
+|  64         |  Gnowsis                               |  3/25/11  |
+|  65         |  Unboxed Consulting                    |  4/1/11   |
+|  66         |  CustomInk                             |  4/8/11   |
+|  67         |  TalentBox                             |  4/25/11  |
+|  68         |  Wavii                                 |  4/29/11  |
+|  69         |  Datadog                               |  5/4/11   |
+|  70         |  Viximo                                |  5/10/11  |
+|  71         |  ZephirWorks                           |  5/11/11  |
+|  72         |  Dell                                  |  5/12/11  |
+|  73         |  Newsweek/Daily Beast Company          |  5/19/11  |
+|  74         |  WordStream                            |  5/19/11  |
+|  75         |  Flagbit                               |  6/14/11  |
+|  76         |  Applications Online                   |  6/17/11  |
+|  77         |  Versapay                              |  7/5/11   |
+|  78         |  DigiTar                               |  7/19/11  |
+|  79         |  DreamHost                             |  7/21/11  |
+|  80         |  Edmunds.com                           |  7/22/11  |
+|  81         |  Every Ware                            |  7/25/11  |
+|  82         |  Ask.com                               |  8/1/11   |
+|  83         |  bring.out doo Sarajevo                |  8/11/11  |
+|  84         |  Kos Media                             |  8/15/11  |
+|  85         |  reallyenglish.com                     |  8/15/11  |
+|  86         |  Fewbytes                              |  8/18/11  |
+|  87         |  Business Intelligence Associates      |  8/19/11  |
+|  88         |  Tacit Knowledge                       |  8/22/11  |
+|  89         |  Zenexity                              |  8/30/11  |
+|  90         |  ClassDo                               |  8/30/11  |
+|  91         |  Myplanet                              |  9/2/11   |
+|  92         |  ihiji                                 |  9/16/11  |
+|  93         |  "Port 80 Productions, LLC"            |  10/28/11 |
+|  94         |  Green Alto                            |  11/2/11  |
+|  95         |  "Heavy Water Software, Inc."          |  11/4/11  |
+|  96         |  Wealthfront Inc.                      |  11/15/11 |
+|  97         |  "Kickstarter, Inc."                   |  11/18/11 |
+|  98         |  Webtrends Inc                         |  11/22/11 |
+|  99         |  "Infochimps, Inc."                    |  11/28/11 |
+|  100        |  "Cycle Computing, LLC"                |  11/29/11 |
+|  101        |  "Ubalo, Inc"                          |  12/8/11  |
+|  102        |  "SweetSpot Diabetes Care, Inc."       |  12/12/11 |
+|  103        |  "RideCharge, Inc."                    |  12/15/11 |
+|  104        |  "Riot Games, Inc."                    |  12/15/11 |
+|  105        |  Fiksu                                 |  12/21/11 |
+|  106        |  WhitePages Inc.                       |  1/3/12   |
+|  107        |  "CX, Inc."                            |  1/12/12  |
+|  108        |  Spoke Software                        |  1/15/12  |
+|  109        |  Xforty Technologies                   |  1/25/12  |
+|  110        |  "Democracy Works, Inc"                |  1/30/12  |
+|  111        |  "Pure Lake Software, Inc."            |  2/10/12  |
+|  112        |  Sveriges Television AB                |  2/14/12  |
+|  113        |  Reaktor Innovations                   |  2/14/12  |
+|  114        |  "Oxygen Cloud, Inc."                  |  2/14/12  |
+|  115        |  Robojar Pty Ltd                       |  2/17/12  |
+|  116        |  Green and Secure IT Limited           |  2/19/12  |
+|  117        |  ModCloth                              |  2/23/12  |
+|  118        |  Joyent                                |  2/29/12  |
+|  119        |  "Wallrazor, Inc."                     |  3/4/12   |
+|  120        |  "Cerner Innovation, Inc."             |  3/8/12   |
+|  121        |  "Numenta, Inc."                       |  3/27/12  |
+|  122        |  Kotiri Software Ltd.                  |  4/3/12   |
+|  123        |  "The Frontside Software, Inc."        |  4/5/12   |
+|  124        |  "Needle, Inc."                        |  4/5/12   |
+|  125        |  "Gap, Inc."                           |  4/10/12  |
+|  126        |  Youscribe                             |  4/11/12  |
+|  127        |  Deutsche Telekom Laboratories         |  4/17/12  |
+|  128        |  "Relevance, Inc."                     |  4/20/12  |
+|  129        |  Truer Sound LLC                       |  4/20/12  |
+|  130        |  Websym Technologies Private Ltd.      |  4/30/12  |
+|  131        |  DreamBox Learning Inc                 |  5/3/12   |
+|  132        |  Simple                                |  5/7/12   |
+|  133        |  "Consumer Club, Inc"                  |  5/10/12  |
+|  134        |  Onddo Labs                            |  5/18/12  |
+|  135        |  CyberAgent Corp.                      |  5/22/12  |
+|  136        |  SourceIndex IT-Services               |  6/7/12   |
+|  137        |  "Scribd, Inc."                        |  6/15/12  |
+|  138        |  Civolution BV                         |  6/18/12  |
+|  139        |  Drillinginfo                          |  6/18/12  |
+|  140        |  NaviNet                               |  6/20/12  |
+|  141        |  "Voxel Dot Net, Inc"                  |  6/26/12  |
+|  142        |  Asbury Theological Seminary           |  6/27/12  |
+|  143        |  The Cloudscaling Group                |  6/27/12  |
+|  144        |  "Creationline, Inc."                  |  6/27/12  |
+|  145        |  "Action Verb, LLC"                    |  7/10/12  |
+|  146        |  Iugu Servicos na Internet LTDA        |  7/11/12  |
+|  147        |  OpeniT                                |  7/18/12  |
+|  148        |  Cloudreach Limited                    |  7/24/12  |
+|  149        |  Bonnier Corporation                   |  7/25/12  |
+|  150        |  "OneHealth Solutions, Inc."           |  7/25/12  |
+|  151        |  Hewlett-Packard                       |  7/26/12  |
+|  152        |  Paydici Corp.                         |  7/26/12  |
+|  153        |  "Novell, Inc."                        |  8/1/12   |
+|  154        |  Schuberg Phillis B.V.                 |  8/3/12   |
+|  155        |  RelatelIQ Inc.                        |  8/3/12   |
+|  156        |  HomeMade Digital Ltd                  |  8/7/12   |
+|  157        |  "PrimeRevenue, Inc"                   |  8/10/12  |
+|  158        |  Calxeda                               |  8/14/12  |
+|  159        |  Big Cartel LLC                        |  8/17/12  |
+|  160        |  Atlassian                             |  8/27/12  |
+|  161        |  One Connect Limited                   |  9/7/12   |
+|  162        |  Sonian Inc                            |  9/8/12   |
+|  163        |  The App Business                      |  9/19/12  |
+|  164        |  "Pat Deegan, PhD & Associates, LLC"   |  9/26/12  |
+|  165        |  OmniTI                                |  9/26/12  |
+|  166        |  "Cloudant, Inc."                      |  10/5/12  |
+|  167        |  ZestFinance                           |  10/8/12  |
+|  168        |  Firebelly Design                      |  10/8/12  |
+|  169        |  Nu Echo                               |  10/16/12 |
+|  170        |  OpenConcept Consulting Inc.           |  10/18/12 |
+|  171        |  Apptentive                            |  10/20/12 |
+|  172        |  "Document Swarm, LLC"                 |  10/20/12 |
+|  173        |  "Tilting @, LLC"                      |  10/29/12 |
+|  174        |  "Sift Science, Inc"                   |  10/31/12 |
+|  175        |  FluxSauce                             |  11/1/12  |
+|  176        |  Rocket Internet GmbH                  |  11/2/12  |
+|  177        |  Coding-Knight LTD                     |  11/6/12  |
+|  178        |  Tapp                                  |  11/13/12 |
+|  179        |  Taqtiqa LLC                           |  11/14/12 |
+|  180        |  "Nordstrom, Inc"                      |  11/15/12 |
+|  181        |  Daptiv Solutions LLC                  |  11/26/12 |
+|  182        |  Lime Pepper Ltd                       |  11/28/12 |
+|  183        |  "Straydog Software, Inc."             |  11/29/12 |
+|  184        |  "Fidelity Technology Group, LLC"      |  12/6/12  |
+|  185        |  "Angelweb, Unipessoal Lda."           |  12/14/12 |
+|  186        |  bcs kommunikationslosungen            |  12/17/12 |
+|  187        |  "North County Tech Center, LLC"       |  12/22/12 |
+|  188        |  Emergent One                          |  1/9/13   |
+|  189        |  Ninefold Pty Limited                  |  1/9/13   |
+|  190        |  DecisionDesk                          |  1/13/13  |
+|  191        |  Belly Inc                             |  1/15/13  |
+|  192        |  cloudbau Gmbh                         |  1/18/13  |
+|  193        |  ActBlue Technical Services            |  1/18/13  |
+|  194        |  HiganWorks LLC                        |  1/22/13  |
+|  195        |  Ontario Systems                       |  1/23/13  |
+|  196        |  "Lytro, Inc."                         |  1/23/13  |
+|  197        |  Grupa Allegro Sp. z o.o.              |  1/31/13  |
+|  198        |  Workday Inc.                          |  2/5/13   |
+|  199        |  "Atlas Digital, LLC"                  |  2/6/13   |
+|  200        |  Intoximeters                          |  2/15/13  |
+|  201        |  Airbnb                                |  2/17/13  |
+|  202        |  Valtech AB                            |  2/20/13  |
+|  203        |  AWeber Communications                 |  2/25/13  |
+|  204        |  adesso mobile solutions GmbH          |  3/4/13   |
+|  205        |  "Banno, LLC"                          |  3/5/13   |
+|  206        |  AboutUs                               |  3/8/13   |
+|  207        |  "Google, Inc"                         |  3/14/13  |
+|  208        |  cloudControl GmbH                     |  3/21/13  |
+|  209        |  Springest                             |  3/25/13  |
+|  210        |  Criteo                                |  3/26/13  |
+|  211        |  "Thinking Phone Networks, Inc."       |  4/8/13   |
+|  212        |  Evolving Web Inc                      |  4/11/13  |
+|  213        |  BinaryBabel OSS                       |  4/17/13  |
+|  214        |  Tout Industries                       |  4/18/13  |
+|  215        |  "Lookout, Inc."                       |  4/22/13  |
+|  216        |  Recorded Future Inc                   |  4/23/13  |
+|  217        |  Irrational Industries                 |  5/1/13   |
+|  218        |  "Socrata, Inc"                        |  5/1/13   |
+|  219        |  "Aspera, Inc"                         |  5/1/13   |
+|  220        |  "Hadapt, Inc"                         |  5/3/13   |
+|  221        |  Moncai                                |  5/7/13   |
+|  222        |  IBM                                   |  5/14/13  |
+|  223        |  Yahoo Inc.                            |  5/14/13  |
+|  224        |  Texas A&M University College of Arch. |  5/20/13  |
+|  225        |  MoPub                                 |  5/21/13  |
+|  226        |  "Onelogin, Inc"                       |  5/24/13  |
+|  227        |  Yola                                  |  5/28/13  |
+|  228        |  CopperEgg                             |  5/28/13  |
+|  229        |  "MeetMe, Inc"                         |  5/30/13  |
+|  230        |  Boadree Innovations Kft.              |  6/17/13  |
+|  231        |  "Bitium, inc"                         |  6/21/13  |
+|  232        |  Heart of Sales LLC DBA Ace of Sales   |  7/4/13   |
+|  233        |  NetSrv Consulting Ltd                 |  7/7/13   |
+|  234        |  "AURIN Project"                       |  7/11/13  |
+|  235        |  Onlife Health Inc                     |  7/17/13  |
+|  236        |  Roblox Inc.                           |  7/17/13  |
+|  237        |  "Taos Mountain, Inc"                  |  7/24/13  |
+|  238        |  CoreMedia AG                          |  7/31/13  |
+|  239        |  "PROS, Inc. a Delaware Corporation"   |  8/14/13  |
+|  240        |  Identive Group                        |  8/21/13  |
+|  241        |  University of Derby                   |  8/22/13  |
+|  242        |  TeamSnap                              |  8/29/13  |
+|  243        |  Social Ally Pty Ltd                   |  8/29/13  |
+|  244        |  Ecodev Sarl                           |  9/9/13   |
+|  245        |  kreuzwerker GmbH                      |  9/18/13  |
+|  246        |  Central Desktop                       |  9/18/13  |
+|  247        |  Siili Solutions                       |  9/19/13  |
+|  248        |  Twiket LTD                            |  9/23/13  |
+|  249        |  Cloudsoft                             |  9/25/13  |
+|  250        |  MYOB NZ Limited                       |  9/26/13  |
+|  251        |  Mollie B.V.                           |  9/30/13  |
+|  252        |  Unbounce                              |  10/1/13  |
+|  253        |  Shutl Ltd.                            |  10/2/13  |
+|  254        |  Rapid7                                |  10/7/13  |
+|  255        |  "Our Film Festival, Inc (dba Fandor)" |  10/7/13  |
+|  256        |  "Ooyala, Inc."                        |  10/9/13  |
+|  257        |  Squaremouth Inc                       |  10/10/13 |
+|  258        |  Optiflows                             |  10/11/13 |
+|  259        |  General Sensing LTD                   |  10/10/13 |
+|  260        |  Deployable LTD                        |  10/22/13 |
+|  261        |  Klarna                                |  10/23/13 |
+|  262        |  "Nike, Inc."                          |  10/25/13 |
+|  263        |  SoundCloud Ltd.                       |  11/5/13  |
+|  264        |  Project Florida                       |  11/5/13  |
+|  265        |  Intuit                                |  11/6/13  |
+|  266        |  ComputeNext                           |  11/6/13  |
+|  267        |  The Weather Companies                 |  11/8/13  |
+|  268        |  PTC Inc                               |  11/13/13 |
+|  269        |  RamTank Inc                           |  11/19/13 |
+|  270        |  GoCardless                            |  11/24/13 |
+|  271        |  ZANOX AG                              |  11/30/13 |
+|  272        |  ARINC                                 |  12/3/13  |
+|  273        |  Lockheed Martin Corporation           |  12/3/13  |
+|  274        |  Brightcove                            |  12/16/13 |
+|  275        |  "Sprint.ly, Inc"                      |  12/27/13 |
+|  276        |  Cramer Development                    |  1/10/14  |
+|  277        |  "BlackBerry, Inc."                    |  1/20/14  |
+|  278        |  Cerner Innovation Inc                 |  2/6/14   |
+|  279        |  Cerner Innovation Inc                 |  2/11/14  |
+|  280        |  Engine Yard                           |  2/12/14  |
+|  281        |  Crux Hosted Services                  |  2/18/14  |
+|  282        |  Blue Spurs                            |  2/24/14  |
+|  283        |  GitLab.com                            |  3/1/14   |
+|  284        |  Yelp                                  |  3/7/14   |
+|  285        |  Workday                               |  3/10/14  |
+|  286        |  BMC Software Inc                      |  3/13/14  |
+|  287        |  Itison                                |  3/14/14  |
+|  288        |  "OnBeep, Inc."                        |  3/19/14  |
+|  289        |  Level 11 Consulting                   |  3/19/14  |
+|  290        |  Linaro Limited                        |  4/4/14   |
+|  291        |  Spanlink Communications               |  4/17/14  |
+|  292        |  "WESEEK, Inc"                         |  4/29/14  |
+|  293        |  "Iniqa UK, Ltd"                       |  6/4/14   | 
+|  294        |  Jemstep                               |  6/13/1   |
+
+
+
+
+Allowed Contributors
+
+The list of allowed contributors to Opscode projects. Persons listed as associated with a company may also be individual contributors as well.
+
+To get on the list, check out our instructions on how to contribute.
+
+1.  Adam Jacob 	 Opscode 	
+1.  Andy Delcambre 	 Engineyard 	1/7/09
+1.  Arjuna Christensen 	 	1/7/09
+1.  Artur Bergman 	 Wikia 	
+1.  Benjamin Black 	 Opscode 	1/10/09 	
+1.  Bryan McLellan 	 	1/7/09 	
+1.  Dan Walters 	 	3/7/09
+1.  Edward Muller 	 Engineyard 	1/28/09
+1.  Ezra Zygmuntowicz 	 Engineyard 	1/7/09
+1.  Jason Cook 	 Wikia 	
+1.  Joe Williams 	 	1/17/09
+1.  Kris Rasmussen 	 Aptana 	2/12/09
+1.  Lee Jensen 	 Engineyard 	1/24/09
+1.  Nick Sullivan 	 Wikia 	
+1.  Paul Nasrat 	 	1/19/09
+1.  Pawel Rein 	 Wikia 	
+1.  Przemek Malkowski 	 Wikia 	
+1.  Sean Cribbs 	 	2/5/09
+1.  Steve Berryman 	 	1/20/09
+1.  Steven Parkes 	 Aptana 	2/12/09
+1.  Thom May 	 	1/21/09
+1.  Tim Dysinger 	 	1/28/09
+1.  Michael Hale 	 	2/16/09
+1.  Mathieu Sauve-Frankel 	 	2/22/09
+1.  Matthew Landauer 	 	2/25/09
+1.  John Hampton 	 CleanOffer 	3/2/09
+1.  Nadeem Bitar 	 CleanOffer 	3/2/09
+1.  James Gartrell 	 	2/6/09
+1.  Joshua Sierles 	 37signals 	3/4/09
+1.  Mark Imbriaco 	 37signals 	3/4/09
+1.  Stephen Haynes 	 Nomitor 	3/9/09
+1.  Yun Huang Yong 	 Nomitor 	3/9/09
+1.  David Lee 	 	3/9/09
+1.  Matthew Kent 	 	3/24/09
+1.  Dave Myron 	 	4/3/09
+1.  Miguel Cabeça 	 	8/4/09
+1.  Jason Jackson 	 	4/9/09
+1.  Caleb Tennis 	 	4/10/09
+1.  Michael Lim 	 	4/14/09
+1.  David Balatero 	 	4/28/09
+1.  David Grandinetti 	 We Go To 12 	4/30/09
+1.  Lachlan Cox 	 Plus2 Pty 	5/8/09
+1.  Scott Likens 	 	4/30/09
+1.  Andrew Willis 	 	5/25/09
+1.  Hongli Lai 	 Phusion 	6/22/09
+1.  Ninh Bui 	 Phusion 	6/22/09
+1.  Edmund Haselwanter	cloudbau Gmbh	6/25/09
+1.  Raphael Simon 	 RightScale 	6/30/09
+1.  Tony Spataro 	 RightScale 	6/30/09
+1.  Stéphane Crivisier 	 	6/30/09
+1.  Matthew Todd 	 Highgroove Studios 	7/1/09
+1.  Grant Zanetti 	 	2/1/09
+1.  Peter Woodman 	 	6/22/09
+1.  Daniel DeLeo 	 	7/10/09
+1.  Jeppe Madsen 	 	9/13/09
+1.  Cary Penniman 	 RightScale 	7/20/09
+1.  J. Chris Anderson 	 	8/7/09
+1.  Graeme Mathieson 	 Rubaidh 	8/10/09
+1.  Mark Connell 	 Rubaidh 	8/10/09
+1.  Jonathan Weiss 	 Peritor GmbH 	8/12/09
+1.  Mathias Meyer 	 Peritor GmbH 	8/12/09
+1.  Pedro Belo 	 Heroku 	8/13/09
+1.  Ricardo Chimal Jr. 	 Heroku 	8/13/09
+1.  Adam Wiggins 	 Heroku 	8/13/09
+1.  Ryan Tomayko 	 Heroku 	8/13/09
+1.  Blake Mizerany 	 Heroku 	8/13/09
+1.  Diego Algorta 	 	
+1.  Kevin Hunt 	 	8/14/09 	
+1.  Sidney Burks 	 	8/20/09 	
+1.  Joe Van Dyk 	 	9/1/09 	
+1.  Sig Lange 	 	9/1/09 	
+1.  Alexander van Zoest 	 	9/1/09 	
+1.  Nathan Mueller 	 	9/7/09 	
+1.  Roman Heinrich 	 	9/11/09 	
+1.  Gábor Vészi 	 	9/20/09 	
+1.  Kenneth Kalmer 	 Internet Exchange 	9/22/09 	
+1.  Luca Greco 	 	9/22/09 	
+1.  Charles Cook 	 Betfair 	9/30/09 	
+1.  Mario Giammarco 	 	10/6/09 	
+1.  Matthew King 	 	10/14/09 	
+1.  James Golick 	 	10/27/09 	
+1.  Jörn Berrisch 	 	10/28/09 	
+1.  Peter Crossley 	 	10/30/09 	
+1.  Eric Hankins 	 Sojern 	11/2/09 	
+1.  David McRae 	 Sojern 	11/2/09 	
+1.  Dan Fitch 	 Sojern 	11/2/09 	
+1.  Ian Meyer 	 	11/8/09 	
+1.  John Alberts 	 	11/9/09 	
+1.  Lee Marlow 	 	11/11/09 	
+1.  Tollef Fog Heen 	 	11/12/09 	
+1.  Cuong Chi Nghiem 	 	11/13/09 	
+1.  Gordon Thiesfeld 	 	11/18/09 	
+1.  Dreamcat4 	 	11/21/09 	
+1.  Guy Bolton King 	 	12/3/09 	
+1.  Robert Berger 	 Runa 	12/20/09 	
+1.  Siva Jagadeesan 	 Runa 	12/20/09 	
+1.  Ivan Pirlik 	 	12/22/09 	
+1.  David Abdemoulaie 	 	12/23/09 	
+1.  Alex Soto 	 	12/29/09 	
+1.  Bryan Helmkamp 	 	12/30/09 	
+1.  Jesse Nelson 	 	1/6/10 	
+1.  Seth Chisamore 	 Opscode 	1/11/10 	
+1.  Alfredo Deza 	 MaxMedia 	1/11/10 	
+1.  N. Alan Johnson Jr. 	 	1/15/10 	
+1.  Pavel Valodzka 	 	2/8/10 	
+1.  Kyle Maxwell 	 Quantifind 	2/11/10 	
+1.  Doug MacEachern 	 VMware 	2/11/10 	
+1.  Jan Zimmek 	 	2/14/10 	
+1.  Dan Prince 	 Rackspace 	2/26/10 	
+1.  Gabe Westmaas 	 Rackspace 	2/26/10 	
+1.  Tim Harper 	 	3/8/10 	
+1.  Renaud Chaput 	 	3/10/10 	
+1.  Daniel Peterson 	 	3/11/10 	
+1.  Amit Cohen 	 Leaway Enterprise 	3/16/10 	
+1.  Avishai Ish-Shalom 	 Leaway Enterprise 	3/16/10 	
+1.  Or Cohen 	 Leaway Enterprise 	3/16/10 	
+1.  Jon Swope 	 	3/19/10 	
+1.  Jonathan Tron 	 	3/19/10 	
+1.  Christopher Peplin 	 Bueda 	3/30/10 	
+1.  Trotter Cashion 	 	4/3/10 	
+1.  Benjamin Standefer 	 	4/6/10 	
+1.  P. Barrett Little 	 	4/7/10 	
+1.  John Nixon 	 	4/13/10 	
+1.  Bruce Krysiak 	 	4/13/10 	
+1.  Akzhan Abdulin 	 	4/14/10 	
+1.  Grant Rodgers 	 	4/17/10 	
+1.  Wesley Beary 	 	4/22/10 	
+1.  Farzad Farid 	 	4/23/10 	
+1.  Olivier Raginel 	 	4/26/10 	
+1.  Jacques Crocker 	 	5/3/10 	
+1.  Pierre Baillet 	 	5/3/10 	
+1.  Joel Merrick 	 	5/3/10 	
+1.  James Sanders 	 	5/3/10 	
+1.  John Goulah 	 	5/3/10 	
+1.  Toomas Pelberg 	 	5/3/10 	
+1.  Ceaser Larry 	 Divergent Logic 	5/3/10 	
+1.  Justin Sheehy 	 Basho Technologies 	5/4/10 	
+1.  Andrew Gross 	 Basho Technologies 	5/4/10 	
+1.  Bryan Fink 	 Basho Technologies 	5/4/10 	
+1.  Ben Mabey 	 	5/5/10 	
+1.  Christopher Durtschi 	 Divergent Logic 	5/7/10 	
+1.  Kevin Carter 	 Divergent Logic 	5/7/10 	
+1.  Saimon Moore 	 	5/13/10 	
+1.  Troy Davis 	 Seven Scale 	5/13/10 	 	
+1.  Eric Lindvall 	 Seven Scale 	5/13/10 	
+1.  Alexey Ivanov		5/14/10 	
+1.  Pritesh Mehta 	 	5/19/10 	
+1.  Ondrej Kudlik 	 IglooNET 	5/21/10 	
+1.  Marek Hulan 	 IglooNET 	5/21/10 	
+1.  Chad Woolley 	 	5/22/10 	
+1.  Jochen Lillich 	 Freistil Consulting 	5/25/10 	
+1.  Marius Ducea 	 Promet Solutions 	5/25/10 	
+1.  Eric Butler 	 	5/26/10 	
+1.  Sahil Cooner 	 	6/6/10 	
+1.  Richard Nicholas 	 Betfair 	6/9/10 	
+1.  Dan Slimmon 	 	6/10/10 	
+1.  Craig Webster 	 Picklive 	6/16/10 	
+1.  Dean Strelau 	 Mint Digital 	6/17/10 	
+1.  Kurt Yoder 	 	6/25/10 	
+1.  Jim Browne 	 42 Lines 	6/27/10 	
+1.  Andrey Sibiryov 	 	7/7/10 	
+1.  Anthony Newman 	 Betfair 	7/8/10 	
+1.  Thomas Hoover 	 	7/8/10 	
+1.  Dylan Egan 	 Wildfire Interactive 	7/9/10 	
+1.  Michael Carruthers 	 Wildfire Interactive 	7/11/10 	
+1.  Jon Seaberg 	 RightScale 	7/20/10 	
+1.  Sean O'Meara 	 	7/20/10 	
+1.  Cory von Wallenstein 	 Dynamic Network Services 	7/21/10 	
+1.  Michael Leinartas 	 	7/22/10 	
+1.  Thomas Bishop 	 	7/23/10 	
+1.  Jon Wood 	 	7/29/10 	
+1.  Dmitry Vyal 	 	8/4/10 	
+1.  Gilles Devaux 	 PeerPong 	8/4/10 	
+1.  Chris Pepper 	 	8/5/10 	
+1.  Dennis Klein 	 	8/6/10 	
+1.  Warwick Poole 	 	8/12/10 	
+1.  Ken Ming Ong 	 	8/15/10 	
+1.  Ash Berlin 	 	8/16/10 	
+1.  Jochen Tuchbreiter 	 domainfactory GmbH 	8/16/10 	
+1.  Mat Ellis 	 Tecnh 	8/17/10 	
+1.  Michael MacDonald 	 	8/17/10 	
+1.  Jorge Luiz deBrito Falcão 	 	8/18/10 	
+1.  Jamie Winsor 	 	8/19/10 	
+1.  Darrin Eden 	 	8/19/10 	
+1.  Jonathan Smith 	 	8/19/10 	
+1.  Andrew Fulcher 	 	8/23/10 	
+1.  Matthias Marschall 	 	8/25/10 	
+1.  Peter Struijk 	 	8/25/10 	
+1.  Robert Anthony Postill 	 	8/28/10 	
+1.  Joshua Timberman 	 Opscode 	9/6/10 	
+1.  Benjamin Rockwood 	 	9/6/10 	
+1.  Douglas Knight 	 	9/9/10 	
+1.  Andrew Cole 	 9Summer 	9/9/10 	
+1.  Dimitri Krassovski 	 Wixpress 	9/13/10 	
+1.  Gregory Man 	 Wixpress 	9/13/10 	
+1.  Allan Feid 	 	9/17/10 	
+1.  Ringo De Smet 	 	9/26/10 	
+1.  Tomasz Napierala 	 	9/27/10 	
+1.  Jesse Proudman 	 Blue Box Group 	9/29/10 	
+1.  Ian Parades 	 Blue Box Group 	9/29/10 	
+1.  Lee Huffman 	 Blue Box Group 	9/29/10 	
+1.  Christopher Horton 	 	10/1/10 	
+1.  Jude Sutton 	 FindsYou Limited 	10/6/10 	
+1.  James Le Cuirot 	 FindsYou Limited 	10/6/10 	
+1.  Richard Pelavin 	 	10/7/10 	
+1.  Blake Irvin 	ModCloth	10/8/10 	
+1.  Jim Van Fleet 	 	10/14/10 	
+1.  Laurent Désarmes 	 	10/14/10 	
+1.  Jay T. McCanta 	 	10/15/10 	
+1.  Eric G. Wolfe 	 	10/20/10 	
+1.  Sami Haahtinen 	 	10/21/10 	
+1.  Chris Kelly 	 Highgroove Studios 	10/25/10 	
+1.  Gerald L. Hevener Jr. 	 	10/25/10 	
+1.  Charles Quinn 	 Highgroove Studios 	10/25/10 	
+1.  Jonathan Wallace 	 Highgroove Studios 	10/25/10 	
+1.  Jason Ardell 	 	10/26/10 	
+1.  Sean Carey 	 	10/27/10 	
+1.  Pierre-Luc Brunet 	 ZeStuff 	10/28/10 	
+1.  Sean Walbran 	 	10/28/10 	
+1.  Brian McKelvey 	 Worlize 	10/28/10 	
+1.  Jeffrey Hulten 	 Automated Labs 	11/3/10 	
+1.  Doug Cole 	 Estately 	11/4/10 	
+1.  Ben Bleything 	 Estately 	11/4/10 	
+1.  Sebastian Boehm 	 	11/6/10 	
+1.  Ches Martin 	 	11/8/10 	
+1.  Eric C. Herot 	 	11/8/10 	
+1.  Oliver Hankeln 	 	11/10/10 	
+1.  David Nolan 	 Kapoq 	11/10/10 	
+1.  Frank Louwers 	 Openminds 	11/10/10 	
+1.  Bernard Grymonpon 	 Openminds 	11/10/10 	
+1.  Bram Gillemon 	 Openminds 	11/10/10 	
+1.  Paul Cortens 	 MobileCause 	11/10/10 	
+1.  Austin Schneider 	 MobileCause 	11/10/10 	
+1.  Kevin Ahrens 	 	11/13/10 	
+1.  Stephen Nelson-Smith 	 Atalanta Systems 	11/14/10 	
+1.  Caleb Groom 	 	11/16/10 	
+1.  Michael Ivey 		11/17/10 	
+1.  Wojciech Wnetrzak 	 	11/20/10 	
+1.  Dmitriy Tkachenko 	 	11/22/10 	
+1.  Filip Tepper 	 	11/24/10 	
+1.  Denis Barushev 	 	11/27/10 	
+1.  Pedro F. <<pancho>> Horrillo Guerra	 	11/28/10 	
+1.  James Harton 	 Sociable Limited 	12/1/10 	
+1.  Noah Kantrowitz 	 	12/4/10 	
+1.  Anthony Burton 	 	12/4/10 	
+1.  David Esposito 	 Nine Summer 	12/6/10 	
+1.  Mike Lecza 	 Nine Summer 	12/6/10 	
+1.  Andrew Cole 	 Nine Summer 	12/6/10 	
+1.  Michael Winser 	 Nine Summer 	12/6/10 	
+1.  Cory Burke 	 Nine Summer 	12/6/10 	
+1.  Charles Duffy 	 Tippr 	12/7/10 	
+1.  John Vincent 	 	12/10/10 	
+1.  Dustin Currie 	 	12/14/10 	
+1.  Mark Sonnabaum 	 	12/14/10 	
+1.  Elliot Murphy 	 	12/22/10 	
+1.  Laradji Nacer 	 	12/30/10 	
+1.  Todd Nine 	 	1/3/11 	
+1.  Elijah Wright 	 	1/5/11 	
+1.  Anshul Khandelwal 	 	1/13/11 	
+1.  Michael Carruthers 	 	1/16/11 	
+1.  Vishvananda Ishaya 	 	1/17/11 	
+1.  Scott Frazer 	 	1/17/11 	
+1.  Eric Hodel 	 	1/21/11 	
+1.  Eric Heydrick 	 	1/25/11 	
+1.  Andreas Kollegger 	 Neo Technology 	1/27/11 	
+1.  Steve Lum 	 	1/31/11 	
+1.  Anthony Goddard 	 	2/1/11 	
+1.  Roland Moriz 	 Moriz GmbH 	2/2/11 	
+1.  Emil Sit 	 Hadapt 	2/2/11 	
+1.  Ranjib Dey 	 	2/3/11 	
+1.  Ryan Davis 	 	2/8/11 	
+1.  Eric Coleman 	 	2/8/11 	
+1.  James Casey 	 	2/9/11 	
+1.  Maciej Pasternacki 	 	2/9/11 	
+1.  Grzegorz Marszalek 	 	2/11/11 	
+1.  James Sulinski 	 AegisCo 	2/14/11 	
+1.  Erik Sabowski 	 AegisCo 	2/14/11 	
+1.  Maciej Pasternacki 	 SetJam 	2/15/11 	
+1.  Steven Dossett 	 Ning 	2/17/11 	
+1.  Dane Knecht 	 Tippr 	2/18/11 	
+1.  Mark Imbriaco 	 Heroku 	2/28/11 	
+1.  Jonathan Matthews	7digital	3/3/11 	
+1.  Patrick Collins 	 	3/7/11 	
+1.  Jim Hopp 	 Workday 	3/12/11 	
+1.  Ken Dove 	 Workday 	3/12/11 	
+1.  Philip Reynolds 	 Workday 	3/12/11 	
+1.  Victor Zakharyev 	 Workday 	3/12/11 	
+1.  Greg Fuller 	 Workday 	3/12/11 	
+1.  Michael Callahan 	 Workday 	3/15/11 	
+1.  Don Norton 	 Workday 	3/15/11 	
+1.  Joe Nuspl 	 Workday 	3/15/11 	
+1.  Dan Thom 	 Workday 	3/15/11 	
+1.  Rick Cooper 	 Workday 	3/15/11 	
+1.  Patrick Debois 	 	3/14/11 	
+1.  Michael Guterl 	 	3/15/11 	
+1.  Andrew Miklas 	 PagerDuty 	3/17/11 	
+1.  Tristan Sloughter 	 	3/22/11 	
+1.  Jonathon Ramsey 	 	3/23/11 	
+1.  Jesai Langenbach 	 	3/24/11 	
+1.  Maciej Pasternacki 	 Gnowsis 	3/25/11 	
+1.  Omri Cohen 	 	3/28/11 	
+1.  Joseph Sokol-Margolis 	 	3/31/11 	
+1.  Alex Tomlins 	 Unboxed Consulting 	4/1/11 	
+1.  Holger Just 	 	4/5/11 	
+1.  Jake Vanderdray 	 CustomInk 	4/8/11 	
+1.  Nathen Harvey 	 CustomInk 	4/8/11 	
+1.  Padraig O'Sullivan 	 	4/8/11 	
+1.  Christian Trabold 	 	4/16/11 	
+1.  KC Braunschweig 	Edmunds.com	4/19/11 	
+1.  Josh Pasqualetto 	 	4/21/11 	
+1.  Christopher C. Johnson 	 	4/21/11 	
+1.  Christian Paredes 	 	4/22/11 	
+1.  Viral Shah 	 	4/24/11 	
+1.  Bradley Fritz 	 	4/24/11 	
+1.  Nat Lownes 	 	4/25/11 	
+1.  Jonathan Tron 	 TalentBox 	4/25/11 	
+1.  Joseph Halter 	 TalentBox 	4/25/11 	
+1.  Wilson Felipe Nunes Fernandes Pereira		4/27/11 	
+1.  Michael Grubb		4/27/11 	
+1.  Brandon Konkle		4/28/11 	
+1.  Matt Griffin		4/28/11 	
+1.  Anh K. Huynh		4/28/11 	
+1.  Erik Frey	Wavii	4/29/11 	
+1.  Spike Gronim	Wavii	4/29/11 	
+1.  Ian MacLeod	Wavii	4/29/11 	
+1.  Guido Bartolucci	Wavii	4/29/11 	
+1.  Fletcher Nichol		5/3/11 	
+1.  James Kane	7digital	5/4/11 	
+1.  Paul Richards	7digital	5/4/11 	
+1.  Alexis Le-Quoc	Datadog	5/4/11 	
+1.  Matthew Singleton	Datadog	5/4/11 	
+1.  Carlo Cabanilla	Datadog	5/4/11 	
+1.  Olivier Pomel	Datadog	5/4/11 	
+1.  Fabrice Ollivier	Datadog	5/4/11 	
+1.  Matt Griffin	Viximo	5/10/11 	
+1.  Chris Chiodo	Viximo	5/10/11 	
+1.  Adam Bell	Viximo	5/10/11 	
+1.  Sergio Rubio		5/10/11 	
+1.  Elmer Rivera		5/10/11 	
+1.  Andrea Campi	ZephirWorks	5/11/11 	
+1.  Andrea Carlo Granata	ZephirWorks	5/11/11 	
+1.  Marco Pierleoni	ZephirWorks	5/11/11 	
+1.  Pietro Giorgianni	ZephirWorks	5/11/11 	
+1.  Jesse Newland		5/11/11 	
+1.  Greg Swallow		5/12/11 	
+1.  Scott Jensen	Dell	5/12/11 	
+1.  Greg Althaus	Dell	5/12/11 	
+1.  Andi Abes	Dell	5/12/11 	
+1.  Rob Hirschfeld	Dell	5/12/11 	
+1.  Paul Webster	Dell	5/12/11 	
+1.  Mitchell Hashimoto		5/12/11 	
+1.  Jamie van Dyke		5/17/11 	
+1.  Vladimir Kozhukalov		5/18/11 	
+1.  Nathan Butler	Newsweek/Daily Beast Company	5/19/11 	
+1.  Ken Garland	Newsweek/Daily Beast Company	5/19/11 	
+1.  Michael Yankovski	WordStream	5/19/11 	
+1.  Augusto Becciu		5/19/11 	
+1.  Greg Albrecht		5/19/11 	
+1.  Eric James Buth		5/24/11 	
+1.  Dan Porter		5/24/11 	
+1.  Adrian Silva	Atalanta Systems	5/25/11 	
+1.  Spike Morelli	Atalanta Systems	5/25/11 	
+1.  Paul Nicholson		5/27/11 	
+1.  Mandi Walls		5/27/11 	
+1.  Carl Perry	DreamHost	5/29/11 	
+1.  Greg Thornton		5/30/11 	
+1.  Joseph Heck		6/1/11 	
+1.  Charles Ray Johnson, Jr.		6/2/11 	
+1.  Joseph Anthony Pasquale Holsten		6/5/11 	
+1.  John Donagher		6/6/11 	
+1.  David Fuhr	Flagbit 	6/14/11 	
+1.  Jörg Weller	Flagbit	6/14/11 	
+1.  Marcel Cary		6/15/11 	
+1.  Yedidya "Jay" Feldblum	Applications Online	6/17/11 	
+1.  Michael Contento		6/20/11 	
+1.  Yogesh Pathade		6/22/11 	
+1.  Gavin Sandie		6/25/11 	
+1.  Bryan Horstmann-Allen		6/28/11 	
+1.  Glenn Pratt		7/5/11 	
+1.  Andrew Narkewicz	Versapay	7/5/11 	
+1.  Zachary Tomas Stevens		7/11/11 	
+1.  Richard Gould		7/11/11 	
+1.  Philip Cohen		7/15/11 	
+1.  Christopher Michael McClimans		7/18/11 	
+1.  Jason J.W. Williams		7/19/11 	
+1.  Nuo Yan		7/21/11 	
+1.  Jaroslaw Śmiejczak		7/25/11 	
+1.  Dimitri Aivaliotis	Every Ware	7/25/11 	
+1.  Eric Rochester		7/27/11 	
+1.  Alex North-Keys	Tippr	7/29/11 	
+1.  Adam Knight	Tippr	7/29/11 	
+1.  Eugene Wood	Ask.com	8/1/11 	
+1.  Aron Bartling	Ask.com	8/1/11 	
+1.  Jack Francis	Ask.com	8/1/11 	
+1.  Richard Marshall	Ask.com	8/1/11 	
+1.  Mikola Kucharski	Ask.com	8/1/11 	
+1.  Rory Mitchell	Ask.com	8/3/11 	
+1.  Oskar Stolc	Ask.com	8/3/11 	
+1.  Jack (John) Roehrig	Ask.com	8/3/11 	
+1.  Paul Stahlke	Ask.com	8/3/11 	
+1.  Jorge Mazzei	Ask.com	8/3/11 	
+1.  Pakojo Samm	Ask.com	8/3/11 	
+1.  David Smith	Ask.com	8/3/11 	
+1.  Mike Adolphs		8/5/11 	
+1.  Ernad Husremović	bring.out doo Sarajevo	8/11/11 	
+1.  Jasmin Beganović	bring.out doo Sarajevo	8/11/11 	
+1.  Saša Vranić	bring.out doo Sarajevo	8/11/11 	
+1.  Šator Emir	bring.out doo Sarajevo	8/11/11 	
+1.  Jeremy Bingham	Kos Media	8/15/11 	
+1.  Michael Taras	Kos Media	8/15/11 	
+1.  Tomoyuki Sakurai	reallyenglish.com	8/15/11 	
+1.  Mitsuru Yoshida	reallyenglish.com	8/15/11 	
+1.  Avishai Ish-Shalom	Fewbytes	8/18/11 	
+1.  Or Cohen	Fewbytes	8/18/11 	
+1.  Domenico Delle Side		8/19/11 	
+1.  Paul Morton	Business Intelligence Associates	8/19/11 	
+1.  Phil Austin	Business Intelligence Associates	8/19/11 	
+1.  Andrian Jardan		8/22/11 	
+1.  Vladimir Girnet	Tacit Knowledge	8/22/11 	
+1.  Scott Askew	Tacit Knowledge	8/22/11 	
+1.  Emmett Finneran		8/26/11 	
+1.  Arthur Gautier	Zenexity	8/30/11 	
+1.  Edward Middleton	ClassDo	8/30/11 	
+1.  Michael Pearson		8/31/11 	
+1.  Nikolay Sturm		9/1/11 	
+1.  Nathan Lloyd Smith		9/1/11 	
+1.  Patrick Connolly	Myplanet	9/2/11 	
+1.  Yashar Rassoulli	Myplanet	9/2/11 	
+1.  James Walker	Myplanet	9/2/11 	
+1.  Chris Read		9/6/11 	
+1.  Prashant Srivastava		9/7/11 	
+1.  Brad Knowles	ihiji	9/16/11 	
+1.  Stuart Rench	ihiji	9/16/11 	
+1.  Michael Maniscalco	ihiji	9/16/11 	
+1.  Brian Cunnie		9/19/11 	
+1.  Joseph F. Reynolds		9/20/11 	
+1.  Gabriel McArthur		9/21/11 	
+1.  David Keith Hudgins		9/21/11 	
+1.  Paul MacDougall		9/23/11 	
+1.  Bulat Shakirzyanov		9/23/11 	
+1.  Jorge Eduardo Espada		9/28/11 	
+1.  Eric Dennis		9/28/11 	
+1.  Stuart Glenn		9/29/11 	
+1.  Bryan Wilson Berry		10/4/11 	
+1.  Christopher Sturm		10/5/11 	
+1.  John Sumsion		10/12/11 	
+1.  Steven Phung		10/13/11 	
+1.  Claudio Cesar Sanchez Tejeda		10/14/11 	
+1.  Igor Afonov		10/26/11 	
+1.  Dan Buettner	Port 80 Production, LLC	10/28/11 	
+1.  Robby Grossman		10/31/11 	
+1.  Alan Harper		11/1/11 	
+1.  Juanje Ojeda		11/1/11 	
+1.  Stephane Jourdan	Green Alto	11/2/11 	
+1.  Gregory Karekinian	Green Alto	11/2/11 	
+1.  Samuel Maftoul	Green Alto	11/2/11 	
+1.  Darrin Eden	Heavy Water Software, Inc.	11/4/11 	
+1.  Sean Escriva	Heavy Water Software, Inc.	11/4/11 	
+1.  Jake Davis	Heavy Water Software, Inc.	11/4/11 	
+1.  AJ Christensen	Heavy Water Software, Inc.	11/4/11 	
+1.  Michael Weinberg	Heavy Water Software, Inc.	11/4/11 	
+1.  Aaron Baer	Heavy Water Software, Inc.	11/4/11 	
+1.  Matthew Kanwisher		11/8/11 	
+1.  Joshua McKenty		11/9/11 	
+1.  Iulian-Corneliu Costan		11/11/11 	
+1.  Daniel Oliver		11/14/11 	
+1.  Adam Garside		11/15/11 	
+1.  Ian Wolfcat Atha	Wealthfront Inc.	11/15/11 	
+1.  John Hitchings	Wealthfront Inc.	11/15/11 	
+1.  David Fortunato	Wealthfront Inc.	11/15/11 	
+1.  Julien Wetterwald	Wealthfront Inc.	11/15/11 	
+1.  Kevin Peterson	Wealthfront Inc.	11/15/11 	
+1.  Maksim Horbul		11/16/11 	
+1.  Roberto Gaiser		11/16/11 	
+1.  Robert Di Marco		11/17/11 	
+1.  Victor Lowther	Dell	11/17/11 	
+1.  Jerry Chen		11/18/11 	
+1.  Murali Raju		11/18/11 	
+1.  Benjamin Smith		11/18/11 	
+1.  Aaron Suggs	Kickstarter, Inc.	11/18/11 	
+1.  Lance Ivy	Kickstarter, Inc.	11/18/11 	
+1.  Cedric Howe	Kickstarter, Inc.	11/18/11 	
+1.  Tieg Zaharia	Kickstarter, Inc.	11/18/11 	
+1.  Teemu Matilainen	Reaktor Innovations	11/22/11 	
+1.  Dave Solbes	Webtrends Inc	11/22/11 	
+1.  Grant Hutchins		11/25/11 	
+1.  Eric Saxby	ModCloth	11/27/11 	
+1.  Gabriel Evans		11/27/11 	
+1.  Tim Smith	Webtrends Inc	11/28/11 	
+1.  Nathaniel Eliot	Infochimps, Inc	11/28/11 	
+1.  Adam Seever	Infochimps, Inc	11/28/11 	
+1.  Travis Dempsey	Infochimps, Inc	11/28/11 	
+1.  Dhruv Bansal	Infochimps, Inc	11/28/11 	
+1.  Andrew Kaczorek	Cycle Computing, LLC	11/29/11 	
+1.  Chris Chalfant	Cycle Computing, LLC	11/29/11 	
+1.  Dan Harris	Cycle Computing, LLC	11/29/11 	
+1.  Ian Alderman	Cycle Computing, LLC	11/29/11 	
+1.  Stephen Balukoff		11/30/11 	
+1.  Kendrick Martin	Webtrends Inc	12/1/11 	
+1.  Adnan Wahab		12/3/11 	
+1.  Alex Howells		12/4/11 	
+1.  Cameron Johnston	Needle, Inc.	12/5/11 	
+1.  Justin Huff		12/8/11 	
+1.  Ian Downes	Ubalo, Inc	12/8/11 	
+1.  Erik Hollensbe		12/9/11 	
+1.  Karel Minarik		12/11/11 	
+1.  Adam Greene	SweetSpot Diabetes Care, Inc.	12/12/11 	
+1.  Justin Schumacher	SweetSpot Diabetes Care, Inc.	12/12/11 	
+1.  Dan Root	SweetSpot Diabetes Care, Inc.	12/12/11 	
+1.  Paul Dowman		12/12/11 	
+1.  Andrew Le		12/12/11 	
+1.  Paul Welch		12/13/11 	
+1.  Harlan Barnes		12/13/11 	
+1.  Philip Kates	Rackspace US, Inc	12/13/11 	
+1.  Brandon Philips	Rackspace US, Inc	12/13/11 	
+1.  Paul Querna	Rackspace US, Inc	12/13/11 	
+1.  Arthur Pirogovski		12/13/11 	
+1.  John Scott Sanders, Jr	RideCharge, Inc	12/15/11 	
+1.  Jamie Winsor	Riot Games	12/15/11 	
+1.  Josiah Kiehl	Riot Games	12/15/11 	
+1.  Jesse Howarth	Riot Games	12/15/11 	
+1.  Michael Matsuuara	Riot Games	12/15/11 	
+1.  Cliff Dickerson	Riot Games	12/15/11 	
+1.  Philip Gollucci	RideCharge, Inc	12/15/11 	
+1.  Radim Marek		12/17/11 	
+1.  Hugo Fichter		12/19/11 	
+1.  Chris Christensen		12/20/11 	
+1.  Chet Luther		12/20/11 	
+1.  Mark Luntzel		12/20/11 	
+1.  Kevin Karwaski	Fiksu	12/21/11 	
+1.  David Calavera		12/22/11 	
+1.  Michael Stillwell		12/23/11 	
+1.  Aaron Bull Schaefer		12/28/11 	
+1.  Max Rabin		1/3/12 	
+1.  Michael Bradshaw	WhitePages Inc.	1/3/12 	
+1.  Michael Cook	WhitePages Inc.	1/3/12 	
+1.  Jack Foy	WhitePages Inc.	1/3/12 	
+1.  Devin Ben-Hur	WhitePages Inc.	1/3/12 	
+1.  Jeff Bellegarde	WhitePages Inc.	1/3/12 	
+1.  John Dyer		1/4/12 	
+1.  Sam Marx		1/5/12 	
+1.  Praveen Arimbrathodiyil		1/6/12 	
+1.  Joshua Buysse		1/6/12 	
+1.  Dale Hui		1/6/12 	
+1.  Jesse Campbell		1/8/12 	
+1.  Roberto Carlos Morano		1/9/12 	
+1.  Miah Johnson	Scribd, Inc. 	1/10/12 	
+1.  Ian Delahorne		1/12/12 	
+1.  Mike Javorski	Spoke Software	1/15/12 	
+1.  Michael A. Fiedler		1/16/12 	
+1.  Luis Bosque		1/16/12 	
+1.  Qiming He		1/18/12 	
+1.  Hector Castro		1/19/12 	
+1.  Wade Warren	Wikia	1/23/12 	
+1.  Geoff Papilion	Wikia	1/23/12 	
+1.  Justin Ryan	Wikia	1/23/12 	
+1.  David King	Xforty Technologies	1/25/12 	
+1.  Christian Pearce	Xforty Technologies	1/25/12 	
+1.  Andrew Libby	Xforty Technologies	1/25/12 	
+1.  Joshua Hou		1/27/12 	
+1.  Alice Kaerast		1/28/12 	
+1.  Brett Hoerner		1/28/12 	
+1.  Jon-Erik Schneiderhan		1/30/12 	
+1.  Wes Morgan	Democracy Works, Inc	1/30/12 	
+1.  Ernie Brodeur		1/31/12 	
+1.  Stephen Figgins		1/31/12 	
+1.  Tal Rotbart		2/1/12 	
+1.  Benjamin Lindsey		2/1/12 	
+1.  Markus Schirp		2/1/12 	
+1.  Tryn Mirell		2/2/12 	
+1.  Hari Krishna Dara		2/7/12 	
+1.  Andrew Grangaard		2/8/12 	
+1.  Adam Mielke		2/8/12 	
+1.  Andrew Allan		2/9/12 	
+1.  Antonio Soares de Azevedo Terceiro		2/9/12 	
+1.  Istvan Szukacs		2/9/12 	
+1.  Brian Parker	Pure Lake Software, Inc.	2/10/12 	
+1.  Sean Porter		2/10/12 	
+1.  William Carroll		2/12/12 	
+1.  Paul Diaconescu	Sveriges Television AB	2/14/12 	
+1.  Jonas Eklof	Sveriges Television AB	2/14/12 	
+1.  Per Bjorn	Sveriges Television AB	2/14/12 	
+1.  Frank Hoffsumer	Sveriges Television AB	2/14/12 	
+1.  Samppa Kytomaki	Reaktor Innovations	2/14/12 	
+1.  Zuhaib Siddique	Atlassian	2/14/12 	
+1.  Andrew Robson	Oxygen Cloud, Inc.	2/14/12 	
+1.  Aaron Follette	Oxygen Cloud, Inc.	2/14/12 	
+1.  Erik Bakker		2/16/12 	
+1.  David Golden		2/16/12 	
+1.  Jacques Chester	Robojar Pty Ltd	2/17/12 	
+1.  Nicholas VINOT		2/18/12 	
+1.  Matthew MacDonald-Wallace		2/19/12 	
+1.  Andrew Gross		2/20/12 	
+1.  Andrew Fecheyr Lippins		2/21/12 	
+1.  Shoaib Kamil		2/21/12 	
+1.  Martin Vidner		2/23/12 	
+1.  Jake Ritorto	ModCloth	2/23/12 	
+1.  Seth Kingry	ModCloth	2/23/12 	
+1.  Manuel Gutierrez	ModCloth	2/23/12 	
+1.  Graham McMillan	World Wide Web Hosting, LLC	2/24/12 	
+1.  Nicholas Stielau		2/24/12 	
+1.  McClain Looney		2/24/12 	
+1.  Jim Meyer		2/29/12 	
+1.  Trevor Orsztynowicz	Joyent	2/29/12 	
+1.  Kevin Chang	Joyent	2/29/12 	
+1.  Geoffery Nix	ModCloth	3/1/12 	
+1.  Roberto Sanchez	ModCloth	3/1/12 	
+1.  Dan Buch	ModCloth	3/1/12 	
+1.  Ziad Sawalha	Rackspace	3/2/12 	
+1.  Benedikt Böhm		3/4/12 	
+1.  Steven Ivy	Wallrazer, Inc.	3/4/12 	
+1.  Krzysztof Wilczynski		3/5/12 	
+1.  Elson Orlando Rodriguez		3/5/12 	
+1.  Michael Schubert		3/5/12 	
+1.  Douglas Thrift	Rightscale	3/5/12 	
+1.  Andrew Benz		3/6/12 	
+1.  Yann Robin	Youscribe	3/6/12 	
+1.  Javier Frias		3/6/12 	
+1.  Josh Miller	Edmunds.com	3/6/12 	
+1.  Moritz Winter		3/6/12 	
+1.  Aaron Blythe	Cerner Innovation, Inc.	3/8/12 	
+1.  Kevin Shekleton	Cerner Innovation, Inc.	3/8/12 	
+1.  Josh Murphy	Cerner Innovation, Inc.	3/8/12 	
+1.  Bryan Baugher	Cerner Innovation, Inc.	3/8/12 	
+1.  Sachin Sagar Ra		3/8/12 	
+1.  Tarik Jabri		3/8/12 	
+1.  Michael W. Myers		3/10/12 	
+1.  Marcus Cobden		3/11/12 	
+1.  Coimbatore Sankarraman Shyam Sundar		3/12/13 	
+1.  Chris Roberts	Heavy Water Software, Inc.	3/13/12 	
+1.  Justin Mazzi	World Wide Web Hosting, LLC	3/13/12 	
+1.  Joshua Priddle	World Wide Web Hosting, LLC	3/13/12 	
+1.  Paul Stengel	World Wide Web Hosting, LLC	3/13/12 	
+1.  Vince Stratful	World Wide Web Hosting, LLC	3/13/12 	
+1.  Artem Veremey		3/13/12 	
+1.  Jon Cowie		3/15/12 	
+1.  Philip Kromer	Infochimps, Inc	3/17/12 	
+1.  Ben Dean		3/18/12 	
+1.  Zachary Cook		3/19/12 	
+1.  Welby McRoberts		3/20/12 	
+1.  Ian Coffey	Voxel Dot Net, Inc	3/20/12 	
+1.  David Amian Valle		3/21/12 	
+1.  Lewis J. Goettner, III		3/21/12 	
+1.  Bernardo Gomez Palacio 		3/23/12 	
+1.  Chris Gaffney 		3/23/12 	
+1.  Igor Kurochkin		3/24/12 	
+1.  Oleksiy Kovyrin 		3/24/12 	
+1.  Jordan Dea-Mattson	Numenta, Inc.	3/26/12 	
+1.  Cody Ebberson	Numenta, Inc.	3/27/12 	
+1.  Martin Hasan Bramwell		3/28/12 	
+1.  Mohammed Siddick		3/28/12 	
+1.  Ira Abramaov	Fewbytes	3/29/12 	
+1.  Paul McCallick		3/29/12 	
+1.  Jon-Paul Sullivan	Hewlett-Packard	3/30/12 	
+1.  Sascha Bates		3/30/12 	
+1.  Julian Cardona	Edmunds.com	4/2/12 	
+1.  David Hudson	Edmunds.com	4/2/12 	
+1.  Andrew Crump	Kotiri Software Ltd.	4/3/12 	
+1.  Zach Dunn		4/5/12 	
+1.  Logan Lowell	The Frontside Software, Inc.	4/5/12 	
+1.  Charles Lowell	The Frontside Software, Inc.	4/5/12 	
+1.  Chris Buben		4/5/12 	
+1.  Joseph Brian Passavanti		4/5/12 	
+1.  Denis Barishev		4/6/12 	
+1.  Jonas Courteau		4/6/12 	
+1.  Eric Hankins		4/10/12 	
+1.  Chris Buben	Gap, Inc.	4/10/12 	
+1.  Oliver Fross	Gap, Inc.	4/10/12 	
+1.  Jeffery Padgett	Gap, Inc.	4/10/12 	
+1.  Philip Vieira		4/10/12 	
+1.  Guilhem Lettron	Youscribe	4/11/12 	
+1.  Sebastien Balant	Youscribe	4/11/12 	
+1.  Robert E. Lewis		4/13/12 	
+1.  David Joos		4/16/12 	
+1.  Umang Chouhan		4/16/12 	
+1.  Sören Blom	Deutsche Telekom Laboratories	4/17/12 	
+1.  Alex Redington	Relevance, Inc.	4/20/12 	
+1.  Gabriel Horner	Relevance, Inc.	4/20/12 	
+1.  Lake Denman	Relevance, Inc.	4/20/12 	
+1.  Larry Karnowski	Relevance, Inc./Truer Sound LLC	4/20/12 	
+1.  Sam Umbach	Relevance, Inc./Truer Sound LLC	4/20/12 	
+1.  Jeremiah Snapp	Asbury Theological Seminary	4/20/12 	
+1.  Brian Bianco		4/20/12 	
+1.  Brandon Martin		4/21/12 	
+1.  Alexander Gordeev		4/24/12 	
+1.  Joe Miller		4/25/12 	
+1.  Nick Peirson		4/27/12 	
+1.  Marc Morata Fite		4/27/12 	
+1.  Seth Thomas		4/27/12 	
+1.  Chris Griego		4/28/12 	
+1.  Dmytro Ilchenko		4/30/12 	
+1.  Morgan Nelson		4/30/12 	
+1.  Chirag Jog	Websym Technologies Private Ltd.	4/30/12 	
+1.  Kalpak Shah	Websym Technologies Private Ltd.	4/30/12 	
+1.  Mohit Sethi	Websym Technologies Private Ltd.	4/30/12 	
+1.  Kyle VanderBeek		5/2/12 	
+1.  TANABE Ken-ichi		5/2/12 	
+1.  Brandon Adams	DreamBox Learning, Inc.	5/3/12 	
+1.  Hui Hu		5/5/12 	
+1.  Will Maier	Simple	5/7/12 	
+1.  Chris Brentano	Simple	5/7/12 	
+1.  Cosmin Stejerean	Simple	5/7/12 	
+1.  Brian Merritt	Simple	5/7/12 	
+1.  Pascal Deschenes		5/8/12 	
+1.  Michael Glenn		5/8/12 	
+1.  Dan Crosta		5/9/12 	
+1.  Daniel Condomitti		5/9/12 	
+1.  Matthew Butcher		5/10/12 	
+1.  Ben Poweski	Consumer Club, Inc.	5/10/12 	
+1.  Chris Griego	Consumer Club, Inc.	5/10/12 	
+1.  Jim Hughes	Consumer Club, Inc.	5/10/12 	
+1.  Morgan Nelson	Consumer Club, Inc.	5/10/12 	
+1.  Kristina Rodgers	Consumer Club, Inc.	5/10/12 	
+1.  Derek Schultz		5/11/12 	
+1.  Anay Nayak		5/15/12 	
+1.  Patrick Ting		5/17/12 	
+1.  Xabier de Zuazo Oteiza	Onddo Labs	5/18/12 	
+1.  Raul Rodriguez Munoz	Onddo Labs	5/18/12 	
+1.  Ramez Mourad		5/21/12 	
+1.  Jonathan Manton		5/22/12 	
+1.  Philipp Wollermann	CyberAgent Corp.	5/22/12 	
+1.  Koji Hasebe	CyberAgent Corp.	5/22/12 	
+1.  Jean-Daniel Bussy	CyberAgent Corp.	5/22/12 	
+1.  Yoshihisa Sakamoto	CyberAgent Corp.	5/22/12 	
+1.  Kohei Maeda	CyberAgent Corp.	5/22/12 	
+1.  Eric Edgar		5/23/12 	
+1.  Rodolphe Blancho		5/23/12 	
+1.  Kevin Nuckolls		5/24/12 	
+1.  Michael Nygard	Relevance, Inc.	5/29/12 	
+1.  Martin Fenner		5/30/12 	
+1.  Lukasz Kaniowski		5/31/12 	
+1.  Brian Flad		5/31/12 	
+1.  Justin Witrick	Rackspace	6/1/12 	
+1.  Nickalaus Willever		6/1/12 	
+1.  Harold "Waldo" Grunenwald III		6/4/12 	
+1.  Bjorn Albers		6/4/12 	
+1.  Timothy Martin Potter		6/5/12 	
+1.  Greg Fitzgerald		6/6/12 	
+1.  Sebastian Wendel	SourceIndex IT-Services	6/7/12 	
+1.  Leif Madsen		6/7/12 	
+1.  Jonathan del Strother		6/7/12 	
+1.  Bernd Roth		6/8/12 	
+1.  Madhurranjan Mohaan		6/11/12 	
+1.  Seth Vargo		6/11/12 	
+1.  Gregory Jones		6/12/12 	
+1.  Joshua Brand		6/15/12 	
+1.  David Stainton	Scribd, Inc.	6/15/12 	
+1.  Sriram Devadas		6/17/12 	
+1.  Christopher Webber		6/17/12 	
+1.  Raf Geens	Civolution BV	6/18/12 	
+1.  Greg Symons	Drillinginfo	6/18/12 	
+1.  Clark Archer	Drillinginfo	6/18/12 	
+1.  David Eddy		6/18/12 	
+1.  Jonathan Hartman	Rackspace	6/21/12 	
+1.  Boyd Edward Hemphill		6/21/12 	
+1.  Martha Greenberg		6/24/12 	
+1.  Paul Meserve		6/25/12 	
+1.  Michael H. Oshita		6/25/12 	
+1.  James W. Brinkerhoff	Voxel Dot Net, Inc	6/26/12 	
+1.  Evan Vetere	Voxel Dot Net, Inc	6/26/12 	
+1.  Kris Beevers	Voxel Dot Net, Inc	6/26/12 	
+1.  Patrick Dowell	Voxel Dot Net, Inc	6/26/12 	
+1.  Zachary Voase		6/26/12 	
+1.  Paul Guth	The Cloudscaling Group, Inc.	6/27/12 	
+1.  Rodolphe Pineau	The Cloudscaling Group, Inc.	6/27/12 	
+1.  Jeremy Deininger	The Cloudscaling Group, Inc.	6/27/12 	
+1.  Blake Barnett	The Cloudscaling Group, Inc.	6/27/12 	
+1.  HIGUCHI Daisuke	Creationline, Inc.	6/27/12 	
+1.  Jey Hotta	Creationline, Inc.	6/27/12 	
+1.  Kent R. Spillner		7/6/12 	
+1.  Brian Dols		7/6/12 	
+1.  Frank Rosquin		7/10/12 	
+1.  Bill Moritz		7/10/12 	
+1.  Alfred Rossi	Action Verb, LLC	7/10/12 	
+1.  Patrick Ribeiro Negri	lugu Seervicos na Internet LTDA	7/11/12 	
+1.  Marcelo Paez	lugu Seervicos na Internet LTDA	7/11/12 	
+1.  Alexandre Paez	lugu Seervicos na Internet LTDA	7/11/12 	
+1.  Wong Liang Zan		7/11/12 	
+1.  Matthew Andersen		7/12/12 	
+1.  Jacob Atzen		7/13/12 	
+1.  Chris Parsons		7/13/12 	
+1.  Timothy Jones		7/14/12 	
+1.  Ameya Prakash Gangamwar		7/15/12 	
+1.  Adrien Brault		7/16/12 	
+1.  Michael T. Halligan		7/17/12 	
+1.  Andreas Boehrnsen	OpeniT	7/18/12 	
+1.  Jay Levitt		7/20/12 	
+1.  Jose Luis Fernandez Perez		7/21/12 	
+1.  Aaron J. Peterson		7/22/12 	
+1.  Jim Croft	Cloudreach Limited	7/24/12 	
+1.  Richard Bowden	Cloudreach Limited	7/24/12 	
+1.  Joe Geldart	Cloudreach Limited	7/24/12 	
+1.  Bryce Lynn	Tacit Knowledge	7/24/12 	
+1.  Brian Smith	Bonnier Corporation	7/25/12 	
+1.  Michael Linde	Bonnier Corporation	7/25/12 	
+1.  Peter Lauda	Bonnier Corporation	7/25/12 	
+1.  Rakesh Patel	OneHealth Solutions, Inc.	7/25/12 	
+1.  Jay Perry		7/26/12 	
+1.  Mark Roddy		7/26/12 	
+1.  Andrew Regan		7/26/12 	
+1.  Takeshi Kondo		7/26/12 	
+1.  Paul Rossman		7/26/12 	
+1.  Bryan Stearns	Paydici Corp.	7/26/12 	
+1.  Jim Harvey	Paydici Corp.	7/26/12 	
+1.  Bill Burcham	Paydici Corp.	7/26/12 	
+1.  Steve Rude		7/26/12 	
+1.  Richard Clamp		7/29/12 	
+1.  Christopher Kelly		7/30/12 	
+1.  Deepak Kannan		7/30/12 	
+1.  Roy Liu		7/31/12 	
+1.  Artiom Lunev		7/31/12 	
+1.  Anna Marseille D. Gabutero		7/31/12 	
+1.  Lucas Jandrew	Riot Games	8/1/12 	
+1.  Dafydd Crosby		8/1/12 	
+1.  Christoph Thiel	Novell, Inc.	8/1/12 	
+1.  Ralf Haferkamp	Novell, Inc.	8/1/12 	
+1.  Adam Spiers	Novell, Inc.	8/1/12 	
+1.  Tim Serong	Novell, Inc.	8/1/12 	
+1.  Sascha Peilicke	Novell, Inc.	8/1/12 	
+1.  Bernhard Wiedemann	Novell, Inc.	8/1/12 	
+1.  Ionuts Artarisi	Novell, Inc.	8/1/12 	
+1.  Vincent Untz	Novell, Inc.	8/1/12 	
+1.  Martin Vidner	Novell, Inc.	8/1/12 	
+1.  J. Daniel Schmidt	Novell, Inc.	8/1/12 	
+1.  Stefan Fent	Novell, Inc.	8/1/12 	
+1.  Danny Kukawka	Novell, Inc.	8/1/12 	
+1.  Michal Vyskocil	Novell, Inc.	8/1/12 	
+1.  Kristian Vlaardingerbroek	Schuberg Philis B.V.	8/3/12 	
+1.  Jon Gretarsson	RelatelIQ Inc.	8/3/12 	
+1.  Danial Pearce		8/5/12 	
+1.  Stathis Touloumis		8/5/12 	
+1.  Matthew Scott Moyer		8/7/12 	
+1.  Benedict Steele		8/7/12 	
+1.  James Tan	Novell, Inc.	8/7/12 	
+1.  John Kip Larsen		8/8/12 	
+1.  Chris Buryta		8/9/12 	
+1.  Sahil Muthoo		8/10/12 	
+1.  Kyle Goodwin	PrimeRevenue, Inc	8/10/12 	
+1.  Ben Rosenblum	PrimeRevenue, Inc	8/10/12 	
+1.  Aaron Kalin		8/10/12 	
+1.  John Dewey		8/11/12 	
+1.  Abel Lopez		8/13/12 	
+1.  Lyndon Washington		8/14/12 	
+1.  Ripal Nathuji	Calxeda	8/14/12 	
+1.  Gardner Bickford		8/15/12 	
+1.  Nick Heppner		8/16/12 	
+1.  Jeffrey Dutton		8/16/12 	
+1.  Taklon Wu		8/17/12 	
+1.  Craig Tracey		8/17/12 	
+1.  Lee Jensen	Big Cartel LLC	8/17/12 	
+1.  Chris Cameron	Big Cartel LLC	8/17/12 	
+1.  Kelley Reynolds	Big Cartel LLC	8/17/12 	
+1.  Michael Wallman		8/17/12 	
+1.  Edward Sargisson		8/19/12 	
+1.  Winfield Peterson		8/20/12 	
+1.  Mathew Davies		8/21/12 	
+1.  Justin Shepherd	Rackspace	8/21/12 	
+1.  Jason Cannavale	Rackspace	8/21/12 	
+1.  Ron Pedde	Rackspace	8/21/12 	
+1.  Joseph Breu	Rackspace	8/21/12 	
+1.  William Kelly	Rackspace	8/21/12 	
+1.  Darren Birkett	Rackspace	8/21/12 	
+1.  Evan Callicoat	Rackspace	8/21/12 	
+1.  Andrew Ferk		8/23/12 	
+1.  Shaun Hope		8/23/12 	
+1.  Matt Kynaston		8/24/12 	
+1.  Ben Marini		8/25/12 	
+1.  Garret Heaton	Atlassian	8/27/12 	
+1.  Julian Dunn		8/27/12 	
+1.  Jordan Evans		8/28/12 	
+1.  Andrew Laski		8/31/12 	
+1.  Mat Schaffer		8/31/12 	
+1.  Elliot Pahl		9/3/12 	
+1.  Richard Shade	Rightscale	9/5/12 	
+1.  Dmytro Kovalov		9/5/12 	
+1.  Shishir Das		9/6/12 	
+1.  Kimball Johnson	One Connect Limited	9/7/12 	
+1.  Roy Crombleholme	One Connect Limited	9/7/12 	
+1.  Martin Foster	One Connect Limited	9/7/12 	
+1.  Alex Klepa		9/7/12 	
+1.  Brendan Hay		9/7/12 	
+1.  Paul Graydon		9/7/12 	
+1.  Steve Layland		9/7/12 	
+1.  Thomas Dudziak		9/7/12 	
+1.  Felix Sheng		9/8/12 	
+1.  Sean Porter	Sonian Inc	9/8/12 	
+1.  Josh Pasqualetto	Sonian Inc	9/8/12 	
+1.  TJ Vanderpoel	Sonian Inc	9/8/12 	
+1.  Justin Kolberg	Sonian Inc	9/8/12 	
+1.  Decklin Foster	Sonian Inc	9/8/12 	
+1.  Randall Morse		9/10/12 	
+1.  Pete Cheslock	Dyn	9/10/12 	
+1.  Max Stepanov		9/11/12 	
+1.  Sean Gallagher		9/11/12 	
+1.  Autif Khan		9/11/12 	
+1.  Jacques Marneweck		9/12/12 	
+1.  William Herry		9/16/12 	
+1.  Pawel Kozlowski		9/16/12 	
+1.  Lawrence Gilbert		9/18/12 	
+1.  Bob Walker		9/18/12 	
+1.  Nathan Schimke		9/18/12 	
+1.  Graham Christensen		9/19/12 	
+1.  Alessandro Dal Grande	The App Business	9/19/12 	
+1.  Saager Suhas Mhatre		9/23/12 	
+1.  Charles J Blaine		9/23/12 	
+1.  Andres de Barbara		9/23/12 	
+1.  Adam Vinsh		9/25/12 	
+1.  Elliot Murphy	Pat Deegan, PhD & Associates, LLC	9/26/12 	
+1.  John Nishinaga	Pat Deegan, PhD & Associates, LLC	9/26/12 	
+1.  Farley Knight	Pat Deegan, PhD & Associates, LLC	9/26/12 	
+1.  Jon Sime	OmniTI	9/26/12 	
+1.  Clinton Wolfe	OmniTI	9/26/12 	
+1.  Theo Schlossnagle	OmniTI	9/26/12 	
+1.  Robert Treat	OmniTI	9/26/12 	
+1.  Adam DePue		9/26/12 	
+1.  Martin Contento		9/27/12 	
+1.  Milos Gajdos		9/27/12 	
+1.  Brad Gignac	Rackspace	9/28/12 	
+1.  Robert Allen		9/30/12 	
+1.  Chia-liang Kao		10/1/12 	
+1.  Ketan Padegaonkar		10/2/12 	
+1.  Antti Puranen	Reaktor Innovations	10/5/12 	
+1.  Stephen Crawley		10/7/12 	
+1.  Brad Bennet	ZestFinance	10/8/12 	
+1.  Alexander Tamoykin	ZestFinance	10/8/12 	
+1.  Lloyd Philbrook	Firebelly Design	10/8/12 	
+1.  Nate Beaty	Firebelly Design	10/8/12 	
+1.  John Skopis		10/8/12 	
+1.  Susan Potter		10/8/12 	
+1.  Jatinder Giri		10/10/12 	
+1.  Joan Touzet	Cloudant, Inc.	10/11/12 	
+1.  Kyle Allan	Riot Games	10/11/12 	
+1.  Jay Pipes		10/12/12 	
+1.  John Austin Page		10/15/12 	
+1.  Chuck Ha		10/15/12 	
+1.  David Dvorak	Webtrends	10/15/12 	
+1.  Dipen Lad		10/15/12 	
+1.  Pascal Deschenes	Nu Echo	10/16/12 	
+1.  Matthieu Vachon	Nu Echo	10/16/12 	
+1.  Raymond Menard	Nu Echo	10/16/12 	
+1.  Jean-Francois Alix	Nu Echo	10/16/12 	
+1.  Mariano Cortesi		10/16/12 	
+1.  Alexander Phan		10/16/12 	
+1.  Jeff Siegel		10/16/12 	
+1.  William Milton		10/17/12 	
+1.  Mark Pimentel		10/18/12 	
+1.  Mike Gifford	OpenConcept	10/18/12 	
+1.  Mike Mallett	OpenConcept	10/18/12 	
+1.  Brian Loomis		10/20/12 	
+1.  Michael Saffitz	Apptentive	10/20/12 	
+1.  Andrew Wooster	Apptentive	10/20/12 	
+1.  Sky Kelsey	Apptentive	10/20/12 	
+1.  Benjamin Michael Atkin	Document Swarm, LLC	10/20/12 	
+1.  Andreas Gerauer		10/22/12 	
+1.  Steven Deaton		10/22/12 	
+1.  Cassiano Bertol Leal		10/23/12 	
+1.  Matt Towers		10/23/12 	
+1.  Mark Ayers		10/23/12 	
+1.  Anthony Leto		10/23/12 	
+1.  Marc Soda		10/24/12 	
+1.  Jerome D Harrington, II		10/24/12 	
+1.  Russell Stewart Egan		10/24/12 	
+1.  Paul Thomas		10/24/12 	
+1.  Chris Lundquist		10/24/12 	
+1.  Anton Orel		10/25/12 	
+1.  Marius Sturm		10/25/12 	
+1.  Dimitri David Boelaert-Roche		10/25/12 	
+1.  Matthew Serafin Horan		10/25/12 	
+1.  Vojtech Hyza		10/25/12 	
+1.  Steve Houser		10/26/12 	
+1.  Dmitry Zamaruev		10/29/12 	
+1.  James Hu		10/29/12 	
+1.  Laust Rud Jacobsen		10/29/12 	
+1.  Zo Obradovic		10/29/12 	
+1.  Dale Kiefling		10/29/12 	
+1.  Todd Fleisher		10/29/12 	
+1.  Karl Freeman		10/30/12 	
+1.  Johannes Becker		10/30/12 	
+1.  Fred Sadaghiani	Sift Science, Inc.	10/31/12 	
+1.  Jeff Thompson		10/31/12 	
+1.  Stanislav Bogatyrev		10/31/12 	
+1.  Jonathan Peck	FluxSauce	11/1/12 	
+1.  Jeffrey Borg		11/1/12 	
+1.  Guido Serra	Rocket Internet GmbH	11/2/12 	
+1.  Sebastian Grewe		11/3/12 	
+1.  Chaoran Xie		11/3/12 	
+1.  Julien Duponchelle		11/4/12 	
+1.  Trae Robrock		11/5/12 	
+1.  Nikita Borzykh		11/6/12 	
+1.  Ilya Sher		11/6/12 	
+1.  Michael Fischer		11/6/12 	
+1.  Nathan Baxter		11/6/12 	
+1.  Simon Belluzzo		11/6/12 	
+1.  Ben Hartshorne		11/9/12 	
+1.  Matt Whiteley	Engine Yard	11/9/12 	
+1.  Raul Naveiras		11/13/12 	
+1.  Eugene Wood		11/13/12 	
+1.  Javier Perez-Griffo	Tapp	11/13/12 	
+1.  Dang Nguyen		11/13/12 	
+1.  Pablo Banos	Tapp	11/13/12 	
+1.  Christian Hofer	Tapp	11/13/12 	
+1.  Matthew Rogers		11/13/12 	
+1.  Stephen Lauck		11/13/12 	
+1.  Mark Van de Vyver	Taqtiqa LLC	11/14/12 	
+1.  Thomas Carroll		11/14/12 	
+1.  Jon DeCamp	Nordstrom, Inc	11/15/12 	
+1.  Doug Ireton	Nordstrom, Inc	11/15/12 	
+1.  Kevin Moser	Nordstrom, Inc	11/15/12 	
+1.  Justin Schumacher	Nordstrom, Inc	11/15/12 	
+1.  Rob Cummings	Nordstrom, Inc	11/15/12 	
+1.  Brandon Burton		11/20/12 	
+1.  Christopher Ferry		11/20/12 	
+1.  Michael Hood		11/22/12 	
+1.  Gavin Montague		11/23/12 	
+1.  Michal Lomnicki		11/24/12 	
+1.  Doc Walker		11/24/12 	
+1.  Nicolas Szalay		11/26/12 	
+1.  Terry Carr		11/26/12 	
+1.  Michael Myers	Daptiv Solutions LLC	11/26/12 	
+1.  Shawn Neal	Daptiv Solutions LLC	11/26/12 	
+1.  Chris Bobo	Daptiv Solutions LLC	11/26/12 	
+1.  Ian Gantt	Daptiv Solutions LLC	11/26/12 	
+1.  Alan Gray	Daptiv Solutions LLC	11/26/12 	
+1.  Kishore Kumar S		11/26/12 	
+1.  Vincent Leraitre		11/27/12 	
+1.  Samuel Gerstein		11/27/12 	
+1.  John T Skarbek		11/27/12 	
+1.  Paul A Jungwirth		11/28/12 	
+1.  Thomas Hodder	Lime Pepper Ltd	11/28/12 	
+1.  Warren Vosper	Straydog Software, Inc.	11/29/12 	
+1.  Joshua Reedy		11/30/12 	
+1.  Mehmet Ali Akmanalp		11/30/12 	
+1.  Panagiotis Papadomitsos		11/30/12 	
+1.  Allan Espinosa		11/30/12 	
+1.  Brian Pitts		12/1/12 	
+1.  Elliot Kendall		12/3/12 	
+1.  Nathan Mische		12/3/12 	
+1.  Matthew Turney		12/3/12 	
+1.  Jay Flowers		12/4/12 	
+1.  Loic Antoine-Gombeaud		12/5/12 	
+1.  Joe Rodriguez		12/5/12 	
+1.  Kyle Scarmardo	Fidelity Technology Group, LLC	12/6/12 	
+1.  Jon Lenzer	Fidelity Technology Group, LLC	12/6/12 	
+1.  Chaoran Xie	Fidelity Technology Group, LLC	12/6/12 	
+1.  Shalon Wood	Fidelity Technology Group, LLC	12/6/12 	
+1.  David Crane		12/6/12 	
+1.  Takumi IINO		12/9/12 	
+1.  Tolleiv Nietsch		12/9/12 	
+1.  Benoit Caron		12/9/12 	
+1.  Mathieu Martin		12/10/12 	
+1.  Yung Giang		12/11/12 	
+1.  Fabian Ruff		12/11/12 	
+1.  Takeshi KOMIYA		12/11/12 	
+1.  Rafael Fonseca		12/12/12 	
+1.  Justin Campbell		12/12/12 	
+1.  Andrey Subbota		12/13/12 	
+1.  Jacob Ritorto		12/13/12 	
+1.  Pierre Ozoux		12/14/12 	
+1.  Shoaib Mushtaq		12/16/12 	
+1.  Arnold Krille	bcs kommunikationslosungen	12/17/12 	
+1.  Rainer Dietz	bcs kommunikationslosungen	12/17/12 	
+1.  Paul Diaconescu		12/17/12 	
+1.  Jake Davis	Simple	12/17/12 	
+1.  Mike Ehlert	Simple	12/17/12 	
+1.  Kevin Bringard		12/19/12 	
+1.  David Whittington		12/20/12 	
+1.  Raphael Valyi		12/20/12 	
+1.  Michael Klapper		12/23/12 	
+1.  Eli Klein		12/24/12 	
+1.  Andrew Lawrence Burns		12/26/12 	
+1.  Kevin Keane	North County Tech Center, LLC	12/26/12 	
+1.  David Petzel		12/28/12 	
+1.  Thomas Robison		12/28/12 	
+1.  Keenan Brock		12/28/12 	
+1.  Stefan Borsje		12/29/12 	
+1.  Jon Galentine		12/29/12 	
+1.  Kiesia Croucher		12/31/12 	
+1.  Deeba Siddiqi		1/2/13 	
+1.  Steven De Coeyer		1/2/13 	
+1.  Yoni Yalovitsky	Fewbytes	1/2/13 	
+1.  Alex Kiernan		1/3/13 	
+1.  Gilles Cornu		1/4/13 	
+1.  Gavin Mogan		1/4/13 	
+1.  Steven Lehrburger		1/4/13 	
+1.  Jordi Llonch		1/6/13 	
+1.  Nicolas Rycar		1/7/13 	
+1.  Andrew McCloud		1/7/13 	
+1.  Gregoire Seux	Criteo	1/8/13 	
+1.  Brian Scott	Emergent One	1/9/13 	
+1.  Mike Taczak	Emergent One	1/9/13 	
+1.  Javier Segura Martinez		1/9/13 	
+1.  Warren Bain	Ninefold Pty Limited	1/9/13 	
+1.  Shaun Domingo	Ninefold Pty Limited	1/9/13 	
+1.  Toby Hede	Ninefold Pty Limited	1/9/13 	
+1.  Paul Handly	DecisionDesk	1/13/13 	
+1.  Eric Neuman	DecisionDesk	1/13/13 	
+1.  Will Olbrys	DecisionDesk	1/13/13 	
+1.  Thomas Bouve		1/14/13 	
+1.  Kevin Reedy	Belly Inc	1/15/13 	
+1.  Craig Ulliott	Belly Inc	1/15/13 	
+1.  Jay OConnor	Belly Inc	1/15/13 	
+1.  Courtenay Gasking		1/16/13 	
+1.  James Dabbs		1/16/13 	
+1.  Jerry Cattell		1/16/13 	
+1.  Jon Webb		1/17/13 	
+1.  Hendrik Volkmer	cloudbau Gmbh	1/18/13 	
+1.  Thomas Kadauke	cloudbau Gmbh	1/18/13 	
+1.  Martin Bosner	cloudbau Gmbh	1/18/13 	
+1.  Christopher Laco		1/18/13 	
+1.  Haggai Philip Zagury		1/19/13 	
+1.  Eric Sigler		1/20/13 	
+1.  Yves Vogl		1/21/13 	
+1.  Yukihiko Sawanobori	HiganWorks LLC	1/21/13 	
+1.  Seth Larson		1/21/13 	
+1.  Ben Langeld		1/21/13 	
+1.  Dan Midwood		1/22/13 	
+1.  Peter Pouliot		1/22/13 	
+1.  Alexander Bondarev		1/23/13 	
+1.  Ben Dean	Ontario Systems	1/23/13 	
+1.  Keith Shook	Ontario Systems	1/23/13 	
+1.  Lucas Heinlen	Ontario Systems	1/23/13 	
+1.  Kyle Michel	Ontario Systems	1/23/13 	
+1.  Brice Oliver	Ontario Systems	1/23/13 	
+1.  David Rogers	Lytro, Inc.	1/23/13 	
+1.  Alvin Lai	Lytro, Inc.	1/23/13 	
+1.  Anuj Biyani	Lytro, Inc.	1/23/13 	
+1.  Tiffany Russo	Lytro, Inc.	1/23/13 	
+1.  Craig Brunner	Lytro, Inc.	1/23/13 	
+1.  Mugur Marculescu	Lytro, Inc.	1/23/13 	
+1.  Tom Hanley	Lytro, Inc.	1/23/13 	
+1.  Thomas Massmann		1/25/13 	
+1.  Ankit Shah		1/25/13 	
+1.  Josh Mahowald		1/25/13 	
+1.  Christopher Bandy		1/25/13 	
+1.  Mal Graty		1/27/13 	
+1.  Vaidas Jablonskis		1/27/13 	
+1.  Simon McCartney		1/28/13 	
+1.  Jake Davis		1/29/13 	
+1.  Sean Kilgore		1/29/13 	
+1.  Scott Lampert		1/29/13 	
+1.  Michael Frick		1/29/13 	
+1.  Kevin Duane		1/30/13 	
+1.  Ryan Geyer		1/30/13 	
+1.  George Hafiz		1/30/13 	
+1.  Eric Pardee	Atlas Digital, LLC	1/30/13 	
+1.  Jaroslaw Zmudzinski	Grupa Allegro Sp. z o.o.	1/31/13 	
+1.  Alexey Polovinkin		2/1/13 	
+1.  Malte Swart		2/2/13 	
+1.  Jon Burgess		2/3/13 	
+1.  Daniel Hahn		2/4/13 	
+1.  Maxime Brugidou	Criteo	2/4/13 	
+1.  Gareth David Rushgrove		2/4/13 	
+1.  Michael Conigliaro		2/4/13 	
+1.  James Kessler		2/4/13 	
+1.  Lukasz Jagiello		2/4/13 	
+1.  Mischa Taylor		2/4/13 	
+1.  Mervyn Hammer	Workday Inc.	2/5/13 	
+1.  David Radcliffe		2/5/13 	
+1.  Alexander Titov		2/5/13 	
+1.  Buntaro OKADA		2/5/13 	
+1.  Alexey Kalinin		2/5/13 	
+1.  Adam Cownoble		2/6/13 	
+1.  Josh Behrends	Webtrends	2/6/13 	
+1.  Mark Shlimovich		2/6/13 	
+1.  Jahn Bertsch		2/7/13 	
+1.  Sergio Rodriguez		2/7/13 	
+1.  Timur Batyrshin		2/8/13 	
+1.  Samuel Cooper		2/8/13 	
+1.  Ignacy Kasperowicz		2/8/13 	
+1.  Ranjib Dey		2/8/13 	
+1.  Kirill Kouznetsov		2/8/13 	
+1.  Jordan Hagan		2/8/13 	
+1.  Alexander Coles		2/9/13 	
+1.  Michael Grosser		2/10/13 	
+1.  Michael Goetz		2/11/13 	
+1.  Patrick Humpal		2/11/13 	
+1.  Nate Smith		2/13/13 	
+1.  Martin Eigenbrodt		2/13/13 	
+1.  Russell Cloran		2/13/13 	
+1.  John Gabriel McArthur		2/13/13 	
+1.  Jessica Bourne		2/13/13 	
+1.  Darren Haken		2/14/13 	
+1.  Rick Polk		2/14/13 	
+1.  Eric Berg		2/14/13 	
+1.  Andrew Williams	Intoximeters	2/15/13 	
+1.  Matthew Follett	Intoximeters	2/15/13 	
+1.  Brendan O'Donnell		2/16/13 	
+1.  Igor Serebryany	Airbnb	2/17/13 	
+1.  Lukas Reinfurt		2/17/13 	
+1.  Adam Gross		2/17/13 	
+1.  Giorgio Valoti		2/19/13 	
+1.  Nathan Beyer	Cerner Corporation	2/19/13 	
+1.  Patrik Stenmark	Valtech AB	2/20/13 	
+1.  Evgeny Zislis		2/20/13 	
+1.  Luyi Wang		2/20/13 	
+1.  Jason Schadel	AWeber Communications	2/20/13 	
+1.  David Kinzer		2/22/13 	
+1.  Achim Rosenhagen		2/23/13 	
+1.  Doug Cole		2/23/13 	
+1.  Matthew Wright		2/25/13 	
+1.  Jasper Lievisse Adriaanse		2/25/13 	
+1.  Julien Vehent	AWeber Communications	2/25/13 	
+1.  Ryan Steele	AWeber Communications	2/25/13 	
+1.  Brian K. Jones	AWeber Communications	2/25/13 	
+1.  Benjamin Krein	AWeber Communications	2/25/13 	
+1.  Cliff Erson		2/26/13 	
+1.  Booker Bense		2/27/13 	
+1.  Charity Majors		2/27/13 	
+1.  Jared Russell		2/27/13 	
+1.  Iiro Uusitalo		2/27/13 	
+1.  Ryan Walker	Rackspace	2/28/13 	
+1.  Todd Bushnell		2/28/13 	
+1.  BK Box		2/28/13 	
+1.  Scott Stout		3/1/13 	
+1.  Steffen Gebert		3/3/13 	
+1.  John Cheng		3/3/13 	
+1.  Jeremy Olliver		3/3/13 	
+1.  Alexander Papaspyrou	adesso mobile solutions GmbH	3/4/13 	
+1.  Stoyan Stoyanov	adesso mobile solutions GmbH	3/4/13 	
+1.  Andreas Thielen	adesso mobile solutions GmbH	3/4/13 	
+1.  Yves Vogl	adesso mobile solutions GmbH	3/4/13 	
+1.  Brett Richardson		3/5/13 	
+1.  Kevin Nuckolls	Banno, LLC	3/5/13 	
+1.  Nic Grayson	Banno, LLC	3/5/13 	
+1.  Luke Amdor	Banno, LLC	3/5/13 	
+1.  Danny Lockard	Banno, LLC	3/5/13 	
+1.  Thomas Wallace		3/5/13 	
+1.  Ptah Dunbar		3/6/13 	
+1.  Jonathan Asghar		3/6/13 	
+1.  Brandon Sanders	AboutUs	3/7/13 	
+1.  Aaron Brown		3/7/13 	
+1.  Paul Oliver		3/7/13 	
+1.  Alan Willis	Riot Games	3/7/13 	
+1.  Dimitrios Verraros		3/8/13 	
+1.  Arangamanikkannan Manickam		3/8/13 	
+1.  David Bresnick		3/8/13 	
+1.  Brett Weaver		3/8/13 	
+1.  Drew Flower		3/8/13 	
+1.  Charles Gregory Willis		3/8/13 	
+1.  Owain Perry		3/9/13 	
+1.  Alexander Sakharchuk		3/9/13 	
+1.  Ameir Abdeldayem		3/9/13 	
+1.  Robert Choi		3/10/13 	
+1.  Gemini Agalo-os		3/10/13 	
+1.  Alexander Galato		3/11/13 	
+1.  Gabriel Klein		3/11/13 	
+1.  Eric Richardson		3/12/13 	
+1.  Steven Barre		3/13/13 	
+1.  Paul Rossman	Google, Inc	3/14/13 	
+1.  Riccardo Carlesso	Google, Inc	3/14/13 	
+1.  Benson Kalahar	Google, Inc	3/14/13 	
+1.  Rick Wright	Google, Inc	3/14/13 	
+1.  Eric Johnson	Google, Inc	3/14/13 	
+1.  Aaron Rice		3/15/13 	
+1.  Radoslaw Gruchalski		3/15/13 	
+1.  Matt Gleeson	Atlassian	3/18/13 	
+1.  Will DeHaan	Atlassian	3/18/13 	
+1.  Gabor Nagy		3/18/13 	
+1.  Bryan Stearns		3/18/13 	
+1.  Jose Diaz-Gonzalez		3/19/13 	
+1.  Jean-Francois Theroux		3/19/13 	
+1.  Christopher Stolfi		3/19/13 	
+1.  Darrell Nash		3/19/13 	
+1.  Sean Kane		3/20/13 	
+1.  Patrick Leckey		3/20/13 	
+1.  Michael Rose		3/20/13 	
+1.  Pitr Vernigorov		3/20/13 	
+1.  Capen Brinkley		3/20/13 	
+1.  Tima Maslyuchenko		3/21/13 	
+1.  Yvo van Doorn		3/21/13 	
+1.  Tobias Wilken	cloudControl GmbH	3/21/13 	
+1.  Mateusz Korszun	cloudControl GmbH	3/21/13 	
+1.  Eric Chaves		3/21/13 	
+1.  Peter Donald		3/21/13 	
+1.  Remon Oldenbeuving		3/22/13 	
+1.  Philip Cristiano		3/22/13 	
+1.  Chris Streeter		3/24/13 	
+1.  Kenneth Vetergaard		3/25/13 	
+1.  Gert Kremer		3/25/13 	
+1.  Peter de Rujiter	Springest	3/25/13 	
+1.  Maarten Hoogendoorn	Springest	3/25/13 	
+1.  Daniel Ryan		3/25/13 	
+1.  Matthieu Launay	Criteo	3/26/13 	
+1.  Jean-Baptiste Note	Criteo	3/26/13 	
+1.  Daniel Koepke		3/26/13 	
+1.  Neil Schelly	Dyn, Inc.	3/26/13 	
+1.  David Miller	Dyn, Inc.	3/26/13 	
+1.  Bill Young	Dyn, Inc.	3/26/13 	
+1.  Phillip Goldenburg		3/27/13 	
+1.  Faiz Kazi		3/31/13 	
+1.  James Tucker	Google, Inc	4/1/13 	
+1.  Marco Delaurenti	Google, Inc	4/1/13 	
+1.  Sebastien Roccaserra		4/4/13 	
+1.  Chendil Kumar Manoharan		4/4/13 	
+1.  Jeremy Mauro	Criteo	4/5/13 	
+1.  Joshua Levine		4/5/13 	
+1.  Harley Alaniz	Lookout, Inc.	4/6/13 	
+1.  Hiroaki Nakamura		4/8/13 	
+1.  Leif Madsen	Thinking Phone Networks, Inc.	4/8/13 	
+1.  Chris Sibbitt	Thinking Phone Networks, Inc.	4/8/13 	
+1.  Christian Brideau	Thinking Phone Networks, Inc.	4/8/13 	
+1.  Travis Hein	Thinking Phone Networks, Inc.	4/8/13 	
+1.  Ming Chan		4/8/13 	
+1.  Jamie Alessio		4/9/13 	
+1.  Daichi Kamemoto		4/10/13 	
+1.  David Groulx		4/10/13 	
+1.  TAKEUCHI Go		4/11/13 	
+1.  Alex Dergachev	Evolving Web Inc	4/11/13 	
+1.  Suzanne Kennedy	Evolving Web Inc	4/11/13 	
+1.  Sander Botman		4/15/13 	
+1.  Julio Arias		4/15/13 	
+1.  Alexander Wenzowski		4/16/13 	
+1.  Pete Bristow		4/16/13 	
+1.  Thorsten Klein		4/16/13 	
+1.  Qingkun Liu		4/17/13 	
+1.  Jonathan Cobb	Tout Industries	4/18/13 	
+1.  Matt Lanier	Tout Industries	4/18/13 	
+1.  Felix Roeser	Tout Industries	4/18/13 	
+1.  Tom Hallett	Tout Industries	4/18/13 	
+1.  Sam Gipe	Tout Industries	4/18/13 	
+1.  Brandon Turner		4/20/13 	
+1.  Mathias Lafeldt		4/20/13 	
+1.  Matt Bower		4/21/13 	
+1.  Zachary Patten	Lookout, Inc.	4/22/13 	
+1.  Jim Hopp	Lookout, Inc.	4/22/13 	
+1.  Zsolt Dollenstein		4/23/13 	
+1.  Andrew Hollingsworth		4/24/13 	
+1.  Benjamin Krueger		4/24/13 	
+1.  Matt Thompson	Rackspace	4/25/13 	
+1.  Hugh Saunders	Rackspace	4/25/13 	
+1.  Harry Harrington	Rackspace	4/25/13 	
+1.  Andy McCrae	Rackspace	4/25/13 	
+1.  Chris Laco	Rackspace	4/25/13 	
+1.  Bett Campbell	Rackspace	4/25/13 	
+1.  Zack Feldstein	Rackspace	4/25/13 	
+1.  Drew Rothstein		4/26/13 	
+1.  Gaetano Santonastaso		4/26/13 	
+1.  Tom Molin		4/26/13 	
+1.  James Thompson		4/26/13 	
+1.  Adam Stegman		4/26/13 	
+1.  Robert Rehberg		4/26/13 	
+1.  Amy Marco		4/27/13 	
+1.  Chris Fordham		4/28/13 	
+1.  Paolo Negri		4/29/13 	
+1.  Jeremy Katz		4/29/13 	
+1.  Troy Ready		4/30/13 	
+1.  Jameson Lee		4/30/13 	
+1.  Mehdi Lahmam		5/1/13 	
+1.  Chandrashekar Seenappa		5/1/13 	
+1.  Sander van Harmelen	Schuberg Philis 	5/1/13 	
+1.  Matthew Hooker	Simple	5/1/13 	
+1.  Robert Roose		5/1/13 	
+1.  Peter Jihoon Kim	Irrational Industries	5/1/13 	
+1.  Daniel Dao Quang Ming	Irrational Industries	5/1/13 	
+1.  Arun K Thampi	Irrational Industries	5/1/13 	
+1.  Paul Paradise	Socrata, Inc	5/1/13 	
+1.  Chris Armstrong	Socrata, Inc	5/1/13 	
+1.  David Chadwick Gibbons		5/1/13 	
+1.  Chulki Lee	Aspera, Inc	5/1/13 	
+1.  Christopher Markle	Aspera, Inc	5/1/13 	
+1.  Jason Rutherford		5/1/13 	
+1.  Peter Norton		5/2/13 	
+1.  Walter Dal Mut		5/2/13 	
+1.  Eric Sorenson		5/2/13 	
+1.  Derrick Bryant		5/3/13 	
+1.  Avrohom Katz		5/3/13 	
+1.  Robert Postill		5/3/13 	
+1.  Gabe Mulley	Hadapt, Inc	5/3/13 	
+1.  Daniel Schauenberg		5/4/13 	
+1.  James Turnbull		5/6/13 	
+1.  Seren Thompson		5/7/13 	
+1.  Solvi Pall Asgeirsson		5/7/13 	
+1.  Dale Ragan	Moncai	5/7/13 	
+1.  Eric Blevins	Moncai	5/7/13 	
+1.  Kevin Landreth		5/8/13 	
+1.  Ka-Wing Tam		5/10/13 	
+1.  John Bellone Jr.		5/10/13 	
+1.  Paolo Agostinetto		5/11/13 	
+1.  Robert Coleman		5/11/13 	
+1.  Ahmad Jemai		5/13/13 	
+1.  Manuel Ryan		5/13/13 	
+1.  Ben Somers		5/13/13 	
+1.  Nate Fox		5/13/13 	
+1.  Simon Coffey		5/14/13 	
+1.  Andrea Bernardo Ciddio		5/14/13 	
+1.  Maxim Doucet		5/14/13 	
+1.  Martin Klein		5/14/13 	
+1.  Jeremiah Wuenschel	Yahoo Inc.	5/14/13 	
+1.  Deven Panchal	Yahoo Inc.	5/14/13 	
+1.  Jeff Parrish	Yahoo Inc.	5/14/13 	
+1.  Venkat Venkataraju	Yahoo Inc.	5/14/13 	
+1.  Chris Wing	Yahoo Inc.	5/14/13 	
+1.  Ittai Shadmon	Yahoo Inc.	5/14/13 	
+1.  Itsik Figenblat	Yahoo Inc.	5/14/13 	
+1.  Matthew Mencel		5/14/13 	
+1.  Olaf Heydorn		5/16/13 	
+1.  Bryan Stenson		5/16/13 	
+1.  Holger Protzek		5/16/13 	
+1.  Nilesh Bairagi		5/16/13 	
+1.  Matt Clark		5/16/13 	
+1.  Jan Nikolai Trzeszkowski		5/17/13 	
+1.  Bernhard K. Weisshuhn		5/17/13 	
+1.  Chris Reid		5/17/13 	
+1.  Morgan Blackthorne		5/20/13 	
+1.  Ken Miles		5/20/13 	
+1.  James "Jim" Rosser, IV	Texas A&M University College of Architecture	5/20/13 	
+1.  Derek Groh	Texas A&M University College of Architecture	5/20/13 	
+1.  Benjamin Liles	Texas A&M University College of Architecture	5/20/13 	
+1.  Kyle Morgan	Rackspace 	5/20/13 	
+1.  Wilfred Hughes		5/21/13 	
+1.  Jeff Anderson		5/21/13 	
+1.  Brian Hatfield		5/21/13 	
+1.  Guillermo Carrasco Hernandez		5/21/13 	
+1.  James Sulinksi	MoPub	5/21/13 	
+1.  Haydn Dufrene	MoPub	5/21/13 	
+1.  Rob McQueen	MoPub	5/21/13 	
+1.  Chris Snook	MoPub	5/21/13 	
+1.  Christophe Arguel		5/22/13 	
+1.  Sean Nolen		5/22/13 	
+1.  Chetan Sarva		5/24/13 	
+1.  Justin Ryan	Onelogin, Inc	5/24/13 	
+1.  Stephen Touset	Onelogin, Inc	5/24/13 	
+1.  Marcelo Serpa	Onelogin, Inc	5/24/13 	
+1.  Nelson Enzo	Onelogin, Inc	5/24/13 	
+1.  Elan Ruusamäe		5/24/13 	
+1.  Marco Betti		5/26/13 	
+1.  Jonathan Hitchcock	Yola	5/27/13 	
+1.  Stefano Rivera	Yola	5/27/13 	
+1.  Adrian Moisey	Yola	5/28/13 	
+1.  Doug Beck	Yola	5/28/13 	
+1.  John Tran		5/28/13 	
+1.  Jesse Ahrens	CopperEgg	5/28/13 	
+1.  Ross Dickey	CopperEgg	5/28/13 	
+1.  Scott Johnson	CopperEgg	5/28/13 	
+1.  Eric Anderson	CopperEgg	5/28/13 	
+1.  Benjamin Bytheway		5/28/13 	
+1.  Tehmasp Chaudhri		5/28/13 	
+1.  Russell Teabeault		5/28/13 	
+1.  Tim Ray		5/29/13 	
+1.  Gavin Roy	MeetMe, Inc	5/30/13 	
+1.  Peter Eisentraut	MeetMe, Inc	5/30/13 	
+1.  Jennifer Fountain	MeetMe, Inc	5/30/13 	
+1.  Kenny Furguson	MeetMe, Inc	5/30/13 	
+1.  Michael Glaesemann	MeetMe, Inc	5/30/13 	
+1.  Edward Robinson		6/1/13 	
+1.  Baldur Gudbjornsson		6/1/13 	
+1.  Jeffrey Jones		6/1/13 	
+1.  Louis-Philippe Perron		6/5/13 	
+1.  Victor Sollerhed		6/5/13 	
+1.  Alvin Yik-ning Liang		6/5/13 	
+1.  Cassiano Morgado de Aquino		6/5/13 	
+1.  Brett Graves		6/6/13 	
+1.  Mattew Collinge		6/6/13 	
+1.  Nick Silkey	Rackspace	6/6/13 	
+1.  Chris Stephan		6/6/13 	
+1.  Peter Fern		6/6/13 	
+1.  Kevin Bridges		6/6/13 	
+1.  Peter Halliday		6/7/13 	
+1.  Felix Bunemann		6/9/13 	
+1.  Nanuk Krinner		6/10/13 	
+1.  Robert Dyer		6/10/13 	
+1.  Anthony Scalisi		6/11/13 	
+1.  Ryan Hass		6/11/13 	
+1.  Brad Beam		6/12/13 	
+1.  Ean Rollings		6/13/13 	
+1.  Ken Robertson		6/13/13 	
+1.  Tony Chong		6/13/13 	
+1.  Oliver Nicolaas Ponder		6/14/13 	
+1.  Mikhail Kolesnik		6/16/13 	
+1.  Sergey Khaladzinksi		6/16/13 	
+1.  Tucker DeWitt		6/16/13 	
+1.  Thomas Meeus		6/17/13 	
+1.  Lin Lin		6/17/13 	
+1.  Omar Vargas		6/17/13 	
+1.  Domonkos Tomcsanyi	Boadree Innovations Kft.	6/17/13 	
+1.  Prashant Nadarajan		6/18/13 	
+1.  Eohyung Lee		6/18/13 	
+1.  David Albrecht		6/18/13 	
+1.  Nicholas Downs		6/19/13 	
+1.  Mike Devine		6/19/13 	
+1.  Thomas Cate	Rackspace 	6/18/13 	
+1.  Ryan Richard	Rackspace 	6/18/13 	
+1.  Matthew Thode	Rackspace	6/18/13 	
+1.  Chris Aumann		6/20/13 	
+1.  Eric Wunderlin		6/21/13 	
+1.  Georgi Markov		6/21/13 	
+1.  Sjoerd Mulder		6/21/13 	
+1.  Benjamin Knauss		6/21/13 	
+1.  Erik Gustavson	Bitium, Inc	6/21/13 	
+1.  Prashant Nadarajan	Bitium, Inc	6/21/13 	
+1.  Walter Schiessberg		6/24/13 	
+1.  Vasily Mikhaylichenko 		6/24/13 	
+1.  William Anthony Rhodes Jr		6/24/13 	
+1.  Adam Wayne		6/24/13 	
+1.  Max Manders 	Cloudreach	6/24/13 	
+1.  Justin Stallard		6/25/13 	
+1.  Nelson Chen		6/26/13 	
+1.  Eric Sproul	OmniTI	6/19/13 	
+1.  Andrew Macgregor 		6/27/13 	
+1.  Jeffrey Damick		6/26/13 	
+1.  Daniel Williams		6/27/13 	
+1.  Bruce Li		6/27/13 	
+1.  Satoshi Akama		6/28/13 	
+1.  Dave Stern		6/28/13 	
+1.  David Andrew		6/28/13 	
+1.  Anthony Burns		6/29/13 	
+1.  Michael Ballantyne		6/28/13 	
+1.  Ewan McDougall		7/1/13 	
+1.  Matt Patterson		7/1/13 	
+1.  Ivan Puzyrevskiy		7/2/13 	
+1.  Stefano Tortarolo		7/3/13 	
+1.  Christopher MacNaughton		7/3/13 	
+1.  Skye Book		7/3/13 	
+1.  Mark Butcher		7/4/13 	
+1.  Nick Morgan 	Heart of Sales LLC DBA Ace of Sales 	7/4/13 	
+1.  Ryan Schlesinger	Heart of Sales LLC DBA Ace of Sales 	7/4/13 	
+1.  Kevin Patrick Pullin II		7/5/13 	
+1.  Colin Woodcock	NetSrv Consulting Ltd	7/7/13 	
+1.  Joshua Tobin		7/8/13 	
+1.  James Cuzella		7/8/13 	
+1.  Michael John Huot Jr.		7/9/13 	
+1.  William Albenzi		7/9/13 	
+1.  Matas Veitas		7/10/13 	
+1.  NagaLakshmi N		7/10/13 	
+1.  Evan Michael Kinney		7/11/13 	
+1.  Adam Lane		7/11/13 	
+1.  Rafael Colton		7/11/13 	
+1.  Julien Phalip		7/11/13 	
+1.  Matthew Savage		7/11/13 	
+1.  Koseki Kengo		7/11/13 	
+1.  Gregory Palmier		7/12/13 	
+1.  Alain O'Dea		7/12/13 	
+1.  Peter Hoellig	PROS, Inc. a Delaware Corporation	7/12/13 	
+1.  Vladimir Skubriev		7/12/13 	
+1.  Ryan Stephens 	AURIN Project -Faculty of Architecture, Building and Planning 	7/12/13 	
+1.  Martin Tomko 	AURIN Project -Faculty of Architecture, Building and Planning 	7/12/13 	
+1.  Christopher Bayliss 	AURIN Project -Faculty of Architecture, Building and Planning 	7/12/13 	
+1.  Peter Ellingsen 	AURIN Project -Faculty of Architecture, Building and Planning 	7/12/13 	
+1.  Chris Pettit 	AURIN Project -Faculty of Architecture, Building and Planning 	7/12/13 	
+1.  Jörg Thalheim		7/12/13 	
+1.  Zac Hallett		7/12/13 	
+1.  Emanuele Zattin		7/11/13 	
+1.  Daniel Steen		7/12/13 	
+1.  Ronnie Taylor		7/13/13 	
+1.  Danny Guinther		7/14/13 	
+1.  Michael Vitale		7/16/13 	
+1.  Nicholas Ethier		7/16/13 	
+1.  Steve Poe	Onlife Health Inc 	7/17/13 	
+1.  Craig Menning		7/17/13 	
+1.  Antoni Baranski	Roblox Inc.	7/17/13 	
+1.  John Landahl		7/18/13 	
+1.  Rudy Grigar		7/19/13 	
+1.  Katsuma Ito		7/19/13 	
+1.  Andrew Wyatt	Onlife Health Inc	7/19/13 	
+1.  Naoki AINOYA		7/21/13 	
+1.  David Giesberg		7/21/13 	
+1.  Luke Hoschke		7/21/13 	
+1.  Myles Steinhauser		7/22/13 	
+1.  Kyle Rames	Rackspace	7/23/13 	
+1.  Chris Snell	Rackspace	7/23/13 	
+1.  Jason Roelofs		7/23/13 	
+1.  Hugo Trippaers		7/24/13 	
+1.  Mark Friedgan		7/24/13 	
+1.  Matthew Hopkins		7/24/13 	
+1.  Eddie Zaneski		7/24/13 	
+1.  Maxwell Robett Dietz		7/24/13 	
+1.  Simon Robson		7/25/13 	
+1.  Dan Bachelder		7/26/13 	
+1.  Matthew Farmer		7/26/13 	
+1.  Thomas Neal Cravey		7/26/13 	
+1.  Ross Timson		7/29/13 	
+1.  Donald Stufft		7/28/13 	
+1.  Gilles Cornu		7/28/13 	
+1.  Kenichi Saita		7/28/13 	
+1.  Ivan Tanev		7/27/13 	
+1.  Chris Gallimore		7/26/13 	
+1.  Sonny Garcia		7/26/13 	
+1.  Alexis Midon		7/26/13 	
+1.  Brandon Henry		7/29/13 	
+1.  Jordan Wesolowski		7/29/13 	
+1.  Christopher Brinley		7/29/13 	
+1.  Nimesh Subramanian	Cerner	7/29/13 	
+1.  Eric Hartmann		7/29/13 	
+1.  Kevin Rochford		7/30/13 	
+1.  Jon San Miguel		7/30/13 	
+1.  Tommy Fotak		7/31/13 	
+1.  Nicholas Hatch		8/1/13 	
+1.  Raf Geens		8/6/13 	
+1.  Thomas Bell		8/6/13 	
+1.  Braden Wright		8/6/13 	
+1.  Johnny Tan		8/6/13 	
+1.  Yvonne Beumer	Cloudreach	8/12/13 	
+1.  Ben House		8/9/13 	
+1.  Joe Fitzgerald		8/12/13 	
+1.  Peter Hessler		8/13/13 	
+1.  Nicholas Russell		8/13/13 	
+1.  Brian Golf		8/13/13 	
+1.  Adam Kunk		8/13/13 	
+1.  Sandy Vanderbleek		8/13/13 	
+1.  Lance French		8/13/13 	
+1.  Jeff Hagadom		8/14/13 	
+1.  George Miranda		8/16/13 	
+1.  Evan Gilman		8/19/13 	
+1.  Nenad Petronijevic		8/19/13 	
+1.  Daniel Spilker 	CoreMedia AG	7/31/13 	 	
+1.  Felix Simmendinger	CoreMedia AG	7/31/13 	
+1.  Eike Thienemann-Dehde	CoreMedia AG	7/31/13 	 	
+1.  Christopher Hass	CoreMedia AG	7/31/13 	
+1.  Daniel Zabel	CoreMedia AG	7/31/13 	
+1.  Ryan Munson	Taos Mountain, Inc.	7/31/13 	
+1.  Tim Fischbach		8/20/13 	
+1.  Chance Zibolski		8/20/13 	
+1.  Kazuki Akamine		8/20/13 	
+1.  David Wittman		8/20/13 	
+1.  Brian Whipple	PROS, Inc. a Delaware Corporation	8/14/13 	
+1.  Michael Jensen	PROS, Inc. a Delaware Corporation	8/14/13 	
+1.  Asanka Samaraweera	PROS, Inc. a Delaware Corporation	8/14/13 	
+1.  Christian Vozar	Belly Inc	8/20/13 	
+1.  Darby Frey	Belly Inc	8/20/13 	
+1.  Matthew Herscovitch	Identive Group	8/20/13 	
+1.  Mark Butcher	Identive Group	8/20/13 	
+1.  Luke Bradbury	University of Derby	8/28/13 	
+1.  Dan Webb	University of Derby	8/28/13 	
+1.  Alastair Firth		8/23/13 	
+1.  Jesse Adams		8/28/13 	
+1.  Matt Alexander		8/28/13 	
+1.  Jason Vanderhoof		8/26/13 	
+1.  Lianping Chen		8/26/13 	
+1.  Christoph Bunte		8/26/13 	
+1.  Yvonne Lam		8/28/13 	
+1.  Mark Cornick	TeamSnap	8/29/13 	
+1.  Justin Clarke	Social Ally Pty Ltd	8/29/13 	
+1.  H Wade Minter	TeamSnap	8/29/13 	
+1.  Kyle Ries	TeamSnap	8/29/13 	
+1.  Phillip Hutchins		8/30/13 	
+1.  Artem Kornienko		8/30/13 	
+1.  Ulf Mansson	Recorded Future	9/2/13 	
+1.  Sam Crang		8/31/13 	
+1.  Jorge Acosta Goszczynski		9/3/13 	
+1.  Lysenko Kostiantyn		9/4/13 	
+1.  Phil Sturgeon		9/4/13 	
+1.  Kamil Bednarz		9/4/13 	
+1.  Travis Petticrew		9/4/13 	
+1.  Peter Walz		8/29/13 	
+1.  Jeffrey Utter		9/4/13 	
+1.  Martin Cozzi		9/4/13 	
+1.  Andrew Thompson		9/4/13 	
+1.  Thomas von Schwerdtner		9/4/13 	
+1.  William Dierkes		9/4/13 	
+1.  Robin Ricard		9/5/13 	
+1.  Ben Longden		9/5/13 	
+1.  Alex Denvir	Protec Innovations Ltd.	9/5/13 	
+1.  Martin Meredith	Protec Innovations Ltd.	9/5/13 	
+1.  Phil Thompson	Protec Innovations Ltd.	9/5/13 	
+1.  Alejandro Blanco		9/5/13 	
+1.  Adrian Moisey		9/5/13 	
+1.  Alex Zorin		9/5/13 	
+1.  Robert Schulze		9/5/13 	
+1.  Wei Liang		9/5/13 	
+1.  Jon Torresdal		9/5/13 	
+1.  Sergii Golovatiuk		9/6/13 	
+1.  Mark O'Keefe		9/6/13 	
+1.  Brint O'Heam		9/6/13 	
+1.  Jim Myhrberg		9/7/13 	
+1.  James FitzGibbon		9/8/13 	
+1.  Isbaran Akcayir		9/9/13 	
+1.  Sylvain Tisso	Ecodev Sarl	9/9/13 	
+1.  Fabien Udriot	Ecodev Sarl	9/9/13 	
+1.  Adrien Crivelli	Ecodev Sarl	9/9/13 	
+1.  Yoshanda Shin		9/10/13 	
+1.  Christo De Lange		9/10/13 	
+1.  Arthur Freyman		9/10/13 	
+1.  Martin Walton		9/10/13 	
+1.  Matthew Brennan		9/10/13 	
+1.  Luis Ricardo Malheiros		9/11/13 	
+1.  Amir Kadivar		9/11/13 	
+1.  Davanum Srinivas		9/12/13 	
+1.  Jesse Pretorius		9/12/13 	
+1.  Denis Corol		9/12/13 	
+1.  Yevgen Kovalienia		9/12/13 	
+1.  Ben Hines		9/13/13 	
+1.  Muneyuki Noguchi		9/14/13 	
+1.  Myers Carpenter		9/16/13 	
+1.  Mathieu Allaire		9/16/13 	
+1.  Michael Stucki		9/17/13 	
+1.  Kevin Webster		9/17/13 	
+1.  Conor McDermottroe		9/17/13 	
+1.  Naoya Nakazawa		9/17/13 	
+1.  Mark Gibbons	Nordstrom	9/17/13 	
+1.  Matthew Moore		9/17/13 	
+1.  Ingo Kampe	kreuzwerker GmbH	9/18/13 	
+1.  Robert Conrad	kreuzwerker GmbH	9/18/13 	
+1.  Daniel Meisen	kreuzwerker GmbH	9/18/13 	
+1.  Alexander Dall	kreuzwerker GmbH	9/18/13 	
+1.  Jan Nabbefeld	kreuzwerker GmbH	9/18/13 	
+1.  Joern Barthel	kreuzwerker GmbH	9/18/13 	
+1.  Harvey Bandana	Nordstrom	9/18/13 	
+1.  Ben Holley		9/18/13 	
+1.  Yuji Takaesu		9/18/13 	
+1.  Colin Burn-Murdoch		9/20/13 	
+1.  Andrius Marcinkevicius		9/20/13 	
+1.  Alan Bryan	Central Desktop	9/18/13 	
+1.  Craig Lewis	Central Desktop	9/18/13 	
+1.  Saku Laitinen	Siili Solutions	9/19/13 	
+1.  Denis Barishev	Twiket LTD	9/23/13 	
+1.  Sam Orlov	Twiket LTD	9/23/13 	
+1.  Jarek Gawor	IBM	9/23/13 	
+1.  Anthony Elder	IBM	9/23/13 	
+1.  Michael C Thompson	IBM	9/23/13 	
+1.  Jeremy Hughes	IBM	9/23/13 	
+1.  Igor Rodionov		9/23/13 	
+1.  Gabor Garami		9/24/13 	
+1.  Iulia Banghea		9/24/13 	
+1.  Paul Dunnavant		9/24/13 	
+1.  Alex Heneveld	Cloudsoft Corp.	9/25/13 	
+1.  Jordi Massaguer Pla		9/25/13 	
+1.  Richard Downer	Cloudsoft Corp.	9/25/13 	
+1.  Roger Hu		9/25/13 	
+1.  Dominic St-Jacques		9/25/13 	
+1.  Mahmoud Abdelkader		9/26/13 	
+1.  Takahiro Himura		9/26/13 	
+1.  Aled Sage	Cloudsoft Corp.	9/25/13 	
+1.  Andrew Kennedy	Cloudsoft Corp.	9/25/13 	
+1.  Sam Corbett	Cloudsoft Corp.	9/25/13 	
+1.  Trevor Leybourne	MYOB NZ Limited	9/26/13 	
+1.  Greg Zapp	MYOB NZ Limited	9/26/13 	
+1.  Bo Ma	MYOB NZ Limited	9/26/13 	
+1.  Dmitry Lavrinenko		9/27/13 	
+1.  Vitaly Shishlyannikov		9/27/13 	
+1.  Jonathan Mickle		9/27/13 	
+1.  Scott Hain Jr		9/27/13 	
+1.  Ethan Fremen		9/29/13 	
+1.  Daniel O'Conner		9/29/13 	
+1.  Bill Wiens		9/30/13 	
+1.  Jeroen Grusebroek	Mollie B.V.	9/30/13 	
+1.  Morton Jonuschat		9/30/13 	
+1.  Bentrand Paquet		10/1/13 	
+1.  Christoph Hartmann		10/1/13 	
+1.  Okezie Eze		10/1/13 	
+1.  Christopher Dwan		10/1/13 	
+1.  Carl Schmidt	Unbounce	10/1/13 	
+1.  Aaron Oman	Unbounce	10/1/13 	
+1.  Chris Spicer	Unbounce	10/1/13 	
+1.  Jimmy Zheng	Unbounce	10/1/13 	
+1.  Josh Blancett		10/1/13 	
+1.  Stephen Romney	Shutl Ltd. 	10/2/13 	
+1.  James Wilford	Shutl Ltd. 	10/2/13 	
+1.  Sam Phillips	Shutl Ltd. 	10/2/13 	
+1.  Yomi Colledge	Shutl Ltd. 	10/2/13 	
+1.  Marco Nenciarini		10/2/13 	
+1.  Jake Herbst		10/2/13 	
+1.  Kawahara Masashi		10/2/13 	
+1.  Ilan Rabinovitch	Ooyala, Inc.	10/3/13 	
+1.  Garry Polley		10/3/13 	
+1.  Akshay Karle		10/3/13 	
+1.  Pascal Gelinas	Nu Echo	10/3/13 	
+1.  Salim Semaoune		10/3/13 	
+1.  August Schwer		10/4/13 	
+1.  Sam Adams		10/7/13 	
+1.  Niels Kristensen		10/7/13 	
+1.  Aliaksei Kliuchnikau		10/7/13 	
+1.  Theofilos Papapanagiotou		10/7/13 	
+1.  Mike Rossetti	Our Film Festival (dba Fandor)	10/7/13 	
+1.  Victor Lin		10/8/13 	
+1.  Tyler Kellen		10/8/13 	
+1.  Baba Buehler		10/8/13 	
+1.  Matt Clifton		10/8/13 	
+1.  Daniel Babel	Ooyala, Inc.	10/9/13 	
+1.  Jurgen Philippaerts	Ooyala, Inc.	10/9/13 	
+1.  Josh Toft	Ooyala, Inc.	10/9/13 	
+1.  Tobias Maier	BauCloud GmbH	10/9/13 	
+1.  Ryota Arai		10/9/13 	
+1.  Kyle Kelley		10/10/13 	
+1.  Jaroslav Barton		10/10/13 	
+1.  Sam Pointer		10/10/13 	
+1.  Sebastian Guevara		10/10/13 	
+1.  Paul Welch	Squaremouth Inc	10/10/13 	
+1.  Peter Georgantas		10/10/13 	
+1.  Karla Jacobsen		10/10/13 	
+1.  Ryan S Brown		10/10/13 	
+1.  Richard Manyanza		10/11/13 	
+1.  Guilhem Lettron	Optiflows	10/11/13 	
+1.  Ludovic Havel	Optiflows	10/11/13 	
+1.  Jean Rouge		10/11/13 	
+1.  Devon Jones		10/11/13 	
+1.  Matthew Kasa		10/11/13 	
+1.  James Moorhouse		10/12/13 	
+1.  Christopher Grim		10/12/13 	
+1.  Ryan Frantz		10/14/13 	
+1.  Shrikant Patnaik	General Sensing LTD	10/10/13 	
+1.  Aaron Valade	General Sensing LTD	10/10/13 	
+1.  Chris Jerdonek		10/13/13 	
+1.  EJ Ciramella	Rapid7	10/14/13 	
+1.  Brandon Turner	Rapid7	10/14/13 	
+1.  Chris Smtih	Rapid7	10/14/13 	
+1.  Ben Tomasini		10/14/13 	
+1.  Evan Todd		10/15/13 	
+1.  Alex Shadrin		10/15/13 	
+1.  Mart Karu		10/15/13 	
+1.  Russell Cardullo		10/15/13 	
+1.  John Tran		10/15/13 	
+1.  Alex Koch		10/15/13 	
+1.  Jonathan Regeimbal		10/15/13 	
+1.  James Walker		10/16/13 	
+1.  Justin Dugger		10/16/13 	
+1.  Dustin Collins		10/16/13 	
+1.  Matthew Boedicker		10/17/13 	
+1.  John Deatherage		10/17/13 	
+1.  Aaron Jensen		10/17/13 	
+1.  Olksandr Slynko		10/17/13 	
+1.  Emanuele Rocca		10/18/13 	
+1.  Antonio Fernandez Vara		10/18/13 	
+1.  Mickhail Zholobov		10/18/13 	
+1.  Daniel Wallace	Rackspace	10/18/13 	
+1.  Christian Fischer		10/18/13 	
+1.  Silviu Dicu		10/18/13 	
+1.  William Pietri		10/19/13 	
+1.  Daniel Tracy		10/21/13 	
+1.  Ashish Shinde		10/22/13 	
+1.  Mathew Hoyle	Deployable LTD	10/22/13 	
+1.  Leonardo Leite	 	10/22/13 	
+1.  Michael Dore		10/22/13 	
+1.  Hannes Van De Vreken		10/22/13 	
+1.  Mevan Samaratunga		10/22/13 	
+1.  Adam Enger		10/22/13 	
+1.  Peter Jönsson	Klarna	10/23/13 	
+1.  Carl Loa Odin	Klarna	10/23/13 	
+1.  Olle Lundberg	Klarna	10/23/13 	
+1.  Pat Downey		10/24/13 	
+1.  Max Lincoln		10/24/13 	
+1.  Pavel Brylov		10/24/13 	
+1.  Sam Clements		10/25/13 	
+1.  Gabriel Mazetto		10/25/13 	
+1.  Cory Gunterman	Nike, Inc.	10/25/13 	
+1.  Justin Redd	Nike, Inc.	10/25/13 	
+1.  Dave Palomino	Nike, Inc.	10/25/13 	
+1.  Tom Luce	Nike, Inc.	10/25/13 	
+1.  Shawn Turpin	Nike, Inc.	10/25/13 	
+1.  Ed Tretyakov		10/27/13 	
+1.  Frank Breedijk	Schuberg Phillis B.V.	10/28/13 	
+1.  Henry Finucane		10/30/13 	
+1.  Thomas de Grenier de Latour		10/30/13 	
+1.  Andrey Chernih		10/30/13 	
+1.  Matt Wormley		10/30/13 	
+1.  Maciej Galkiewicz		10/31/13 	
+1.  Makiko Nomura		11/1/13 	
+1.  Cheah Chu Yeow	Irrational Industries, Inc.	11/1/13 	
+1.  Christian Paredes	Irrational Industries, Inc.	11/1/13 	
+1.  Rafael Kolless		11/2/13 	
+1.  Zsolt Takacs		11/2/13 	
+1.  Tobias Schmidt	SoundCloud Ltd.	11/5/13 	
+1.  Frederick Jaeckel	SoundCloud Ltd.	11/5/13 	
+1.  Matthias Rampke	SoundCloud Ltd.	11/5/13 	
+1.  Daman Yang	SoundCloud Ltd.	11/5/13 	
+1.  Ben Kochie	SoundCloud Ltd.	11/5/13 	
+1.  Alexander Grosse	SoundCloud Ltd.	11/5/13 	
+1.  Allan Beaufour	Project Florida	11/5/13 	
+1.  Jow Crobak	Project Florida	11/5/13 	
+1.  Derek Groh		11/5/13 	
+1.  David Shawley		11/5/13 	
+1.  Jason Faulkner		11/5/13 	
+1.  Cheryl Ainoa	Intuit	11/6/13 	
+1.  Thomas Bishop	Intuit	11/6/13 	
+1.  Jeffrey Mendoza		11/6/13 	
+1.  Munirathnam Srikanth	ComputeNext	11/6/13 	
+1.  Sergio Patino		11/6/13 	
+1.  Andrew Caldwell		11/6/13 	
+1.  Alex Derzhi		11/7/13 	
+1.  Olivier Biesmans		11/7/13 	
+1.  Gabriel Rosendorf	The Weather Companies	11/8/13 	
+1.  Nathaniel Eliot		11/9/13 	
+1.  Thibaut Notteboom		11/10/13 	
+1.  Walter Huf		11/11/13 	
+1.  David Larken Nolen		11/11/13 	
+1.  Makana Greenwell		11/12/13 	
+1.  Mathew Hartley		11/12/13 	
+1.  Julie Rice	PTC Inc	11/13/13 	
+1.  Matt Welch	PTC Inc	11/13/13 	
+1.  Jonathan Bass	PTC Inc	11/13/13 	
+1.  Joe Rocklin		11/14/13 	
+1.  Zaininnari		11/14/13 	
+1.  Jean Mertz		11/18/13 	
+1.  Gleb Borisov		11/19/13 	
+1.  Curtis Stewart		11/19/13 	
+1.  Jim Park	RamTank Inc	11/19/13 	
+1.  Pierre Ynard	Criteo	11/19/13 	
+1.  Sergey Balbeko		11/20/13 	
+1.  Igor Serko		11/20/13 	
+1.  Jason Giedymin		11/20/13 	
+1.  Luca Pradovera		11/20/13 	
+1.  Jason Giedymin		11/20/13 	
+1.  Shaun Rowe		11/21/13 	
+1.  Chad Cloes	Intuit	11/21/13 	
+1.  Rick Mendes	Intuit	11/21/13 	
+1.  Grant Hoffman	Intuit	11/21/13 	
+1.  Capen Brinkley	Intuit	11/21/13 	
+1.  Kevin Young	Intuit	11/21/13 	
+1.  Walter Askew IV		11/22/13 	
+1.  Spencer Smith		11/23/13 	
+1.  Spencer Smith		11/23/13 	
+1.  Connor Goodwolf		11/23/13 	
+1.  Seiji Komatsu		11/24/13 	
+1.  Steve Domin	GoCardless	11/24/13 	
+1.  Milos Gajdos	GoCardless	11/24/13 	
+1.  Harry Marr	GoCardless	11/24/13 	
+1.  Komatsu Seiji		11/25/13 	
+1.  Gokulnath Manakkattil		11/26/13 	
+1.  Joel Moss		11/27/13 	
+1.  Drew J. Sonne		11/30/13 	
+1.  Sascha Mollering	ZANOX AG	11/30/13 	
+1.  Boris Komraz		12/1/13 	
+1.  Mark O'Connor		12/1/13 	
+1.  Ivan Larionov		12/2/13 	
+1.  Pierre Carrier		12/2/13 	
+1.  Joe A. Kemp	ARINC	12/3/13 	
+1.  Douglas Mendizabal		12/3/13 	
+1.  Tejay Cardon	Lockheed Martin Corporation	12/3/13 	
+1.  David Deal	Lockheed Martin Corporation	12/3/13 	
+1.  Jason Loveland	Lockheed Martin Corporation	12/3/13 	
+1.  Friedrich Clausen		12/4/13 	
+1.  Paul Kehrer		12/4/13 	
+1.  Stephan Renatus		12/5/13 	
+1.  Abhijit Hiremagalur		12/5/13 	
+1.  Wojciech Oledzki		12/5/13 	
+1.  Johannes Plunien		12/7/13 	
+1.  Benjamin Demaree		12/8/13 	
+1.  Friedel Ziegelmayer		12/13/13 	
+1.  Jason Vervlied		12/13/13 	
+1.  Fabian Lee		12/15/13 	
+1.  Tino Breddin		12/16/13 	
+1.  Cameron Cope	Brightcove	12/16/13 	
+1.  Jason Perry	Brightcove	12/16/13 	
+1.  Eric Moakley	Brightcove	12/16/13 	
+1.  Joshua Spiewak	Brightcove	12/16/13 	
+1.  John Schectman	Brightcove	12/16/13 	
+1.  Keegan Holley		12/16/13 	
+1.  James La Spada		12/17/13 	
+1.  Jesué Sousa Cunha Junior		12/17/13 	
+1.  Dan Rathbone		12/17/13 	
+1.  Jay Geeseman		12/19/13 	
+1.  David Bernick		12/20/13 	
+1.  Primož Verdnik		12/20/13 	
+1.  Yavor Nikolov		12/26/13 	
+1.  Joseph C. Stump	Sprint.ly, Inc	12/27/13 	
+1.  Justin T. Abrahms	Sprint.ly, Inc	12/27/13 	
+1.  Theodore Chuong Nordsieck		12/29/13 	
+1.  Thomas Noonan II		12/30/13 	
+1.  Coman Ioan Andrei		12/30/13 	
+1.  Steven Geerts	Schuberg Phillis B.V.	1/2/14 	
+1.  Scott Russell		1/3/14 	
+1.  Lothar Wieske		1/3/14 	
+1.  Paul Czarkowski		1/3/14 	
+1.  Ramil Lim		1/3/14 	
+1.  Jeff Byrnes		1/3/14 	
+1.  Christopher James Saylor		1/4/14 	
+1.  Gary Cao		1/6/14 	
+1.  Christopher William Pernicano		1/6/14 	
+1.  Emmanuel Idi		1/6/14 	
+1.  Reid Beels		1/7/14 	
+1.  Anthony LoBono		1/8/14 	
+1.  Barthélemy Vessemont		1/10/14 	
+1.  Michael Holtzman		1/10/14 	
+1.  Tristan O'Neil	Cramer Development	1/10/14 	
+1.  Brian Cobb	Cramer Development	1/10/14 	
+1.  Brett Chalupa	Cramer Development	1/10/14 	
+1.  Dan Volkens	Cramer Development	1/10/14 	
+1.  Ryan Keairns	Cramer Development	1/10/14 	
+1.  Nikhil Benesch		1/12/14 	
+1.  Christian Höltje		1/13/14 	
+1.  Alexander C Corvin		1/17/14 	
+1.  Samuel Chambers		1/18/14 	
+1.  Cheah Chu Yeow		1/18/14 	
+1.  Kazuki Saito		1/18/14 	
+1.  Pete Richards		1/19/14 	
+1.  Jimmy McCrory		1/19/14 	
+1.  Olivier Dolbeau		1/20/14 	
+1.  Andrew Brown	BlackBerry, Inc.	1/20/14 	
+1.  Phil Oliva	BlackBerry, Inc.	1/20/14 	
+1.  Dave Urschatz	BlackBerry, Inc.	1/20/14 	
+1.  Ishtiaq Ahmed		1/25/14 	
+1.  Caleb Land		1/26/14 	
+1.  Charles B Johnson		1/26/14 	
+1.  Diego Rodriguez		1/27/14 	
+1.  Nitin Mohan		1/27/14 	
+1.  Szymon Szypulski		1/29/14 	
+1.  Jaime Gil de Sagredo		1/29/14 	
+1.  Jose Luis Ferrer Riera		1/29/14 	
+1.  Yury Velikanau		1/29/14 	
+1.  Jeroen Jacobs		1/30/14 	
+1.  W. Hart Hoover	Rackspace	2/3/14 	
+1.  Jerry Richardson	Disruptive Ventures, Inc	2/4/14 	
+1.  Brian Dwyer		2/4/14 	
+1.  Aaron O'Mullan	FriendCode, Inc	2/5/14 	
+1.  Jean-Baptiste Dalido		2/6/14 	
+1.  Juri Timoshin		2/6/14 	
+1.  Pascal Laporte		2/6/14 	
+1.  Steven Cummings	Cerner Innovation Inc	2/6/14 	
+1.  Pascal Laporte		2/6/14 	
+1.  Mick Brooks		2/7/14 	
+1.  Aurélien Noce		2/7/14 	
+1.  Charlie Huggard	Cerner Innovation Inc	2/11/14 	
+1.  Matthias Arnason	Engine Yard	2/12/14 	
+1.  Bryan Taylor		2/12/14 	
+1.  Michael Dillion		2/17/14 	
+1.  Seth Kingry		2/18/14 	
+1.  Wesley David DeCesare	Crux Hosted Services	2/18/14 	
+1.  Kent Shultz		2/18/14 	
+1.  Adam Durana		2/21/14 	
+1.  Jacob McCann		2/21/14 	
+1.  Andriy Tyurnikov		2/21/14 	
+1.  Anton Koldaev		2/21/14 	
+1.  Matthew Rathbone		2/21/14 	
+1.  Egor Medvedev		2/23/14 	
+1.  Eric Tucker	Blue Spurs	2/24/14 	
+1.  Tomas Gutierrez		2/24/14 	
+1.  Jordan Burke		2/25/14 	
+1.  Zvi Effron		2/25/14 	
+1.  Pranay Manwatkar		2/26/14 	
+1.  Kaspars Mickevics		2/26/14 	
+1.  Roman Gorodeckij		2/27/14 	
+1.  Matthew Baxa		2/27/14 	
+1.  Maxime Caumartin		2/27/14 	
+1.  Brandon Raabe		2/28/14 	
+1.  Alan Grosskurth		2/28/14 	
+1.  Nathan Milford		2/28/14 	
+1.  Jacob Vosmaer	GitLab.com	3/1/14 	
+1.  Job van der Voort	GitLab.com	3/1/14 	
+1.  Marin Jankovski	GitLab.com	3/1/14 	
+1.  Martin Glaß		3/1/14 	
+1.  Sergey Sergeev		3/1/14 	
+1.  Marshall Ian Farmer		3/2/14 	
+1.  Markus Schabel		3/3/14 	
+1.  Torben Knerr		3/4/14 	
+1.  Pavel Sadikov		3/5/14 	
+1.  David King		3/7/14 	
+1.  Charles Guenther	Yelp	3/7/14 	
+1.  Kris Wehner	Yelp	3/7/14 	
+1.  Brian Fletcher	Workday	3/10/14 	
+1.  Brad Pokorny	IBM	3/10/14 	
+1.  John Warren	IBM	3/10/14 	
+1.  Lance Bragstad	IBM	3/10/14 	
+1.  Luis Garcia	IBM	3/10/14 	
+1.  Mark Vanderwiel	IBM	3/10/14 	
+1.  Mathew Odden	IBM	3/10/14 	
+1.  Andrew Coulton		3/11/14 	
+1.  Andrew Ordiales		3/11/14 	
+1.  Will Hattingh		3/12/14 	
+1.  Eohyung Lee		3/13/14 	
+1.  Matthew Zito	BMC Software Inc	3/13/14 	
+1.  Nick Galbreath		3/13/14 	
+1.  Thomas Duckering		3/14/14 	
+1.  Stanley Halka		3/14/14 	
+1.  Michael Morris		3/14/14 	
+1.  Gavin Montague	itison	3/14/14 	
+1.  John Daniels	itison	3/14/14 	
+1.  Matthias Endler		3/17/14 	
+1.  Greg Albrecht	OnBeep, Inc.	3/19/14 	
+1.  Andy Issacson	OnBeep, Inc.	3/19/14 	
+1.  Ben Graver	OnBeep, Inc.	3/19/14 	
+1.  Jim Qin	OnBeep, Inc.	3/19/14 	
+1.  Carlos Vinueza	OnBeep, Inc.	3/19/14 	
+1.  Benson Miller	Level 11 Consulting	3/19/14 	
+1.  Nik Ormseth	Level 11 Consulting	3/19/14 	
+1.  James Francis	Level 11 Consulting	3/19/14 	
+1.  Kevin Rivers	Level 11 Consulting	3/19/14 	
+1.  Michael Dellanoce		3/20/14 	
+1.  Joey Line		3/21/14 	
+1.  Nick Lopez		3/22/14 	
+1.  Jason Byck		3/23/14 	
+1.  Ian Neubert		3/25/14 	
+1.  Brandon Taylor Groves		3/25/14 	
+1.  Sean Walberg		3/25/14 	
+1.  Matthijs Wijers		3/26/14 	
+1.  Tensibai Zhaoying		3/26/14 	
+1.  Michael Chletso		3/27/14 	
+1.  Joseph Korkames		3/27/14 	
+1.  Matthew Juszczak		3/27/14 	
+1.  Hongbin Lu		3/27/14 	
+1.  Ryan Lewon		3/28/14 	
+1.  Tiru Srikantha		3/29/14 	
+1.  Calvin Worsnup		3/31/14 	
+1.  Andres More		4/1/14 	
+1.  Joe Richards		4/1/14 	
+1.  Mikael Henriksson		4/2/14 	
+1.  Benjamin Dalton LeMasurier		4/2/14 	
+1.  Dirk Moermans		4/3/14 	
+1.  Pavel Yudin		4/4/14 	
+1.  Ed Neville	Linaro Limited	4/4/14 	
+1.  Andrew McDermott	Linaro Limited	4/4/14 	
+1.  Ron Nandy	Linaro Limited	4/4/14 	
+1.  Florian Holzhauer		4/4/14 	
+1.  Joshua Yotty		4/4/14 	
+1.  Narendra V Dharmavarapu		4/4/14 	
+1.  Brian Wilson Leake		4/6/14 	
+1.  John Northrup		4/7/14 	
+1.  Yoichi Isozaki		4/7/14 	
+1.  Jordan Evans		4/8/14 	
+1.  Oliver Kohl		4/9/14 	
+1.  Craig Monson		4/10/14 	
+1.  Rob Brown		4/10/14 	
+1.  Alexander Myasnikov		4/11/14 	
+1.  Matthew Hodgkins		4/12/14 	
+1.  Aaron Quint		4/12/14 	
+1.  Jaewoo Kim		4/17/14 	
+1.  Vasiliy Tolstov		4/17/14 	
+1.  Ryan Moe		4/18/14 	
+1.  G. Panula		4/21/14 	
+1.  Chris Antenesse		4/21/14 	
+1.  Lloyd Chan		4/22/14 	
+1.  Satoshi Tanaka		4/22/14 	
+1.  Tim Heckman		4/24/14 	
+1.  Trevor Lauder		4/25/14 	
+1.  Nathan Haneysmith	Nordstrom	4/25/14 	
+1.  Aaron Lane		4/26/14 	
+1.  Bao Nguyen		4/27/14 	
+1.  Salvatore Poliandro III		4/28/14 	
+1.  Eric Zhoe		4/29/14 	
+1.  Alex Kahn		4/29/14 	
+1.  Brendan Murtagh		4/29/14 	
+1.  Tyler Cipriani		4/29/14 	
+1.  Syunsuke Komma	WESEEK	4/29/14 	
+1.  Yuki Takei	WESEEK	4/29/14 	
+1.  Trevor Bramwell		5/1/14 	
+1.  Robert Tarrall		5/1/14 	
+1.  Josh Reichardt		5/1/14 	
+1.  Trevor Lauder	Intuit	5/1/14 	
+1.  Jake Plimack		5/2/14 	
+1.  Brian D Clark		5/3/14 	
+1.  Roman Chukh		5/4/14 	
+1.  Nick Montgomery		5/4/14 	
+1.  Patrick Moore		5/5/14 	
+1.  Edmund Dipple		5/6/14 	
+1.  Kyle Boorky		5/6/14 	
+1.  Olivier Larivain		5/6/14 	
+1.  Aaron Valade		5/7/14 	
+1.  Jonathan Serafini		5/7/14 	
+1.  Jason Nelson	Rackspace	5/8/14 	
+1.  Alexander Meng		5/8/14 	
+1.  Kyle McGovern	Cerner Innovation Inc	5/8/14 	
+1.  Jesse Washburn		5/8/14 	
+1.  Ian Blenke		5/9/14 	
+1.  Jochen Seeber		5/9/14 	
+1.  Florin Stan		5/9/14 	
+1.  Bearnard Hibbins		5/12/14 	
+1.  Amruta Krishna	Cerner Innovation Inc	5/13/14 	
+1.  Daniel Zautner		5/13/14 	
+1.  Andrew DuFour		5/13/14 	
+1.  David Gil Oliva		5/19/14 	
+1.  Emmanuel Sciara		5/20/14 	
+1.  Francois Visconte		5/21/14 	
+1.  Cyril Scetbon		5/21/14 	
+1.  Doug Wilson	CustomInk	4/4/14 	
+1.  Meherez Alachheb		5/22/14 	
+1.  Ash Wilson	Rackspace	5/22/14 	
+1.  Alexey Velikiy		5/21/14 	
+1.  Anand Suresh		5/24/14 	
+1.  Christoph Krämer		5/26/14 	
+1.  Marcus Nilsson		5/27/14 	
+1.  Eric Black		5/27/14 	
+1.  Michiel Sikkes		5/29/14 	
+1.  Miguel Landaeta		5/29/14 	
+1.  Claude Ballew Jr		5/29/14 	
+1.  Carlos Macasaet		5/29/14 	
+1.  Steve Jansen		6/3/14 	
+1.  Jake Champlin		6/4/14 	
+1.  Alistair Stead	Iniqa UK, Ltd	6/4/14 	
+1.  Fahd Sultan		6/4/14 	
+1.  Martin Smith III	Rackspace	6/4/14 	
+1.  Klaas Jan Wierenga		6/5/14 	
+1.  Michael Bumann		6/6/14 	
+1.  Grant Hudgens		6/6/14 	
+1.  Rob Redpath	World Wide Web Hosting, LLC	6/6/14 	
+1.  Benjamin Ahrens		6/9/14 	
+1.  Alessio Franceschelli		6/10/14 	
+1.  Joseph Bowman		6/11/14 	
+1.  William Cody Crawford		6/11/14 	
+1.  Ryan Trauntvein		6/12/14 	
+1.  Adam Lavin		6/14/14 	
+1.  Brett Cave	Jemstep	6/13/14 	
+1.  Matt Wrock		6/16/14 	
+1.  William Clark		6/17/14 	
+1.  Karsten McMinn		6/17/14 	
+1.  Alexander Simonov		6/17/14 	
+1.  James Coleman		6/18/14 	
+1.  Charles Ruhl		6/18/14 	
+1.  Pushkar Subhash Raste		6/19/14 	
+1.  John Coleman		6/20/14 	
+1.  Joshua Rutherford		6/20/14 	
+1.  Elijah Buck		6/21/14 	
+1.  Nikalai Stakanov		6/22/14 	
+1.  Blair Hamilton		6/22/14 	
+1.  Jeffrey Goldschrafe		6/24/14 	
+1.  Vijay Bheemineni		6/25/14 	
+1.  Joshua Benjamin		6/25/14 	
+1.  Stafford Brunk		6/25/14 	
+1.  Sumit Gupta		6/26/14 	 	
+1.  Jan Mara		6/27/14
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cc41653..b2f9ece 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,7 +11,7 @@ We utilize **Github Issues** for issue tracking and contributions. You can contr
 
 We have a 3 step process that utilizes **Github Issues**:
 
-1. Sign or be added to an existing [Contributor License Agreement (CLA)](https://supermarket.getchef.com/become-a-contributor).
+1. Sign or be added to an existing [Contributor License Agreement (CLA)](https://supermarket.chef.io/become-a-contributor).
 2. Create a Github Pull Request.
 3. Do [Code Review](#cr) with the **Chef Engineering Team** or **Chef Core Committers** on the pull request.
 
@@ -21,7 +21,7 @@ Chef is built to last. We strive to ensure high quality throughout the Chef expe
   this, we require a couple of things for all pull requests to Chef:
 
 1. **Tests:** To ensure high quality code and protect against future regressions, we require all the
-  code in Chef to have at least unit test coverage. See the [spec/unit](https://github.com/opscode/chef/tree/master/spec/unit)
+  code in Chef to have at least unit test coverage. See the [spec/unit](https://github.com/chef/chef/tree/master/spec/unit)
   directory for the existing tests and use ```bundle exec rake spec``` to run them.
 2. **Green Travis Run:** We use [Travis CI](https://travis-ci.org/) in order to run our tests
   continuously on all the pull requests. We require the Travis runs to succeed on every pull
@@ -63,14 +63,14 @@ You can watch the recordings of the old Code Review hangouts on the [opscodebtm]
 Licensing is very important to open source projects. It helps ensure the
   software continues to be available under the terms that the author desired.
 
-Chef uses [the Apache 2.0 license](https://github.com/opscode/chef/blob/master/LICENSE)
+Chef uses [the Apache 2.0 license](https://github.com/chef/chef/blob/master/LICENSE)
   to strike a balance between open contribution and allowing you to use the
   software however you would like to.
 
 The license tells you what rights you have that are provided by the copyright holder.
   It is important that the contributor fully understands what rights they are
   licensing and agrees to them. Sometimes the copyright holder isn't the contributor,
-  most often when the contributor is doing work for a company.
+  such as when the contributor is doing work for a company.
 
 To make a good faith effort to ensure these criteria are met, Chef requires an Individual CLA
   or a Corporate CLA for contributions. This agreement helps ensure you are aware of the
@@ -81,10 +81,10 @@ To make a good faith effort to ensure these criteria are met, Chef requires an I
 It only takes a few minutes to complete a CLA, and you retain the copyright to your contribution.
 
 You can complete our
-  [Individual CLA](https://supermarket.getchef.com/icla-signatures/new) online.
+  [Individual CLA](https://supermarket.chef.io/icla-signatures/new) online.
   If you're contributing on behalf of your employer and they retain the copyright for your works,
   have your employer fill out our
-  [Corporate CLA](https://supermarket.getchef.com/ccla-signatures/new) instead.
+  [Corporate CLA](https://supermarket.chef.io/ccla-signatures/new) instead.
 
 ### Chef Obvious Fix Policy
 
@@ -109,7 +109,7 @@ As a rule of thumb, changes are obvious fixes if they do not introduce any new f
 ```
 ------------------------------------------------------------------------
 commit 370adb3f82d55d912b0cf9c1d1e99b132a8ed3b5
-Author: danielsdeleo <dan at opscode.com>
+Author: danielsdeleo <dan at chef.io>
 Date:   Wed Sep 18 11:44:40 2013 -0700
 
   Fix typo in config file docs.
@@ -126,16 +126,16 @@ Chef Issue Tracking is handled using Github Issues.
 If you are familiar with Chef and know the component that is causing you a problem or if you
   have a feature request on a specific component you can file an issue in the corresponding
   Github project. All of our Open Source Software can be found in our
-  [Github organization](https://github.com/opscode/).
+  [Github organization](https://github.com/chef/).
 
 There is also a listing of the various Chef products and where to file issues that can be
   found in the Chef docs in the [community contributions section](https://docs.chef.io/community_contributions.html#issues-and-bug-reports).
 
-Otherwise you can file your issue in the [Chef project](https://github.com/opscode/chef/issues)
+Otherwise you can file your issue in the [Chef project](https://github.com/chef/chef/issues)
   and we will make sure it gets filed against the appropriate project.
 
-In order to decrease the back and forth an issues and help us get to the bottom of them quickly
-  we use below issue template. You can copy paste this code into the issue you are opening and
+In order to decrease the back and forth in issues, and to help us get to the bottom of them quickly
+  we use the below issue template. You can copy/paste this template into the issue you are opening and
   edit it accordingly.
 
 <a name="issuetemplate"></a>
@@ -148,33 +148,29 @@ In order to decrease the back and forth an issues and help us get to the bottom
 ### Scenario:
 [What you are trying to achieve and you can't?]
 
-
-
 ### Steps to Reproduce:
 [If you are filing an issue what are the things we need to do in order to repro your problem?]
 
-
 ### Expected Result:
 [What are you expecting to happen as the consequence of above reproduction steps?]
 
-
 ### Actual Result:
 [What actually happens after the reproduction steps?]
 ```
 
 ### Useful Github Queries
 
-Contributions go through a review process to improve code quality and avoid regressions. Managing a large number of contributions requires a workflow to provide queues for work such as triage, code review, and merging. A semi-formal process has evolved over the life of the project. Chef maintains this process pending community development and acceptance of an [RFC](https://github.com/opscode/chef-rfc). These queries will help track contributions through this process:
+Contributions go through a review process to improve code quality and avoid regressions. Managing a large number of contributions requires a workflow to provide queues for work such as triage, code review, and merging. A semi-formal process has evolved over the life of the project. Chef maintains this process pending community development and acceptance of an [RFC](https://github.com/chef/chef-rfc). These queries will help track contributions through this process:
 
-* [Issues that are not assigned to a team](https://github.com/opscode/chef/issues?q=is%3Aopen+-label%3AAIX+-label%3ABSD+-label%3Awindows+-label%3A%22Chef+Core%22++-label%3A%22Dev+Tools%22+-label%3AUbuntu+-label%3A%22Enterprise+Linux%22+-label%3A%22Ready+For+Merge%22+-label%3AMac+-label%3ASolaris+)
-* [Untriaged Issues](https://github.com/opscode/chef/issues?q=is%3Aopen+is%3Aissue+-label%3ABug+-label%3AEnhancement+-label%3A%22Tech+Cleanup%22+-label%3A%22Ready+For+Merge%22)
-* [PRs to be Reviewed](https://github.com/opscode/chef/labels/Pending%20Maintainer%20Review)
-* [Suitable for First Contribution](https://github.com/opscode/chef/labels/Easy)
+* [Issues that are not assigned to a team](https://github.com/chef/chef/issues?q=is%3Aopen+-label%3AAIX+-label%3ABSD+-label%3Awindows+-label%3A%22Chef+Core%22++-label%3A%22Dev+Tools%22+-label%3AUbuntu+-label%3A%22Enterprise+Linux%22+-label%3A%22Ready+For+Merge%22+-label%3AMac+-label%3ASolaris+)
+* [Untriaged Issues](https://github.com/chef/chef/issues?q=is%3Aopen+is%3Aissue+-label%3ABug+-label%3AEnhancement+-label%3A%22Tech+Cleanup%22+-label%3A%22Ready+For+Merge%22)
+* [PRs to be Reviewed](https://github.com/chef/chef/labels/Pending%20Maintainer%20Review)
+* [Suitable for First Contribution](https://github.com/chef/chef/labels/Easy)
 
 ## <a name="release"></a> Chef Release Cycles
 
 Our primary shipping vehicle is operating system specific packages that includes
-  all the requirements of Chef. We call these [Omnibus packages](https://github.com/opscode/omnibus-ruby)
+  all the requirements of Chef. We call these [Omnibus packages](https://github.com/chef/omnibus)
 
 We also release our software as gems to [Rubygems](https://rubygems.org/) but we strongly
   recommend using Chef packages since they are the only combination of native libraries &
@@ -194,7 +190,7 @@ We frequently make `alpha` and `beta` releases with version numbers that look li
 We do a `Minor` release approximately every 3 months and `Patch` releases on a when-needed
   basis for regressions, significant bugs, and security issues.
 
-Announcements of releases are available on [Chef Blog](http://www.getchef.com/blog) when they are
+Announcements of releases are available on [Chef Blog](http://www.chef.io/blog) when they are
   available.
 
 ## Chef Community
@@ -207,6 +203,6 @@ Chef is made possible by a strong community of developers and system administrat
 
 Also here are some additional pointers to some awesome Chef content:
 
-* [Chef Docs](http://docs.opscode.com/)
-* [Learn Chef](https://learnchef.opscode.com/)
-* [Chef Inc](http://www.getchef.com/)
+* [Chef Docs](https://docs.chef.io/)
+* [Learn Chef](https://learn.chef.io/)
+* [Chef Inc](https://www.chef.io/)
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md
new file mode 100644
index 0000000..79d60b8
--- /dev/null
+++ b/DOC_CHANGES.md
@@ -0,0 +1,133 @@
+<!---
+This file is reset every time a new release is done. This file describes changes that have not yet been released.
+
+Example Doc Change:
+### Headline for the required change
+Description of the required change.
+-->
+
+### `chef_version` and `ohai_version`
+
+see: https://docs.chef.io/release/12-6/release_notes.html#new-metadata-rb-settings
+
+The metadata.rb DSL is extended to support `chef_version` and `ohai_version` to establish ranges
+of chef and ohai versions that the cookbook supports.
+
+When the running chef or ohai version does not match, then the chef-client run will abort with an
+exception immediately after cookbooks have been synchronized before any cookbook contents are
+parsed.
+
+The format of the dependencies is based on rubygems (and implemented with rubygems code).  Pessimistic
+version constraints, floor and ceiling constraints, and specifying multiple constraints are all valid.
+
+Examples:
+
+```
+# matches any 12.x version, but not 11.x or 13.x
+chef_version "~> 12"
+```
+
+```
+# matches any 12.x, 13.x, etc version
+chef_version ">= 12"
+```
+
+```
+# matches any chef 12 version >= 12.5.1 or any chef 13 version
+chef_version ">= 12.5.1", "< 14.0"
+```
+
+```
+# matches chef 11 >= 11.18.4 or chef 12 >= 12.5.1 (i.e. depends on a backported bugfix)
+chef_version ">= 11.18.12", "< 12.0"
+chef_version ">= 12.5.1", "< 13.0"
+```
+
+As seen in the last example multiple constraints are OR'd.
+
+There is currently no support in supermarket for making this metadata visible in /universe to
+depsolvers, or support in Berksfile/PolicyFile for automatically pruning cookbooks that fail
+to match.
+
+### `ksh` resources
+
+Use the ksh resource to execute scripts using the Korn shell (ksh) interpreter.
+This resource may also use any of the actions and properties that are available
+to the execute resource.
+
+Example:
+```ruby
+ksh 'hello world' do
+  code <<-EOH
+    echo "Hello world!"
+    echo "Current directory: " $cwd
+    EOH
+end
+```
+
+See https://docs.chef.io/release/12-6/resource_ksh.html for more info.
+
+### `dsc_resource` resource
+
+Added reboot_action attribute to dsc_resource.
+
+If the DSC resource indicates that it requires a reboot, reboot_action can use the reboot resource to
+either reboot immediately (:reboot_now) or queue a reboot (:request_reboot).  The default value of reboot_action is :nothing.
+
+The following two items in the dsc_resource doc in Chef 12.6.0 are ONLY applicable for PowerShell versions earlier than 5.0.10586.0. The latest version of WMF 5 has relaxed the limitation that prevented us from running in non-disabled RefreshMode configuration, and including both dsc_script and dsc_resource in the same run list:
+1. The RefreshMode configuration setting in the Local Configuration Manager must be set to Disabled
+2. The dsc_script resource may not be used in the same run-list with the dsc_resource. This is because the dsc_script resource requires that RefreshMode in the Local Configuration Manager be set to Push, whereas the dsc_resource resource requires it to be set to Disabled
+
+
+### `knife bootstrap --ssh-identity-file`
+
+The --identity-file option to `knife bootstrap` has been deprecated in favor of `knife bootstrap --ssh-identity-file`
+to better align with other ssh related options.
+
+### `windows_package` resource
+
+`windows_package` now supports more than just `MSI`. Most common windows installer types are supported including Inno Setup, Nullsoft, Wise and InstallShield. The new allowed `installer_type` values are: `inno`, `nsis`, `wise`, `installshield`, `custom`, and `msi`.
+
+**Non `:msi` package installation**
+When installing non `:msi` packages, the `package_name` should match the display name used for the installed package in the "Add/Remove Programs" settings application. This value can also be found in the following registry locations:
+* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
+* HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall
+* HKEY_LOCAL_MACHINE\Software\Wow6464Node\Microsoft\Windows\CurrentVersion\Uninstall
+
+ Further, non `:msi` packages must explicitly include a package `source` attribute when using the `:install` action. Unlike `:msi` packages, they will not default to the package name if missing. Without the name matching the software's display name, non `:msi` packages will always reconverge on `:install`.
+
+Also, while being able to download remote installers from a `HTTP` resource is not new, it looks as though the top of the docs page is incorrect stating that only local installers can be used as a source.
+
+Example Nullsoft (`nsis`) package resource:
+```
+package 'Mercurial 3.6.1 (64-bit)' do
+  source 'http://mercurial.selenic.com/release/windows/Mercurial-3.6.1-x64.exe'
+  checksum 'febd29578cb6736163d232708b834a2ddd119aa40abc536b2c313fc5e1b5831d'
+end
+```
+
+Example Custom `windows_package` resource:
+```
+package 'Microsoft Visual C++ 2005 Redistributable' do
+  source 'https://download.microsoft.com/download/6/B/B/6BB661D6-A8AE-4819-B79F-236472F6070C/vcredist_x86.exe'
+  installer_type :custom
+  options '/Q'
+end
+```
+Using a `:custom` package is one way to install a non `.msi` file that embeds an `msi` based installer.
+
+**`windows_package` removal**
+Packages can now be removed without the need to include the package `source`. The relevent uninstall metadata will now be discovered from the registry.
+```
+package 'Mercurial 3.6.1 (64-bit)' do
+  action :remove
+end
+```
+For non `:msi` packages, it is important that the package name used is EXACTLY the same as the display name found in "Add/Remove programs" or the `DisplayName` property in the appropriate registry key:
+* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
+* HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall
+* HKEY_LOCAL_MACHINE\Software\Wow6464Node\Microsoft\Windows\CurrentVersion\Uninstall
+
+When removing `:msi` packages, this same package naming rule applies if the `source` is omitted.
+
+Note that if there are multiple versions of a package installed with the same display name, all packages will be removed unless a version is provided in the `version` attribute or can be discovered in the `source` installer file.
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..2c37e6c
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,58 @@
+source "https://rubygems.org"
+gemspec name: "chef"
+
+gem "activesupport", "< 4.0.0", group: :compat_testing, platform: "ruby"
+
+gem "chef-config", path: "chef-config" if File.exist?(__FILE__ + "../chef-config")
+
+group(:docgen) do
+  gem "yard"
+end
+
+group(:maintenance) do
+  gem "tomlrb"
+
+  # To sync maintainers with github
+  gem "octokit"
+  gem "netrc"
+end
+
+group(:ruby_prof) do
+  # may need to disable this in insolation on fussy builds like AIX, RHEL4, etc
+  gem "ruby-prof"
+end
+
+group(:development, :test) do
+  gem "simplecov"
+  gem "rack", "~> 1.5.1"
+
+  # for testing new chefstyle rules
+  # gem 'chefstyle', github: 'chef/chefstyle'
+  gem "chefstyle", git: "https://github.com/chef/chefstyle.git", branch: "master"
+
+  gem "ruby-shadow", platforms: :ruby unless RUBY_PLATFORM.downcase.match(/(aix|cygwin)/)
+
+  # For external tests
+  #  gem 'chef-zero', github: 'chef/chef-zero'
+  #  gem 'cheffish', github: 'chef/cheffish'
+  #  gem 'chef-provisioning'#, github: 'chef/chef-provisioning'
+  #  gem 'chef-provisioning-aws', github: 'chef/chef-provisioning-aws'
+  #  gem 'test-kitchen'
+  #  gem 'chefspec'
+  #  gem 'chef-sugar'
+  #  gem 'poise', github: 'poise/poise', branch: 'deeecb890a6a0bc2037dfb09ce0fd0a8931519aa'
+  #  gem 'halite', github: 'poise/halite'
+  #  gem 'foodcritic', github: 'acrmp/foodcritic', branch: 'v5.0.0'
+  #  gem 'chef-rewind'
+end
+
+group(:travis) do
+  # See `bundler-audit` in .travis.yml
+  gem "bundler-audit", git: "https://github.com/rubysec/bundler-audit.git", ref: "4e32fca"
+end
+
+instance_eval(ENV["GEMFILE_MOD"]) if ENV["GEMFILE_MOD"]
+
+# If you want to load debugging tools into the bundle exec sandbox,
+# add these additional dependencies into chef/Gemfile.local
+eval(IO.read(__FILE__ + ".local"), binding) if File.exist?(__FILE__ + ".local")
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
new file mode 100644
index 0000000..0023cb9
--- /dev/null
+++ b/MAINTAINERS.md
@@ -0,0 +1,234 @@
+<!-- This is a generated file. Please do not edit directly -->
+
+# Maintainers
+
+This file lists how the Chef project is maintained. When making changes to the system, this
+file tells you who needs to review your patch - you need a simple majority of maintainers
+for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
+to not receive a veto from a Lieutenant or the Project Lead.
+
+Check out [How Chef is Maintained](https://github.com/opscode/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
+a maintainer, lieutenant, or the project lead.
+
+# Project Lead
+
+* [Adam Jacob](https://github.com/adamhjk)
+
+## Components
+
+## Chef Core
+
+Handles the core parts of the Chef DSL, base resource and provider
+infrastructure, the Chef applications and [omnibus-chef](https://github.com/chef/omnibus-chef). Includes anything not covered by
+another component.
+
+To mention the team, use @chef/client-core
+
+### Lieutenant
+
+* [Thom May](https://github.com/thommay)
+
+### Maintainers
+
+* [Bryan McLellan](https://github.com/btm)
+* [Noah Kantrowitz](https://github.com/coderanger)
+* [Daniel DeLeo](https://github.com/danielsdeleo)
+* [AJ Christensen](https://github.com/fujin)
+* [Phil Dibowitz](https://github.com/jaymzh)
+* [Jay Mundrawala](https://github.com/jaym)
+* [Jon Cowie](https://github.com/jonlives)
+* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Claire McQuin](https://github.com/mcquin)
+* [Steven Murawski](https://github.com/smurawski)
+* [Tyler Ball](https://github.com/tyler-ball)
+* [Ranjib Dey](https://github.com/ranjib)
+* [Matt Wrock](https://github.com/mwrock)
+
+## Dev Tools
+
+Chef Zero, Knife, Chef Apply and Chef Shell.
+To mention the team, use @chef/client-dev-tools
+
+### Maintainers
+
+* [Daniel DeLeo](https://github.com/danielsdeleo)
+* [Joshua Timberman](https://github.com/jtimberman)
+* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Steven Danna](https://github.com/stevendanna)
+
+## Test Tools
+
+ChefSpec
+To mention the team, use @chef/client-test-tools
+
+### Lieutenant
+
+* [Seth Vargo](https://github.com/sethvargo)
+
+### Maintainers
+
+* [Joshua Timberman](https://github.com/jtimberman)
+* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Ranjib Dey](https://github.com/ranjib)
+
+## Platform Specific Components
+
+The specific components of Chef related to a given platform - including (but not limited to) resources, providers, and the core DSL.
+
+## Enterprise Linux
+
+To mention the team, use @chef/client-enterprise-linux
+
+### Lieutenant
+
+* [Jon Cowie](https://github.com/jonlives)
+
+### Maintainers
+
+* [Phil Dibowitz](https://github.com/jaymzh)
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## Ubuntu
+
+To mention the team, use @chef/client-ubuntu
+
+### Lieutenant
+
+* [Ranjib Dey](https://github.com/ranjib)
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Thom May](https://github.com/thommay)
+
+## Windows
+
+To mention the team, use @chef/client-windows
+
+### Lieutenant
+
+* [Bryan McLellan](https://github.com/btm)
+
+### Maintainers
+
+* [Jay Mundrawala](https://github.com/jaym)
+* [Kartik Cating-Subramanian](https://github.com/ksubrama)
+* [Steven Murawski](https://github.com/smurawski)
+* [Salim Alam](https://github.com/chefsalim)
+* [Matt Wrock](https://github.com/mwrock)
+
+## Solaris
+
+To mention the team, use @chef/client-solaris
+
+### Lieutenant
+
+* [Thom May](https://github.com/thommay)
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## AIX
+
+To mention the team, use @chef/client-aix
+
+### Lieutenant
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## Mac OS X
+
+To mention the team, use @chef/client-os-x
+
+### Lieutenant
+
+* [Joshua Timberman](https://github.com/jtimberman)
+
+### Maintainers
+
+* [Tyler Ball](https://github.com/tyler-ball)
+
+## Debian
+
+To mention the team, use @chef/client-debian
+
+### Lieutenant
+
+* [Thom May](https://github.com/thommay)
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## Fedora
+
+To mention the team, use @chef/client-fedora
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## openSUSE
+
+To mention the team, use @chef/client-opensuse
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## SUSE Enterprise Linux Server
+
+To mention the team, use @chef/client-suse
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## FreeBSD
+
+To mention the team, use @chef/client-freebsd
+
+### Lieutenant
+
+* [Aaron Kalin](https://github.com/martinisoft)
+
+### Maintainers
+
+* [Cory Stephenson](https://github.com/Aevin1387)
+* [David Aronsohn](https://github.com/tbunnyman)
+* [Bryant Lippert](https://github.com/agentmeerkat)
+
+## OpenBSD
+
+To mention the team, use @chef/client-openbsd
+
+### Lieutenant
+
+* [Joe Miller](https://github.com/joemiller)
+
+## Gentoo
+
+To mention the team, use @chef/client-gentoo
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+
+## OmniOS
+
+To mention the team, use @chef/client-omnios
+
+### Maintainers
+
+* [Thom May](https://github.com/thommay)
+
+## ArchLinux
+
+To mention the team, use @chef/client-archlinux
+
+### Maintainers
+
+* [Lamont Granquist](https://github.com/lamont-granquist)
+* [Ryan Cragun](https://github.com/ryancragun)
+
diff --git a/MAINTAINERS.toml b/MAINTAINERS.toml
new file mode 100644
index 0000000..e2548d3
--- /dev/null
+++ b/MAINTAINERS.toml
@@ -0,0 +1,338 @@
+#
+# This file is structured to be consumed by both humans and computers.
+# To update the generated Markdown, run `bundle exec rake maintainers:generate`
+# To synchronize the maintainers with the github teams, run `bundle exec rake maintainers:synchronize`
+# It is a TOML document containing Markdown
+#
+[Preamble]
+  title = "Maintainers"
+  text = """
+This file lists how the Chef project is maintained. When making changes to the system, this
+file tells you who needs to review your patch - you need a simple majority of maintainers
+for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
+to not receive a veto from a Lieutenant or the Project Lead.
+
+Check out [How Chef is Maintained](https://github.com/opscode/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
+a maintainer, lieutenant, or the project lead.
+"""
+
+[Org]
+  [Org.Lead]
+    title = "Project Lead"
+    person = "adamhjk"
+
+  [Org.Components]
+    title = "Components"
+
+    [Org.Components.Core]
+      title = "Chef Core"
+      team = "client-core"
+      text = """
+Handles the core parts of the Chef DSL, base resource and provider
+infrastructure, the Chef applications and [omnibus-chef](https://github.com/chef/omnibus-chef). Includes anything not covered by
+another component.
+"""
+
+      lieutenant = "thommay"
+
+      maintainers = [
+        "btm",
+        "coderanger",
+        "danielsdeleo",
+        "fujin",
+        "jaymzh",
+        "jaym",
+        "jonlives",
+        "lamont-granquist",
+        "mcquin",
+        "smurawski",
+        "tyler-ball",
+        "ranjib",
+        "mwrock"
+      ]
+
+    [Org.Components.DevTools]
+      title = "Dev Tools"
+      team = "client-dev-tools"
+      text = "Chef Zero, Knife, Chef Apply and Chef Shell."
+
+      paths = [
+        "lib/chef/knife.rb",
+        "lib/chef/knife/",
+        "spec/functional/knife/",
+        "spec/integration/knife/",
+        "spec/unit/knife/"
+      ]
+
+      maintainers = [
+        "danielsdeleo",
+        "jtimberman",
+        "lamont-granquist",
+        "stevendanna"
+      ]
+
+    [Org.Components.TestTools]
+      title = "Test Tools"
+      team = "client-test-tools"
+      text = "ChefSpec"
+
+      lieutenant = "sethvargo"
+
+      maintainers = [
+        "jtimberman",
+        "lamont-granquist",
+        "ranjib"
+      ]
+
+    [Org.Components.Subsystems]
+      title = "Platform Specific Components"
+      text = """
+The specific components of Chef related to a given platform - including (but not limited to) resources, providers, and the core DSL.
+"""
+
+      [Org.Components.Subsystems."Enterprise Linux"]
+        title = "Enterprise Linux"
+        team = "client-enterprise-linux"
+
+        lieutenant = "jonlives"
+
+        maintainers = [
+          "jaymzh",
+          "lamont-granquist"
+        ]
+
+      [Org.Components.Subsystems.Ubuntu]
+        title = "Ubuntu"
+        team = "client-ubuntu"
+
+        lieutenant = "ranjib"
+
+        maintainers = [
+          "lamont-granquist",
+          "thommay"
+        ]
+
+      [Org.Components.Subsystems.Windows]
+        title = "Windows"
+        team = "client-windows"
+
+        lieutenant = "btm"
+        maintainers = [
+          "jaym",
+          "ksubrama",
+          "smurawski",
+          "chefsalim",
+          "mwrock"
+        ]
+
+      [Org.Components.Subsystems.Solaris]
+        title = "Solaris"
+        team = "client-solaris"
+
+        lieutenant = "thommay"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+      [Org.Components.Subsystems.AIX]
+        title = "AIX"
+        team = "client-aix"
+
+        lieutenant = "lamont-granquist"
+
+      [Org.Components.Subsystems."Mac OS X"]
+        title = "Mac OS X"
+        team = "client-os-x"
+
+        lieutenant = "jtimberman"
+
+        maintainers = [
+          "tyler-ball"
+        ]
+
+      [Org.Components.Subsystems.Debian]
+        title = "Debian"
+        team = "client-debian"
+
+        lieutenant = "thommay"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+    [Org.Components.Subsystems.Fedora]
+        title = "Fedora"
+        team = "client-fedora"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+      [Org.Components.Subsystems.openSUSE]
+        title = "openSUSE"
+        team = "client-opensuse"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+      [Org.Components.Subsystems."SUSE Enterprise Linux"]
+        title = "SUSE Enterprise Linux Server"
+        team = "client-suse"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+      [Org.Components.Subsystems.FreeBSD]
+        title = "FreeBSD"
+        team = "client-freebsd"
+
+        lieutenant = "martinisoft"
+
+        maintainers = [
+          "Aevin1387",
+          "tBunnyMan",
+          "AgentMeerkat"
+        ]
+
+      [Org.Components.Subsystems.OpenBSD]
+        title = "OpenBSD"
+        team = "client-openbsd"
+
+        lieutenant = "joemiller"
+
+    [Org.Components.Subsystems.Gentoo]
+        title = "Gentoo"
+        team = "client-gentoo"
+
+        maintainers = [
+          "lamont-granquist"
+        ]
+
+    [Org.Components.Subsystems.OmniOS]
+        title = "OmniOS"
+        team = "client-omnios"
+
+        maintainers = [
+          "thommay"
+        ]
+
+    [Org.Components.Subsystems.ArchLinux]
+        title = "ArchLinux"
+        team = "client-archlinux"
+
+        maintainers = [
+          "lamont-granquist",
+          "ryancragun"
+        ]
+
+[people]
+  [people.adamhjk]
+    Name = "Adam Jacob"
+    GitHub = "adamhjk"
+
+  [people.Aevin1387]
+    Name = "Cory Stephenson"
+    GitHub = "Aevin1387"
+
+  [people.AgentMeerkat]
+    Name = "Bryant Lippert"
+    GitHub = "AgentMeerkat"
+
+  [people.btm]
+    Name = "Bryan McLellan"
+    GitHub = "btm"
+
+  [people.danielsdeleo]
+    Name = "Daniel DeLeo"
+    GitHub = "danielsdeleo"
+
+  [people.fujin]
+    Name = "AJ Christensen"
+    GitHub = "fujin"
+
+  [people.jaymzh]
+    Name = "Phil Dibowitz"
+    GitHub = "jaymzh"
+
+  [people.jaym]
+    Name = "Jay Mundrawala"
+    GitHub = "jaym"
+
+  [people.jonlives]
+    Name = "Jon Cowie"
+    GitHub = "jonlives"
+
+  [people.jtimberman]
+    Name = "Joshua Timberman"
+    GitHub = "jtimberman"
+
+  [people.lamont-granquist]
+    Name = "Lamont Granquist"
+    GitHub = "lamont-granquist"
+
+  [people.martinisoft]
+    Name = "Aaron Kalin"
+    GitHub = "martinisoft"
+
+  [people.mcquin]
+    Name = "Claire McQuin"
+    GitHub = "mcquin"
+
+  [people.ranjib]
+    Name = "Ranjib Dey"
+    GitHub = "ranjib"
+
+  [people.sethvargo]
+    Name = "Seth Vargo"
+    GitHub = "sethvargo"
+
+  [people.smurawski]
+    Name = "Steven Murawski"
+    GitHub = "smurawski"
+
+  [people.stevendanna]
+    Name = "Steven Danna"
+    GitHub = "stevendanna"
+
+  [people.tBunnyMan]
+    Name = "David Aronsohn"
+    GitHub = "tbunnyman"
+    IRC = "tBunnyMan"
+    Twitter = "OnlyHaveCans"
+
+  [people.thommay]
+    Name = "Thom May"
+    GitHub = "thommay"
+    IRC = "thom"
+    Twitter = "thommay"
+
+  [people.tyler-ball]
+    Name = "Tyler Ball"
+    GitHub = "tyler-ball"
+
+  [people.ksubrama]
+    Name = "Kartik Cating-Subramanian"
+    GitHub = "ksubrama"
+
+  [people.joemiller]
+    Name = "Joe Miller"
+    GitHub = "joemiller"
+
+  [people.coderanger]
+    Name = "Noah Kantrowitz"
+    GitHub = "coderanger"
+
+  [people.ryancragun]
+    Name = "Ryan Cragun"
+    GitHub = "ryancragun"
+
+  [people.chefsalim]
+    Name = "Salim Alam"
+    GitHub = "chefsalim"
+
+  [people.mwrock]
+    Name = "Matt Wrock"
+    GitHub = "mwrock"
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..19223a4
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,21 @@
+Chef NOTICE
+===========
+
+Developed at Opscode (http://www.opscode.com).
+
+Contributors and Copyright holders:
+
+ * Copyright 2008-2016, Adam Jacob <adam at chef.io>
+ * Copyright 2008-2016, Arjuna Christensen <aj at hjksolutions.com>
+ * Copyright 2008-2016, Bryan McLellan <btm at loftninjas.org>
+ * Copyright 2008-2016, Ezra Zygmuntowicz <ezra at engineyard.com>
+ * Copyright 2009-2016, Sean Cribbs <seancribbs at gmail.com>
+ * Copyright 2009-2016, Christopher Brown <cb at chef.io>
+ * Copyright 2009-2016, Thom May <thom at clearairturbulence.org>
+ * Copyright 2009-2016, Joe Williams <joe at joetify.com>
+
+Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard.
+
+Chef incorporates code modified from deep_merge (http://trac.misuse.org/science/wiki/DeepMerge), which is Copyright 2008-2016, Steve Midgley
+
+Chef incorporates code modified from diff-lcs (http://diff-lcs.rubyforge.org/), which is Copyright (c) 2004–2013 Austin Ziegler
diff --git a/README.md b/README.md
index 3b1c719..5ec4d50 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-# Chef 
-[![Code Climate](https://codeclimate.com/github/opscode/chef.png)](https://codeclimate.com/github/opscode/chef)
+# Chef
+[![Code Climate](https://codeclimate.com/github/chef/chef.svg)](https://codeclimate.com/github/chef/chef)
 [![Build Status Master](https://travis-ci.org/chef/chef.svg?branch=master)](https://travis-ci.org/chef/chef)
 [![Build Status Master](https://ci.appveyor.com/api/projects/status/github/chef/chef?branch=master&svg=true&passingText=master%20-%20Ok&pendingText=master%20-%20Pending&failingText=master%20-%20Failing)](https://ci.appveyor.com/project/Chef/chef/branch/master)
 
@@ -9,7 +9,9 @@ Want to try Chef? Get started with [learnchef](https://learn.chef.io)
 * Source: [http://github.com/chef/chef/tree/master](http://github.com/chef/chef/tree/master)
 * Tickets/Issues: [https://github.com/chef/chef/issues](https://github.com/chef/chef/issues)
 * IRC: `#chef` and `#chef-hacking` on Freenode
-* Mailing list: [http://lists.opscode.com](http://lists.opscode.com)
+  - Join via browser: [#chef](https://webchat.freenode.net/?channels=chef), [#chef-hacking](https://webchat.freenode.net/?channels=chef-hacking)
+  - View logs: [#chef](https://botbot.me/freenode/chef/), [#chef-hacking](https://botbot.me/freenode/chef-hacking/)
+* Mailing list: [https://discourse.chef.io](https://discourse.chef.io)
 
 Chef is a configuration management tool designed to bring automation to your
 entire infrastructure.
@@ -18,7 +20,7 @@ This README focuses on developers who want to modify Chef source code.
 If you just want to use Chef, check out these resources:
 
 * [learnchef](https://learn.chef.io): Getting started guide
-* [http://docs.chef.io](http://docs.chef.io): Comprehensive User Docs
+* [docs.chef.io](http://docs.chef.io): Comprehensive User Docs
 * [Installer Downloads](https://www.chef.io/download-chef-client/): Install Chef as a complete package
 
 ## Installing From Git
@@ -30,8 +32,8 @@ to get a prebuilt package.
 
 ### Prerequisites
 
-Install these via your platform's preferred method (apt, yum, ports,
-emerge, etc.):
+Install these via your platform's preferred method (`apt`, `yum`, `ports`,
+`emerge`, etc.):
 
 * git
 * C compiler, header files, etc. On Ubuntu/Debian, use the
@@ -44,21 +46,22 @@ emerge, etc.):
 
 Then get the source and install it:
 
-    # Clone this repo
-    git clone https://github.com/chef/chef.git
-    
-    # cd into the source tree
-    cd chef
+```bash
+# Clone this repo
+git clone https://github.com/chef/chef.git
 
-    # Install dependencies with bundler
-    bundle install
+# cd into the source tree
+cd chef
 
-    # Build a gem
-    rake gem
+# Install dependencies with bundler
+bundle install
 
-    # Install the gem you just built
-    gem install pkg/chef-VERSION.gem
+# Build a gem
+bundle exec rake gem
 
+# Install the gem you just built
+gem install pkg/chef-VERSION.gem
+```
 
 ## Contributing/Development
 
@@ -68,11 +71,11 @@ read the
 
 The general development process is:
 
-1. Fork this repo and clone it to your workstation
-2. Create a feature branch for your change
-3. Write code and tests
+1. Fork this repo and clone it to your workstation.
+2. Create a feature branch for your change.
+3. Write code and tests.
 4. Push your feature branch to github and open a pull request against
-   master
+   master.
 
 Once your repository is set up, you can start working on the code. We do use
 TDD with RSpec, so you'll need to get a development environment running.
@@ -81,7 +84,7 @@ copy of the source running.
 
 ## Reporting Issues
 
-Issues can be reported by using [GitHub issues](https://github.com/chef/chef/issues).
+Issues can be reported by using [GitHub Issues](https://github.com/chef/chef/issues).
 
 Full details on how to report issues can be found in the [CONTRIBUTING](https://github.com/chef/chef/blob/master/CONTRIBUTING.md#-chef-issue-tracking) doc.
 
@@ -97,14 +100,16 @@ against the repository you think best fits and it will be directed to the approp
 We use RSpec for unit/spec tests. It is not necessary to start the development
 environment to run the specs--they are completely standalone.
 
-    # Run All the Tests
-    bundle exec rake spec
+```bash
+# Run All the Tests
+bundle exec rake spec
 
-    # Run a Single Test File
-    bundle exec rspec spec/PATH/TO/FILE_spec.rb
+# Run a Single Test File
+bundle exec rspec spec/PATH/TO/FILE_spec.rb
 
-    # Run a Subset of Tests
-    bundle exec rspec spec/PATH/TO/DIR
+# Run a Subset of Tests
+bundle exec rspec spec/PATH/TO/DIR
+```
 
 When you submit a pull request, we will automatically run the functional and unit
 tests in spec/functional/ and spec/unit/ respectively. These will be run on Ubuntu
@@ -118,7 +123,7 @@ Chef - A configuration management system
 |                      |                                          |
 |:---------------------|:-----------------------------------------|
 | **Author:**          | Adam Jacob (<adam at chef.io>)
-| **Copyright:**       | Copyright (c) 2008-2015 Chef Software, Inc.
+| **Copyright:**       | Copyright 2008-2016, Chef Software, Inc.
 | **License:**         | Apache License, Version 2.0
 
 Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
new file mode 100644
index 0000000..80d3efd
--- /dev/null
+++ b/RELEASE_NOTES.md
@@ -0,0 +1,82 @@
+# Chef Client Release Notes 12.7:
+
+## Updates to versioning strategy
+
+We recently updated the [versioning specification](https://github.com/chef/chef-rfc/pull/175) in our [release process](https://github.com/chef/chef-rfc/commits/master/rfc047-release-process.md) to facilitate faster releases with lower risk between each release.  Soon an automated process will begin updating the "patch" version (the third number in the version).
+
+For consumers of Chef this means that the first release of 12.7 you use may be 12.7.2 or 12.7.5 without earlier versions of 12.7 having been released first.  Those earlier versions may be available in the _current_ channel that you can access through the install.sh and install.ps1 scripts.
+
+## Net-ssh updates
+
+We updated the version of [net-ssh](https://github.com/net-ssh/net-ssh) in Chef from version 2.9 to 3.0 to take in an upstream bug fix.  The biggest change here is that they dropped support for Ruby 1.9 (which Chef already dropped support for).  Because this is such a low level dependency we found that many other projects had to be updated in lock-step (like Test Kitchen and Berkshelf) for the ChefDK packaging to succeed without dependency conflicts.
+
+## Zypper Package Multipackage Support
+
+On SuSE systems the `package` provider (aka `zypper_package` provider) now accepts arrays and will install them with a single zypper command together:
+
+```ruby
+package [ 'git', 'nmap' ]
+```
+
+Some additional code-cleanup was done to the provider and long-standing bugs may have been fixed.
+
+## Chocolatey Package Provider
+
+There is now a `chocolatey_package` provider in core chef.  It is named `chocolatey_package` instead of `chocolatey` in order to not conflict with the existing resource in the chocolatey cookbook and to
+comply with existing naming standards for package resources in core chef.
+
+The API for `chocolatey_package` conforms to the `package` API in core chef, rather than being a straight port of the cookbook version, and there are some API differences (e.g. it favors the `:remove`
+action over the `:uninstall` action since that is the API standard for core chef package providers).  The `chocolatey_package` provider also supports multipackage installations and will execute them
+in a single statement where possible:
+
+```ruby
+chocolatey_package [ 'googlechrome', 'flashplayerplugin', '7zip', 'git' ]
+```
+
+The `choco.exe` binary must be installed prior to using the resource, so the chocolatey cookbook recipe should still be used to install it.
+
+## EMEA Customers and UTF-8 Support
+
+EMEA customers in particular, and those customers who need reliable UTF-8 support, are highly encouraged to upgrade to the 12.7.0 release.  The 12.4.x/12.5.x/12.6.x releases of chef-client had an
+extremely bad UTF-8 handling bug in them which corrupted all UTF-8 data in the node.  In 12.7.0 that bug was fixed, along with another fix to make resource and audit reporting more reliable when fed
+non-UTF-8 (e.g. Latin-1/ISO-8859-1) characters.
+
+## Chef Solo -r (--recipe-url) changes
+
+The use of the `-r` option to chef-client result in setting the `--run-list`:
+
+```
+chef-client -r 'role[foo]'
+```
+
+Passing the same argument to chef-solo:
+
+```
+chef-solo -r 'role[foo]'
+```
+
+Instead invokes the `--recipe-url` code, which had the side effect of running an immediate unprompted `rm -rf *` in the current working directory of the user.   Due to this problem and other issues
+around this `rm -rf *` behavior it has been removed from the `--recipe-url` code in chef-solo.  The use of `-r` in chef-solo to mean `--recipe-url` has also been deprecated.
+
+The `rm -rf *` behavior has been moved to a `--delete-entire-chef-repo` option.  Users of chef-solo who want the old pre-12.7 behavior of `-r XXX` should therefore use `--recipe-url XXX --delete-entire-chef-repo`.
+
+## Chef::REST
+
+We recently completed moving our internal API calls from `Chef::REST` to
+`Chef::ServerAPI`. As part of that move, `Chef::REST` is no longer globally
+required, so if your code uses `Chef::REST`, you must ensure that you
+require it correctly.
+
+```ruby
+require 'chef/rest'
+```
+
+We strongly encourage users to move away from using `Chef::REST`; if
+your code is run inside `knife` or `chef` then consider using
+`Chef::ServerAPI`, otherwise please investigate [ChefAPI](http://sethvargo.github.io/chef-api/).
+
+## Nokogiri
+
+The latest version of the nokogiri gem will now be included in all omnibus-chef builds.  See
+[RFC 063](https://github.com/chef/chef-rfc/blob/master/rfc063-omnibus-chef-native-gems.md) and
+[RFC 063 PR discussion](https://github.com/chef/chef-rfc/pull/162) for more information.
diff --git a/ROADMAP.md b/ROADMAP.md
new file mode 100644
index 0000000..3db4932
--- /dev/null
+++ b/ROADMAP.md
@@ -0,0 +1,15 @@
+# Roadmap
+
+This file provides direction for the project as set forth by [RFC030#Roadmap](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#roadmap). 
+
+It is drafted by the Project Lead and the Lieutenants, with input from Maintainers and Contributors.
+
+## 2015 Q4
+* Windows - core package provider
+  - Moving the remaining package providers from the Windows cookbook into core
+
+## 2016 Q1
+* Windows - core windows_feature
+  - Move windows_feature from Windows cookbook, add caching
+* Windows - knife windows bootstrap, knife windows winrm in core
+  - Migrate Windows bootstrapping functionality into core
diff --git a/Rakefile b/Rakefile
index 70a45d9..5643c66 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,62 +17,54 @@
 # limitations under the License.
 #
 
-require File.dirname(__FILE__) + '/lib/chef/version'
+VERSION = IO.read(File.expand_path("../VERSION", __FILE__)).strip
 
-require 'rubygems'
-require 'rubygems/package_task'
-require 'rdoc/task'
-require './tasks/rspec.rb'
+require "rubygems"
+require "chef-config/package_task"
+require "rdoc/task"
+require_relative "tasks/rspec"
+require_relative "tasks/external_tests"
+require_relative "tasks/maintainers"
+require_relative "tasks/cbgb"
 
-GEM_NAME = "chef"
-
-Dir[File.expand_path("../*gemspec", __FILE__)].reverse.each do |gemspec_path|
-  gemspec = eval(IO.read(gemspec_path))
-  Gem::PackageTask.new(gemspec).define
-end
-
-task :install => :package do
-  sh %{gem install pkg/#{GEM_NAME}-#{Chef::VERSION}.gem --no-rdoc --no-ri}
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "Chef") do |package|
+  package.component_paths = ["chef-config"]
+  package.generate_version_class = true
 end
 
-task :uninstall do
-  sh %{gem uninstall #{GEM_NAME} -x -v #{Chef::VERSION} }
-end
+task :pedant, :chef_zero_spec
 
-desc "Build it, tag it and ship it"
-task :ship => :gem do
-  sh("git tag #{Chef::VERSION}")
-  sh("git push opscode --tags")
-  Dir[File.expand_path("../pkg/*.gem", __FILE__)].reverse.each do |built_gem|
-    sh("gem push #{built_gem}")
+task :build_eventlog do
+  Dir.chdir "ext/win32-eventlog/" do
+    system "rake build"
   end
 end
 
-task :pedant do
-  require File.expand_path('spec/support/pedant/run_pedant')
-end
-
-task :build_eventlog do
-  Dir.chdir 'ext/win32-eventlog/' do
-    system 'rake build'
+task :register_eventlog do
+  Dir.chdir "ext/win32-eventlog/" do
+    system "rake register"
   end
 end
 
-task :register_eventlog do
-  Dir.chdir 'ext/win32-eventlog/' do
-    system 'rake register'
+begin
+  require "chefstyle"
+  require "rubocop/rake_task"
+  RuboCop::RakeTask.new(:style) do |task|
+    task.options += ["--display-cop-names", "--no-color"]
   end
+rescue LoadError
+  puts "chefstyle/rubocop is not available.  gem install chefstyle to do style checking."
 end
 
 begin
-  require 'yard'
+  require "yard"
   DOC_FILES = [ "README.rdoc", "LICENSE", "spec/tiny_server.rb", "lib/**/*.rb" ]
   namespace :yard do
     desc "Create YARD documentation"
 
     YARD::Rake::YardocTask.new(:html) do |t|
       t.files = DOC_FILES
-      t.options = ['--format', 'html']
+      t.options = ["--format", "html"]
     end
   end
 
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..a028d14
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+12.7.2
diff --git a/acceptance/.gitignore b/acceptance/.gitignore
new file mode 100644
index 0000000..66f8ed3
--- /dev/null
+++ b/acceptance/.gitignore
@@ -0,0 +1 @@
+/Gemfile.lock
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml
new file mode 100644
index 0000000..50558c3
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml
@@ -0,0 +1,27 @@
+# Not quite ready yet
+
+driver:
+  name: digitalocean
+  digitalocean_access_token: <%= ENV['DIGITALOCEAN_API_TOKEN'] %>
+  region: <%= ENV['DIGITALOCEAN_REGION'] %>
+  size: 2gb
+  ssh_key_ids: <%= ENV['DIGITALOCEAN_SSH_KEYS'] %>
+  transport:
+    ssh_key: <%= ENV['DIGITALOCEAN_SSH_KEY_PATH'] %>
+
+provisioner:
+  name: chef_zero
+  product_name: chef
+  product_version: latest
+  channel: current
+
+platforms:
+<% %w(centos-6.5 centos-7.0
+      fedora-21
+      debian-8.1
+      ubuntu-12.04 ubuntu-14.04 ubuntu-15.10
+).each do |platform| %>
+  - name: #{platform}
+    driver_config:
+      image: <%= "#{platform.gsub('.', '-')}-x64" %>
+<% end %>
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
new file mode 100644
index 0000000..e4b2211
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml
@@ -0,0 +1,281 @@
+# Not quite ready yet
+
+<%
+def file_if_exists(path)
+  path = File.expand_path(path)
+  File.exist?(path) ? path : nil
+end
+%>
+
+driver:
+  name: ec2
+  tags:
+    X-Project: Kitchen Tests
+  aws_ssh_key_id: <%= ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME'] %>
+  # test-specific stuff
+  region: us-west-2
+  availability_zone: a
+  subnet_id: subnet-19ac017c
+  security_group_ids: ["sg-e401eb83", "sg-96274af3"]
+  instance_type: m3.large
+#  associate_public_ip: true  # Don't enable public IP, as subnet specified is behind VPN
+
+transport:
+  ssh_key: <%= file_if_exists("~/.ssh/#{ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME']}.pem") ||
+               file_if_exists("~/.ssh/#{ENV['AWS_SSH_KEY_ID'] || ENV['USER'] || ENV['USERNAME']}") ||
+               file_if_exists("~/.ssh/id_rsa") %>
+
+provisioner:
+  name: chef_zero
+  product_name: <%= ENV["KITCHEN_CHEF_PRODUCT"] %>
+  product_version: <%= ENV["KITCHEN_CHEF_VERSION"] %>
+  channel: <%= ENV["KITCHEN_CHEF_CHANNEL"] %>
+  client_rb:
+    audit_mode: :enabled
+
+platforms:
+  #
+  # AIX
+  #
+  # - name: aix-6.1
+  # - name: aix-7.1
+  #
+  # Debian
+  #
+  - name: debian-8
+    driver:
+      image_search:
+        name: debian-jessie-*
+        owner-id: "379101102735"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: admin
+  - name: debian-7
+    driver:
+      image_search:
+        name: debian-wheezy-*
+        owner-id: "379101102735"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: standard
+        image-type: machine
+    transport:
+      username: admin
+  #
+  # Ubuntu
+  #
+  - name: ubuntu-15.10
+    driver:
+      image_search:
+        name: ubuntu/images/*/ubuntu-*-15.10-amd64-server-*
+        owner-id: "099720109477"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ubuntu
+  - name: ubuntu-14.04
+    driver:
+      image_search:
+        name: ubuntu/images/*/ubuntu-*-14.04-*-server-*
+        owner-id: "099720109477"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ubuntu
+  - name: ubuntu-12.04
+    driver:
+      image_search:
+        name: ubuntu/images/*/ubuntu-*-12.04-*-server-*
+        owner-id: "099720109477"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ubuntu
+  #
+  # Red Hat Enterprise Linux
+  #
+  - name: el-7
+    driver:
+      image_search:
+        name: RHEL-7.*
+        owner-id: "309956199498"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ec2-user
+  - name: el-6
+    driver:
+      image_search:
+        name: RHEL-6.*
+        owner-id: "309956199498"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ec2-user
+  - name: el-5
+    driver:
+      image_search:
+        name: RHEL-5.*
+        owner-id: "309956199498"
+        architecture: x86_64
+        virtualization-type: paravirtual
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ec2-user
+  #
+  # FreeBSD
+  #
+  - name: freebsd-10
+    driver:
+      image_search:
+        name: FreeBSD/EC2 10.*-RELEASE*
+        owner-id: "118940168514"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ec2-user
+  - name: freebsd-9
+    driver:
+      image_search:
+        name: FreeBSD/EC2 9.*-RELEASE*
+        owner-id: "118940168514"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: ec2-user
+  - name: freebsd-8
+    driver:
+      image_search:
+        name: FreeBSD/EC2 8.*-RELEASE*
+        owner-id: "118940168514"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: standard
+        image-type: machine
+    transport:
+      username: ec2-user
+  #
+  # OS/X
+  #
+  # - name: mac_os_x-10.11
+  # - name: mac_os_x-10.10
+  # - name: mac_os_x-10.9
+  # - name: mac_os_x-10.8
+  #
+  # Nexus???
+  #
+  # - name: nexus-7
+  #
+  # Solaris
+  #
+  # - name: solaris-11
+  # - name: solaris-10
+  #
+  # Windows
+  #
+  - name: windows-2012r2
+    driver:
+      image_search:
+        name: Windows_Server-2012-R2*-English-*-Base-*
+        owner-alias: amazon
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+      user_data: |
+        <powershell>
+        $logfile="C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log"
+        #PS Remoting and & winrm.cmd basic config
+        Enable-PSRemoting -Force -SkipNetworkProfileCheck
+        & winrm.cmd set winrm/config '@{MaxTimeoutms="1800000"}' >> $logfile
+        & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
+        & winrm.cmd set winrm/config/winrs '@{MaxShellsPerUser="50"}' >> $logfile
+        #Server settings - support username/password login
+        & winrm.cmd set winrm/config/service/auth '@{Basic="true"}' >> $logfile
+        & winrm.cmd set winrm/config/service '@{AllowUnencrypted="true"}' >> $logfile
+        & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile
+        #Firewall Config
+        & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any  >> $logfile
+        #Set script execution to unrestricted
+        & Set-ExecutionPolicy Unrestricted -Force
+        </powershell>
+    transport:
+      username: administrator
+
+  - name: windows-2012
+    driver:
+      image_search:
+        name: Windows_Server-2012-RTM*-English-*-Base-*
+        owner-alias: amazon
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: administrator
+  - name: windows-2008r2
+    driver:
+      image_search:
+        name: Windows_Server-2008-R2*-English-*-Base-*
+        owner-alias: amazon
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
+    transport:
+      username: administrator
+  #
+  # Centos
+  #
+  - name: centos-7
+    driver:
+      image_search:
+        name: CentOS Linux 7 *
+        owner-alias: aws-marketplace
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: standard
+        image-type: machine
+    transport:
+      username: root
+  - name: centos-6
+    driver:
+      image_search:
+        name: CentOS-6.5-GA-*
+        owner-alias: aws-marketplace
+        architecture: x86_64
+        virtualization-type: paravirtual
+        block-device-mapping.volume-type: standard
+        image-type: machine
+    transport:
+      username: root
+  #
+  # Fedora
+  #
+  - name: fedora-21
+    driver:
+      image_search:
+        name: Fedora-Cloud-Base-21-*
+        owner-id: "125523088429"
+        architecture: x86_64
+        virtualization-type: hvm
+        block-device-mapping.volume-type: gp2
+        image-type: machine
diff --git a/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml b/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml
new file mode 100644
index 0000000..2cdb74a
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml
@@ -0,0 +1,49 @@
+driver:
+  name: vagrant
+  forward_agent: yes
+  customize:
+    cpus: 2
+    memory: 1024
+
+provisioner:
+  name: chef_zero
+  product_name: <%= ENV["KITCHEN_CHEF_PRODUCT"] %>
+  product_version: <%= ENV["KITCHEN_CHEF_VERSION"] %>
+  channel: <%= ENV["KITCHEN_CHEF_CHANNEL"] %>
+  client_rb:
+    audit_mode: :enabled
+
+platforms:
+<% %w(
+debian-8
+debian-7
+debian-6
+ubuntu-15.10
+ubuntu-14.04
+el-7
+el-6
+el-5
+freebsd-10
+freebsd-9
+fedora-21
+).each do |platform| %>
+  - name: <%= platform %>
+    driver:
+      box: opscode-<%= platform %>
+      box_url: http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_<%= platform %>_chef-provisionerless.box
+<% end %>
+# freebsd-8
+# ubuntu-12.04
+# centos-7
+# centos-6
+
+<% %w(
+2012r2
+2012
+2008r2
+).each do |version| %>
+  - name: windows-<%= version %>
+    driver:
+      box: chef/windows-server-<%= version %>-standard
+# URL is atlas
+<% end %>
diff --git a/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
new file mode 100644
index 0000000..d3913eb
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb
@@ -0,0 +1,46 @@
+module KitchenAcceptance
+  class Kitchen < Chef::Resource
+    resource_name :kitchen
+
+    property :command, String, name_property: true
+    property :driver, %w(ec2 vagrant), coerce: proc { |v| v.to_s }, default: lazy { ENV["KITCHEN_DRIVER"] || :ec2 }
+    property :instances, String, default: lazy { ENV["KITCHEN_INSTANCES"] }
+    property :kitchen_dir, String, default: Chef.node['chef-acceptance']['suite-dir']
+    property :chef_product, String, default: lazy {
+      ENV["KITCHEN_CHEF_PRODUCT"] ||
+      # If we're running the chef or chefdk projects in jenkins, pick up the project name.
+      (%w(chef chefdk).include?(ENV["PROJECT_NAME"]) ? ENV["PROJECT_NAME"] : "chef")
+    }
+    property :chef_channel, String, default: lazy {
+      ENV["KITCHEN_CHEF_CHANNEL"] ||
+      # Pick up current if we can't connect to artifactory
+      (ENV["ARTIFACTORY_USERNAME"] ? "unstable" : "current")
+    }
+    property :chef_version, String, default: lazy {
+      ENV["KITCHEN_CHEF_VERSION"] ||
+      # If we're running the chef or chefdk projects in jenkins, pick up the project name.
+      (ENV["PROJECT_NAME"] == chef_product ? ENV["OMNIBUS_BUILD_VERSION"] : nil) ||
+      "latest"
+    }
+    property :artifactory_username, String, default: lazy { ENV["ARTIFACTORY_USERNAME"] }
+    property :artifactory_password, String, default: lazy { ENV["ARTIFACTORY_PASSWORD"] }
+    property :env, Hash, default: {}
+    property :kitchen_options, String, default: lazy { ENV["PROJECT_NAME"] ? "-c -l debug" : "-c" }
+
+    action :run do
+      execute "bundle exec kitchen #{command}#{instances ? " #{instances}" : ""}#{kitchen_options ? " #{kitchen_options}" : ""}" do
+        cwd kitchen_dir
+        env({
+          "KITCHEN_DRIVER" => driver,
+          "KITCHEN_INSTANCES" => instances,
+          "KITCHEN_LOCAL_YAML" => ::File.expand_path("../../.kitchen.#{driver}.yml", __FILE__),
+          "KITCHEN_CHEF_PRODUCT" => chef_product,
+          "KITCHEN_CHEF_CHANNEL" => chef_channel,
+          "KITCHEN_CHEF_VERSION" => chef_version,
+          "ARTIFACTORY_USERNAME" => artifactory_username,
+          "ARTIFACTORY_PASSWORD" => artifactory_password
+        }.merge(new_resource.env))
+      end
+    end
+  end
+end
diff --git a/acceptance/.shared/kitchen_acceptance/metadata.rb b/acceptance/.shared/kitchen_acceptance/metadata.rb
new file mode 100644
index 0000000..70dc342
--- /dev/null
+++ b/acceptance/.shared/kitchen_acceptance/metadata.rb
@@ -0,0 +1 @@
+name "kitchen_acceptance"
diff --git a/acceptance/Gemfile b/acceptance/Gemfile
new file mode 100644
index 0000000..753b211
--- /dev/null
+++ b/acceptance/Gemfile
@@ -0,0 +1,11 @@
+source "https://rubygems.org"
+
+gem "mixlib-install", github: "chef/mixlib-install"
+gem "chef-acceptance", github: "chef/chef-acceptance"
+gem "test-kitchen", github: "sersut/test-kitchen", branch: "sersut/mixlib-install-update"
+gem "kitchen-ec2", github: "test-kitchen/kitchen-ec2", branch: "jk/image-search-only"
+gem "kitchen-inspec"
+gem "kitchen-vagrant"
+gem "windows_chef_zero"
+gem "winrm-transport"
+gem "berkshelf"
diff --git a/acceptance/README.md b/acceptance/README.md
new file mode 100644
index 0000000..48fa672
--- /dev/null
+++ b/acceptance/README.md
@@ -0,0 +1,86 @@
+# Acceptance Testing for Chef Client
+This folder contains acceptance tests that are required for Chef client
+release readiness.
+
+## Getting started
+The tests use the _chef-acceptance_ gem as the high level framework.
+All the gems needed to run these tests can be installed with Bundler.
+
+### Important Note!
+Before running chef-acceptance, you *MUST* do the following on your current session:
+
+```
+export APPBUNDLER_ALLOW_RVM=true
+```
+
+## Pre-requisites / One time set up
+
+### Set up for local VM (Vagrant)
+
+If you intend to run the acceptance tests on a local VM, the supported solution is to use Vagrant.
+Ensure that Vagrant is installed on the machine that tests will run from, along with a
+virtualization driver (E.g.: VirtualBox).
+
+Set up the KITCHEN_DRIVER environment variable appropriately (value should be "vagrant").  E.g.:
+```
+export KITCHEN_DRIVER=vagrant
+```
+Add this to your shell profile or startup script as needed.
+
+### Set up for cloud VM (EC2)
+
+If you intend to run the acceptance tests on a cloud VM, the supported solution is to use EC2.
+
+The steps you will need to do are:
+
+1. Add your AWS credentials to the machine - e.g., to the ~/.aws/credentials directory.
+   - The easiest way to do this is to download the aws command line (`brew install awscli` on OS/X) and run `aws configure`.
+2. Create or import a SSH key to AWS. (If you already have one, you can skip the import/create)
+   - In the AWS console, click Key Pairs, then Create Key Pair or Import Key Pair.
+3. Copy or move the private key file (USERNAME.pem) to the SSH folder (e.g. `~/.ssh/USERNAME.pem`).
+   - If you Created a key pair in step 2, download the private key and move it to `~/.ssh`.
+   - If you Importd a key pair in step 2, just ensure your private key is in `~/.ssh` and has the same name as the key pair (`~/.ssh/USERNAME` or `~/.ssh/USERNAME.pem`).
+4. Set AWS_SSH_KEY_ID to the SSH key name.
+   - This is **optional** if your AWS SSH key name is your local username.
+   - You may want to set this in your shell `.profile`.
+
+     ```shell
+     export AWS_SSH_KEY_ID=name-of-private-key
+     ```
+5. Set the private key to only be readable by root
+
+   ```shell
+   chmod 0400 ~/.ssh/USERNAME.pem
+   ```
+6. Set up the KITCHEN_DRIVER environment variable appropriately (value should be "ec2"). (This is optional, as ec2 is the default.) E.g.:
+
+   ```shell
+   export KITCHEN_DRIVER=ec2
+   ```
+   Add this to your shell profile or startup script as needed.
+7. **Connect to Chef VPN**. The instances you create will not have public IPs!
+
+### Setting up and running a test suite
+To get started, do a bundle install from the acceptance directory:
+```shell
+chef/acceptance$ bundle install --binstubs
+```
+
+To get some basic info and ensure chef-acceptance can be run, do:
+```shell
+chef/acceptance$ bin/chef-acceptance info
+```
+
+To run a particular test suite, do the following:
+```shell
+chef/acceptance$ bin/chef-acceptance test TEST_SUITE
+```
+
+To restrict which OS's will run, use the KITCHEN_INSTANCES environment variable:
+
+```shell
+chef/acceptance$ export KITCHEN_INSTANCES=*-ubuntu-1404
+chef/acceptance$ bin/chef-acceptance test cookbook-git
+```
+
+If KITCHEN_INSTANCES is not specified, the default instances are default-ubuntu-1404 and default-windows-windows-2012r2. All selected instances will be run in *parallel* if the driver supports it (ec2 does, vagrant doesn't).
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore b/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000..041413b
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000..2b7547b
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,3 @@
+name 'acceptance-cookbook'
+
+depends "kitchen_acceptance"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000..e2d663a
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000..5726c0e
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "converge"
diff --git a/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000..05ac94c
--- /dev/null
+++ b/acceptance/basics/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/basics/.kitchen.yml b/acceptance/basics/.kitchen.yml
new file mode 100644
index 0000000..4b7a516
--- /dev/null
+++ b/acceptance/basics/.kitchen.yml
@@ -0,0 +1,4 @@
+suites:
+  - name: chef-current-install
+    includes: [ubuntu-14.04, windows-server-2012r2]
+    run_list:
diff --git a/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb b/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb
new file mode 100644
index 0000000..dd0e0e4
--- /dev/null
+++ b/acceptance/basics/test/integration/chef-current-install/serverspec/chef_client_spec.rb
@@ -0,0 +1,19 @@
+
+require "spec_helper"
+
+gem_path = "/opt/chef/embedded/bin/gem"
+white_list = %w{chef-config json rake}
+
+describe "gem list" do
+  it "should not have non-whitelisted duplicate gems" do
+    gems = command("#{gem_path} list").stdout
+
+    duplicate_gems = gems.lines().select { |l| l.include?(",") }.collect { |l| l.split(" ").first }
+    puts "Duplicate gems found: #{duplicate_gems}" if duplicate_gems.length > 0
+
+    non_whitelisted_duplicates = duplicate_gems.select { |l| !white_list.include?(l) }
+    puts "Non white listed duplicates: #{non_whitelisted_duplicates}" if non_whitelisted_duplicates.length > 0
+
+    (non_whitelisted_duplicates.length).should be == 0
+  end
+end
diff --git a/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb b/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb
new file mode 100644
index 0000000..7189ddb
--- /dev/null
+++ b/acceptance/basics/test/integration/chef-current-install/serverspec/spec_helper.rb
@@ -0,0 +1,6 @@
+require "serverspec"
+require "pathname"
+
+set :backend, :exec
+
+set :path, "/bin:/usr/local/bin:$PATH"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000..041413b
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb
new file mode 100644
index 0000000..5d851a6
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/cookbook_kitchen.rb
@@ -0,0 +1,43 @@
+class CookbookKitchen < KitchenAcceptance::Kitchen
+  resource_name :cookbook_kitchen
+
+  property :command, default: lazy { name.split(" ")[0] }
+  property :kitchen_dir, default: lazy { ::File.join(repository_root, cookbook_relative_dir) }
+  property :test_cookbook, String, default: lazy { name.split(" ")[1] }
+  property :repository, String, default: lazy { "chef-cookbooks/#{test_cookbook}" },
+    coerce: proc { |v|
+      # chef-cookbooks/runit -> https://github.com/chef-cookbooks/runit.git
+      if !v.include?(':')
+        "https://github.com/#{v}.git"
+      else
+        v
+      end
+    }
+  property :repository_root, String, default: lazy { ::File.join(Chef.node["chef-acceptance"]["suite-dir"], "test_run", test_cookbook) }
+  property :branch, String, default: "master"
+  property :cookbook_relative_dir, String, default: ""
+  property :env, default: lazy {
+    {
+      "BUNDLE_GEMFILE" => ::File.expand_path("../Gemfile", Chef.node["chef-acceptance"]["suite-dir"]),
+#      "KITCHEN_GLOBAL_YAML" => ::File.join(kitchen_dir, ".kitchen.yml"),
+      "KITCHEN_YAML" => ::File.join(node["chef-acceptance"]["suite-dir"], ".kitchen.#{test_cookbook}.yml")
+    }
+  }
+
+  action :run do
+    # Ensure the parent directory exists
+    directory ::File.expand_path("..", repository_root) do
+      recursive true
+    end
+
+    # Grab the cookbook
+    # TODO Grab the source URL from supermarket
+    # TODO get git to include its kitchen tests in the cookbook.
+    git repository_root do
+      repository new_resource.repository
+      branch new_resource.branch
+    end
+
+    super()
+  end
+end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
new file mode 100644
index 0000000..5989bd0
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/libraries/top_cookbooks.rb
@@ -0,0 +1,21 @@
+class TopCookbooks < Chef::Resource
+  resource_name :top_cookbooks
+
+  property :command, String, name_property: true
+
+  action :run do
+    cookbook_kitchen "#{command} git" do
+    end
+
+    # https://github.com/learn-chef/learn-chef-acceptance/pull/10
+    # cookbook_kitchen "#{command} learn-the-basics-ubuntu" do
+    #   repository "learn-chef/learn-chef-acceptance"
+    #   cookbook_relative_dir "cookbooks/learn-the-basics-ubuntu"
+    # end
+    #
+    # cookbook_kitchen "#{command} learn-the-basics-windows" do
+    #   repository "learn-chef/learn-chef-acceptance"
+    #   cookbook_relative_dir "cookbooks/learn-the-basics-windows"
+    # end
+  end
+end
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000..26cdab4
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,3 @@
+name "acceptance-cookbook"
+
+depends "kitchen_acceptance"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000..63d10e8
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+top_cookbooks "destroy"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000..7b16f8e
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+top_cookbooks "converge"
diff --git a/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000..8d00a2e
--- /dev/null
+++ b/acceptance/top-cookbooks/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+top_cookbooks "verify"
diff --git a/acceptance/top-cookbooks/.gitignore b/acceptance/top-cookbooks/.gitignore
new file mode 100644
index 0000000..306f0cc
--- /dev/null
+++ b/acceptance/top-cookbooks/.gitignore
@@ -0,0 +1 @@
+test_run/
diff --git a/acceptance/top-cookbooks/.kitchen.git.yml b/acceptance/top-cookbooks/.kitchen.git.yml
new file mode 100644
index 0000000..8db1829
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.git.yml
@@ -0,0 +1,10 @@
+suites:
+  - name: git-default
+    run_list: ["recipe[git]"]
+    includes: [ubuntu-14.04]
+  - name: git-source
+    run_list: ["recipe[git::source]"]
+    includes: [nonexistent]
+  - name: git-default-windows
+    run_list: ["recipe[git]"]
+    includes: [windows-2012r2]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml
new file mode 100644
index 0000000..6b8848e
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-rhel.yml
@@ -0,0 +1,4 @@
+suites:
+  - name: learn-the-basics-rhel-default
+    run_list: ["recipe[learn-the-basics-rhel::default]"]
+    includes: [el-6]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml
new file mode 100644
index 0000000..b0a3e45
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-ubuntu.yml
@@ -0,0 +1,4 @@
+suites:
+  - name: learn-the-basics-ubuntu-default
+    run_list: ["recipe[learn-the-basics-ubuntu::default]"]
+    includes: [ubuntu-14.04]
diff --git a/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml b/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml
new file mode 100644
index 0000000..4e22987
--- /dev/null
+++ b/acceptance/top-cookbooks/.kitchen.learn-the-basics-windows.yml
@@ -0,0 +1,4 @@
+suites:
+  - name: learn-the-basics-windows-default
+    run_list: ["recipe[learn-the-basics-windows::default]"]
+    includes: [windows-2012r2]
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore b/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000..041413b
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000..6c75456
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,2 @@
+name "acceptance-cookbook"
+depends "kitchen_acceptance"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000..e2d663a
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000..a6f148f
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "setup"
diff --git a/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000..05ac94c
--- /dev/null
+++ b/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/trivial/.kitchen.yml b/acceptance/trivial/.kitchen.yml
new file mode 100644
index 0000000..1e0af03
--- /dev/null
+++ b/acceptance/trivial/.kitchen.yml
@@ -0,0 +1,7 @@
+verifier:
+  name: inspec
+
+suites:
+  - name: chef-current-install
+    includes: [windows-2012r2]
+    run_list:
diff --git a/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb b/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb
new file mode 100644
index 0000000..05c1331
--- /dev/null
+++ b/acceptance/trivial/test/integration/chef-current-install/inspec/chef_client_spec.rb
@@ -0,0 +1,5 @@
+chef_version = ENV["KITCHEN_CHEF_VERSION"].split("+")[0]
+describe command("chef-client -v") do
+  its("exit_status") { should eq 0 }
+  its(:stdout) { should match /Chef: #{chef_version}/ } if chef_version != "latest"
+end
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore b/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore
new file mode 100644
index 0000000..041413b
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/.gitignore
@@ -0,0 +1,2 @@
+nodes/
+tmp/
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb
new file mode 100644
index 0000000..6c75456
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/metadata.rb
@@ -0,0 +1,2 @@
+name "acceptance-cookbook"
+depends "kitchen_acceptance"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
new file mode 100644
index 0000000..e2d663a
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/destroy.rb
@@ -0,0 +1 @@
+kitchen "destroy"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
new file mode 100644
index 0000000..5726c0e
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/provision.rb
@@ -0,0 +1 @@
+kitchen "converge"
diff --git a/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
new file mode 100644
index 0000000..05ac94c
--- /dev/null
+++ b/acceptance/windows-service/.acceptance/acceptance-cookbook/recipes/verify.rb
@@ -0,0 +1 @@
+kitchen "verify"
diff --git a/acceptance/windows-service/.kitchen.yml b/acceptance/windows-service/.kitchen.yml
new file mode 100644
index 0000000..5270e81
--- /dev/null
+++ b/acceptance/windows-service/.kitchen.yml
@@ -0,0 +1,7 @@
+verifier:
+  name: inspec
+
+suites:
+  - name: chef-windows-service
+    includes: [windows-2012r2]
+    run_list:
diff --git a/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
new file mode 100644
index 0000000..a791177
--- /dev/null
+++ b/acceptance/windows-service/test/integration/chef-windows-service/inspec/chef_windows_service_spec.rb
@@ -0,0 +1,58 @@
+only_if do
+  os["family"] == "windows"
+end
+
+describe command("chef-service-manager") do
+  it { should exist }
+  its("exit_status") { should eq 0 }
+end
+
+describe service("chef-client") do
+  it { should_not be_enabled }
+  it { should_not be_installed }
+  it { should_not be_running }
+end
+
+describe command("chef-service-manager -a install") do
+  its("exit_status") { should eq 0 }
+  its(:stdout) { should match /Service 'chef-client' has successfully been installed./ }
+end
+
+describe service("chef-client") do
+  it { should be_enabled }
+  it { should be_installed }
+  it { should_not be_running }
+end
+
+describe command("chef-service-manager -a start") do
+  its("exit_status") { should eq 0 }
+  its(:stdout) { should match /Service 'chef-client' is now 'running'/ }
+end
+
+describe service("chef-client") do
+  it { should be_enabled }
+  it { should be_installed }
+  it { should be_running }
+end
+
+describe command("chef-service-manager -a stop") do
+  its("exit_status") { should eq 0 }
+  its(:stdout) { should match /Service 'chef-client' is now 'stopped'/ }
+end
+
+describe service("chef-client") do
+  it { should be_enabled }
+  it { should be_installed }
+  it { should_not be_running }
+end
+
+describe command("chef-service-manager -a uninstall") do
+  its("exit_status") { should eq 0 }
+  its(:stdout) { should match /Service chef-client deleted/ }
+end
+
+describe service("chef-client") do
+  it { should_not be_enabled }
+  it { should_not be_installed }
+  it { should_not be_running }
+end
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..d5c9ae0
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,36 @@
+version: "master-{build}"
+
+os: Windows Server 2012 R2
+platform:
+  - x64
+
+environment:
+  matrix:
+    - ruby_version: "200-x64"
+    - ruby_version: "21"
+
+clone_folder: c:\projects\chef
+clone_depth: 1
+skip_tags: true
+branches:
+  only:
+    - master
+
+install:
+  - systeminfo
+  - winrm quickconfig -q
+  - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
+  - echo %PATH%
+  - ruby --version
+  - gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc || gem install bundler --quiet --no-ri --no-rdoc
+  - gem install rubygems-pkg/rubygems-update-2.4.6.gem
+  - update_rubygems
+  - gem --version
+  - bundler --version
+
+build_script:
+  - bundle install || bundle install || bundle install
+
+test_script:
+  - SET SPEC_OPTS=--format progress
+  - bundle exec rake spec
diff --git a/bin/chef-apply b/bin/chef-apply
index c617129..39c6682 100755
--- a/bin/chef-apply
+++ b/bin/chef-apply
@@ -3,7 +3,7 @@
 # ./chef-apply - Run a single chef recipe
 #
 # Author:: Bryan W. Berry (<bryan.berry at gmail.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'rubygems'
+require "rubygems"
 $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef/application/apply'
+require "chef/application/apply"
 
 Chef::Application::Apply.new.run
diff --git a/bin/chef-client b/bin/chef-client
index 5b2b058..207bb89 100755
--- a/bin/chef-client
+++ b/bin/chef-client
@@ -2,8 +2,8 @@
 #
 # ./chef-client - Run the chef client
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'rubygems'
+require "rubygems"
 $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef'
-require 'chef/application/client'
+require "chef"
+require "chef/application/client"
 
 Chef::Application::Client.new.run
diff --git a/bin/chef-service-manager b/bin/chef-service-manager
new file mode 100755
index 0000000..c894b10
--- /dev/null
+++ b/bin/chef-service-manager
@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+#
+# ./chef-service-manager - Control chef-service on Windows platforms.
+#
+# Author:: Serdar Sutay (serdar at chef.io)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "rubygems"
+$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
+require "chef"
+require "chef/application/windows_service_manager"
+
+if Chef::Platform.windows?
+  chef_client_service = {
+    :service_name => "chef-client",
+    :service_display_name => "Chef Client Service",
+    :service_description => "Runs Chef Client on regular, configurable intervals.",
+    :service_file_path => File.expand_path("../chef-windows-service", $PROGRAM_NAME),
+    :delayed_start => true,
+    :dependencies => ["Winmgmt"],
+  }
+  Chef::Application::WindowsServiceManager.new(chef_client_service).run
+else
+  puts "chef-service-manager is only available on Windows platforms."
+end
diff --git a/bin/chef-shell b/bin/chef-shell
index f334635..9cc7651 100755
--- a/bin/chef-shell
+++ b/bin/chef-shell
@@ -25,7 +25,7 @@ end
 
 require "irb"
 require "irb/completion"
-require 'irb/ext/save-history'
+require "irb/ext/save-history"
 
 $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
 
diff --git a/bin/chef-solo b/bin/chef-solo
index 958ab21..23def86 100755
--- a/bin/chef-solo
+++ b/bin/chef-solo
@@ -2,8 +2,8 @@
 #
 # ./chef-solo - Run the chef client, in stand-alone mode
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'rubygems'
+require "rubygems"
 $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
-require 'chef/application/solo'
+require "chef/application/solo"
 
 Chef::Application::Solo.new.run
diff --git a/bin/chef-windows-service b/bin/chef-windows-service
new file mode 100755
index 0000000..184c3d7
--- /dev/null
+++ b/bin/chef-windows-service
@@ -0,0 +1,35 @@
+#!/usr/bin/env ruby
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+#
+# Copyright:: 2014, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Note:
+# The file is used by appbundler to generate a ruby file that
+# we can execute using the correct gems. The batch file we
+# generate will call that file, and will be registered as
+# a windows service.
+
+require "rubygems"
+$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
+require "chef"
+require "chef/application/windows_service"
+
+if Chef::Platform.windows?
+  Chef::Application::WindowsService.mainloop
+else
+  puts "chef-windows-service is only available on Windows platforms."
+end
diff --git a/bin/knife b/bin/knife
index 6173aad..b8983d6 100755
--- a/bin/knife
+++ b/bin/knife
@@ -2,8 +2,8 @@
 #
 # ./knife - Chef CLI interface
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'rubygems'
+require "rubygems"
 $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")))
-require 'chef/application/knife'
+require "chef/application/knife"
 
 Chef::Application::Knife.new.run
-
diff --git a/chef-config/.gitignore b/chef-config/.gitignore
new file mode 100644
index 0000000..0cb6eeb
--- /dev/null
+++ b/chef-config/.gitignore
@@ -0,0 +1,9 @@
+/.bundle/
+/.yardoc
+/Gemfile.lock
+/_yardoc/
+/coverage/
+/doc/
+/pkg/
+/spec/reports/
+/tmp/
diff --git a/chef-config/.rspec b/chef-config/.rspec
new file mode 100644
index 0000000..eb3ef03
--- /dev/null
+++ b/chef-config/.rspec
@@ -0,0 +1,2 @@
+--color
+-fd
diff --git a/chef-config/.travis.yml b/chef-config/.travis.yml
new file mode 100644
index 0000000..927580f
--- /dev/null
+++ b/chef-config/.travis.yml
@@ -0,0 +1,31 @@
+language: ruby
+
+sudo: false
+# Early warning system to catch if Rubygems breaks something
+before_install:
+  gem update --system
+
+branches:
+  only:
+  - master
+
+matrix:
+  include:
+  - rvm: 2.0
+  - rvm: 2.1
+
+notifications:
+  on_change: true
+  on_failure: true
+  on_success: change
+  on_pull_requests: false
+  irc:
+    channels:
+    - chat.freenode.net#chef-hacking
+  hipchat:
+    rooms:
+    # Build Statuses
+    - secure: G8MNo94L8bmWWwkH2/ViB2QaZnZHZscYM/mEjDbOGd15sqrruwckeARyBoUcRI7P1C6AFmS4IKCNVXa6KzX4Pbh51gQWM92zRpRTZpplwtXz53/1l8ajLFLLMLvEMTlBFAANUKEUFAQPY4dMa14V3Qc5oijfIncN61k4nZNTKpY=
+  - rvm: 2.2
+    # Open Source
+    - secure: hmcex4PpG5dn8WvjndONO4xCUKOC5kPU/bUEGRrfVbe2YKJE7t0XXbNDC96W/xBgzgnJzvf1Er0zJKDrNf4qEDEWFoozdN00WLcqREgaLLS3Seto2FjR/BpBk5q+sCV0rwwEMms2P4Qk+VSnDCnm9EaeM55hOabqNuOrRzoZLBQ=
diff --git a/chef-config/Gemfile b/chef-config/Gemfile
new file mode 100644
index 0000000..96ab544
--- /dev/null
+++ b/chef-config/Gemfile
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+# Specify your gem's dependencies in chef-config.gemspec
+gemspec
diff --git a/chef-config/LICENSE b/chef-config/LICENSE
new file mode 100644
index 0000000..11069ed
--- /dev/null
+++ b/chef-config/LICENSE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/chef-config/README.md b/chef-config/README.md
new file mode 100644
index 0000000..c365272
--- /dev/null
+++ b/chef-config/README.md
@@ -0,0 +1,4 @@
+# ChefConfig
+
+This repo is experimental. Use at your own risk.
+
diff --git a/chef-config/Rakefile b/chef-config/Rakefile
new file mode 100644
index 0000000..151c275
--- /dev/null
+++ b/chef-config/Rakefile
@@ -0,0 +1,13 @@
+require "rspec/core/rake_task"
+require "chef-config/package_task"
+
+ChefConfig::PackageTask.new(File.expand_path("..", __FILE__), "ChefConfig") do |package|
+  package.module_path = "chef-config"
+end
+
+task :default => :spec
+
+desc "Run standard specs"
+RSpec::Core::RakeTask.new(:spec) do |t|
+  t.pattern = FileList["spec/**/*_spec.rb"]
+end
diff --git a/chef-config/chef-config.gemspec b/chef-config/chef-config.gemspec
new file mode 100644
index 0000000..f597416
--- /dev/null
+++ b/chef-config/chef-config.gemspec
@@ -0,0 +1,32 @@
+# coding: utf-8
+lib = File.expand_path("../lib", __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require "chef-config/version"
+
+Gem::Specification.new do |spec|
+  spec.name          = "chef-config"
+  spec.version       = ChefConfig::VERSION
+  spec.authors       = ["Adam Jacob"]
+  spec.email         = ["adam at chef.io"]
+
+  spec.summary       = %q{Chef's default configuration and config loading}
+  spec.homepage      = "https://github.com/chef/chef"
+  spec.license       = "Apache-2.0"
+
+  spec.require_paths = ["lib"]
+
+  spec.add_dependency "mixlib-shellout", "~> 2.0"
+  spec.add_dependency "mixlib-config", "~> 2.0"
+
+  spec.add_development_dependency "rake", "~> 10.0"
+
+  %w{rspec-core rspec-expectations rspec-mocks}.each do |rspec|
+    spec.add_development_dependency(rspec, "~> 3.2")
+  end
+
+  spec.files = %w{Rakefile LICENSE README.md} + Dir.glob("*.gemspec") +
+               Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
+
+  spec.bindir        = "bin"
+  spec.executables   = []
+end
diff --git a/chef-config/lib/chef-config.rb b/chef-config/lib/chef-config.rb
new file mode 100644
index 0000000..3c52462
--- /dev/null
+++ b/chef-config/lib/chef-config.rb
@@ -0,0 +1,20 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module ChefConfig
+
+end
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
new file mode 100644
index 0000000..ac55853
--- /dev/null
+++ b/chef-config/lib/chef-config/config.rb
@@ -0,0 +1,920 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Mark Mzyk (<mmzyk at chef.io>)
+# Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "mixlib/config"
+require "pathname"
+
+require "chef-config/logger"
+require "chef-config/windows"
+require "chef-config/path_helper"
+require "mixlib/shellout"
+require "uri"
+require "openssl"
+
+module ChefConfig
+
+  class Config
+
+    extend Mixlib::Config
+
+    # Evaluates the given string as config.
+    #
+    # +filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file.
+    def self.from_string(string, filename)
+      self.instance_eval(string, filename, 1)
+    end
+
+    def self.inspect
+      configuration.inspect
+    end
+
+    def self.platform_specific_path(path)
+      path = PathHelper.cleanpath(path)
+      if ChefConfig.windows?
+        # turns \etc\chef\client.rb and \var\chef\client.rb into C:/chef/client.rb
+        if env["SYSTEMDRIVE"] && path[0] == '\\' && path.split('\\')[2] == "chef"
+          path = PathHelper.join(env["SYSTEMDRIVE"], path.split('\\', 3)[2])
+        end
+      end
+      path
+    end
+
+    def self.add_formatter(name, file_path = nil)
+      formatters << [name, file_path]
+    end
+
+    def self.add_event_logger(logger)
+      event_handlers << logger
+    end
+
+    # Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
+    configurable(:config_file)
+
+    default(:config_dir) do
+      if config_file
+        PathHelper.dirname(PathHelper.canonical_path(config_file, false))
+      else
+        PathHelper.join(user_home, ".chef", "")
+      end
+    end
+
+    default :formatters, []
+
+    def self.is_valid_url?(uri)
+      url = uri.to_s.strip
+      /^http:\/\// =~ url || /^https:\/\// =~ url || /^chefzero:/ =~ url
+    end
+    # Override the config dispatch to set the value of multiple server options simultaneously
+    #
+    # === Parameters
+    # url<String>:: String to be set for all of the chef-server-api URL's
+    #
+    configurable(:chef_server_url).writes_value do |uri|
+      unless is_valid_url? uri
+        raise ConfigurationError, "#{uri} is an invalid chef_server_url."
+      end
+      uri.to_s.strip
+    end
+
+    # When you are using ActiveSupport, they monkey-patch 'daemonize' into Kernel.
+    # So while this is basically identical to what method_missing would do, we pull
+    # it up here and get a real method written so that things get dispatched
+    # properly.
+    configurable(:daemonize).writes_value { |v| v }
+
+    # The root where all local chef object data is stored.  cookbooks, data bags,
+    # environments are all assumed to be in separate directories under this.
+    # chef-solo uses these directories for input data.  knife commands
+    # that upload or download files (such as knife upload, knife role from file,
+    # etc.) work.
+    default :chef_repo_path do
+      if self.configuration[:cookbook_path]
+        if self.configuration[:cookbook_path].kind_of?(String)
+          File.expand_path("..", self.configuration[:cookbook_path])
+        else
+          self.configuration[:cookbook_path].map do |path|
+            File.expand_path("..", path)
+          end
+        end
+      elsif configuration[:cookbook_artifact_path]
+        File.expand_path("..", self.configuration[:cookbook_artifact_path])
+      else
+        cache_path
+      end
+    end
+
+    def self.find_chef_repo_path(cwd)
+      # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
+      # This allows us to run config-free.
+      path = cwd
+      until File.directory?(PathHelper.join(path, "cookbooks")) || File.directory?(PathHelper.join(path, "cookbook_artifacts"))
+        new_path = File.expand_path("..", path)
+        if new_path == path
+          ChefConfig.logger.warn("No cookbooks directory found at or above current directory.  Assuming #{Dir.pwd}.")
+          return Dir.pwd
+        end
+        path = new_path
+      end
+      ChefConfig.logger.info("Auto-discovered chef repository at #{path}")
+      path
+    end
+
+    def self.derive_path_from_chef_repo_path(child_path)
+      if chef_repo_path.kind_of?(String)
+        PathHelper.join(chef_repo_path, child_path)
+      else
+        chef_repo_path.uniq.map { |path| PathHelper.join(path, child_path) }
+      end
+    end
+
+    # Location of acls on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/acls.
+    default(:acl_path) { derive_path_from_chef_repo_path("acls") }
+
+    # Location of clients on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/acls.
+    default(:client_path) { derive_path_from_chef_repo_path("clients") }
+
+    # Location of containers on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/containers.
+    default(:container_path) { derive_path_from_chef_repo_path("containers") }
+
+    # Location of cookbook_artifacts on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/cookbook_artifacts.
+    default(:cookbook_artifact_path) { derive_path_from_chef_repo_path("cookbook_artifacts") }
+
+    # Location of cookbooks on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/cookbooks.  If chef_repo_path
+    # is not specified, this is set to [/var/chef/cookbooks, /var/chef/site-cookbooks]).
+    default(:cookbook_path) do
+      if self.configuration[:chef_repo_path]
+        derive_path_from_chef_repo_path("cookbooks")
+      else
+        Array(derive_path_from_chef_repo_path("cookbooks")).flatten +
+          Array(derive_path_from_chef_repo_path("site-cookbooks")).flatten
+      end
+    end
+
+    # Location of data bags on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/data_bags.
+    default(:data_bag_path) { derive_path_from_chef_repo_path("data_bags") }
+
+    # Location of environments on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/environments.
+    default(:environment_path) { derive_path_from_chef_repo_path("environments") }
+
+    # Location of groups on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/groups.
+    default(:group_path) { derive_path_from_chef_repo_path("groups") }
+
+    # Location of nodes on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/nodes.
+    default(:node_path) { derive_path_from_chef_repo_path("nodes") }
+
+    # Location of policies on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/policies.
+    default(:policy_path) { derive_path_from_chef_repo_path("policies") }
+
+    # Location of policy_groups on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/policy_groups.
+    default(:policy_group_path) { derive_path_from_chef_repo_path("policy_groups") }
+
+    # Location of roles on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/roles.
+    default(:role_path) { derive_path_from_chef_repo_path("roles") }
+
+    # Location of users on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/users.
+    default(:user_path) { derive_path_from_chef_repo_path("users") }
+
+    # Location of policies on disk. String or array of strings.
+    # Defaults to <chef_repo_path>/policies.
+    default(:policy_path) { derive_path_from_chef_repo_path("policies") }
+
+    # Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity
+    default :enforce_path_sanity, true
+
+    # Formatted Chef Client output is a beta feature, disabled by default:
+    default :formatter, "null"
+
+    # The number of times the client should retry when registering with the server
+    default :client_registration_retries, 5
+
+    # An array of paths to search for knife exec scripts if they aren't in the current directory
+    default :script_path, []
+
+    # The root of all caches (checksums, cache and backup).  If local mode is on,
+    # this is under the user's home directory.
+    default(:cache_path) do
+      if local_mode
+        PathHelper.join(config_dir, "local-mode-cache")
+      else
+        primary_cache_root = platform_specific_path("/var")
+        primary_cache_path = platform_specific_path("/var/chef")
+        # Use /var/chef as the cache path only if that folder exists and we can read and write
+        # into it, or /var exists and we can read and write into it (we'll create /var/chef later).
+        # Otherwise, we'll create .chef under the user's home directory and use that as
+        # the cache path.
+        unless path_accessible?(primary_cache_path) || path_accessible?(primary_cache_root)
+          secondary_cache_path = PathHelper.join(user_home, ".chef")
+          ChefConfig.logger.info("Unable to access cache at #{primary_cache_path}. Switching cache to #{secondary_cache_path}")
+          secondary_cache_path
+        else
+          primary_cache_path
+        end
+      end
+    end
+
+    # Returns true only if the path exists and is readable and writeable for the user.
+    def self.path_accessible?(path)
+      File.exists?(path) && File.readable?(path) && File.writable?(path)
+    end
+
+    # Where cookbook files are stored on the server (by content checksum)
+    default(:checksum_path) { PathHelper.join(cache_path, "checksums") }
+
+    # Where chef's cache files should be stored
+    default(:file_cache_path) { PathHelper.join(cache_path, "cache") }
+
+    # Where backups of chef-managed files should go
+    default(:file_backup_path) { PathHelper.join(cache_path, "backup") }
+
+    # The chef-client (or solo) lockfile.
+    #
+    # If your `file_cache_path` resides on a NFS (or non-flock()-supporting
+    # fs), it's recommended to set this to something like
+    # '/tmp/chef-client-running.pid'
+    default(:lockfile) { PathHelper.join(file_cache_path, "chef-client-running.pid") }
+
+    ## Daemonization Settings ##
+    # What user should Chef run as?
+    default :user, nil
+    default :group, nil
+    default :umask, 0022
+
+    # Valid log_levels are:
+    # * :debug
+    # * :info
+    # * :warn
+    # * :fatal
+    # These work as you'd expect. There is also a special `:auto` setting.
+    # When set to :auto, Chef will auto adjust the log verbosity based on
+    # context. When a tty is available (usually because the user is running chef
+    # in a console), the log level is set to :warn, and output formatters are
+    # used as the primary mode of output. When a tty is not available, the
+    # logger is the primary mode of output, and the log level is set to :info
+    default :log_level, :auto
+
+    # Logging location as either an IO stream or string representing log file path
+    default :log_location, STDOUT
+
+    # Using `force_formatter` causes chef to default to formatter output when STDOUT is not a tty
+    default :force_formatter, false
+
+    # Using `force_logger` causes chef to default to logger output when STDOUT is a tty
+    default :force_logger, false
+
+    # Using 'stream_execute_output' will have Chef always stream the execute output
+    default :stream_execute_output, false
+
+    default :http_retry_count, 5
+    default :http_retry_delay, 5
+    default :interval, nil
+    default :once, nil
+    default :json_attribs, nil
+    # toggle info level log items that can create a lot of output
+    default :verbose_logging, true
+    default :node_name, nil
+    default :diff_disabled,           false
+    default :diff_filesize_threshold, 10000000
+    default :diff_output_threshold,   1000000
+    default :local_mode, false
+
+    # Configures the mode of operation for ChefFS, which is applied to the
+    # ChefFS-based knife commands and chef-client's local mode. (ChefFS-based
+    # knife commands include: knife delete, knife deps, knife diff, knife down,
+    # knife edit, knife list, knife show, knife upload, and knife xargs.)
+    #
+    # Valid values are:
+    # * "static": ChefFS only manages objects that exist in a traditional Chef
+    #   Repo as of Chef 11.
+    # * "everything": ChefFS manages all object types that existed on the OSS
+    #   Chef 11 server.
+    # * "hosted_everything": ChefFS manages all object types as of the Chef 12
+    #   Server, including RBAC objects and Policyfile objects (new to Chef 12).
+    default :repo_mode do
+      if local_mode && !chef_zero.osc_compat
+        "hosted_everything"
+      elsif chef_server_url =~ /\/+organizations\/.+/
+        "hosted_everything"
+      else
+        "everything"
+      end
+    end
+
+    default :pid_file, nil
+
+    # Whether Chef Zero local mode should bind to a port. All internal requests
+    # will go through the socketless code path regardless, so the socket is
+    # only needed if other processes will connect to the local mode server.
+    #
+    # For compatibility this is set to true but it will be changed to false in
+    # the future.
+    default :listen, true
+
+    config_context :chef_zero do
+      config_strict_mode true
+      default(:enabled) { ChefConfig::Config.local_mode }
+      default :host, "localhost"
+      default :port, 8889.upto(9999) # Will try ports from 8889-9999 until one works
+
+      # When set to a String, Chef Zero disables multitenant support.  This is
+      # what you want when using Chef Zero to serve a single Chef Repo. Setting
+      # this to `false` enables multi-tenant.
+      default :single_org, "chef"
+
+      # Whether Chef Zero should operate in a mode analogous to OSS Chef Server
+      # 11 (true) or Chef Server 12 (false). Chef Zero can still serve
+      # policyfile objects in Chef 11 mode, as long as `repo_mode` is set to
+      # "hosted_everything". The primary differences are:
+      # * Chef 11 mode doesn't support multi-tennant, so there is no
+      #   distinction between global and org-specific objects (since there are
+      #   no orgs).
+      # * Chef 11 mode doesn't expose RBAC objects
+      default :osc_compat, false
+    end
+    default :chef_server_url, "https://localhost:443"
+
+    default(:chef_server_root) do
+      # if the chef_server_url is a path to an organization, aka
+      # 'some_url.../organizations/*' then remove the '/organization/*' by default
+      if self.configuration[:chef_server_url] =~ /\/organizations\/\S*$/
+        self.configuration[:chef_server_url].split("/")[0..-3].join("/")
+      elsif self.configuration[:chef_server_url] # default to whatever chef_server_url is
+        self.configuration[:chef_server_url]
+      else
+        "https://localhost:443"
+      end
+    end
+
+    default :rest_timeout, 300
+    default :yum_timeout, 900
+    default :yum_lock_timeout, 30
+    default :solo,  false
+    default :splay, nil
+    default :why_run, false
+    default :color, false
+    default :client_fork, true
+    default :ez, false
+    default :enable_reporting, true
+    default :enable_reporting_url_fatals, false
+    # Possible values for :audit_mode
+    # :enabled, :disabled, :audit_only,
+    #
+    # TODO: 11 Dec 2014: Currently audit-mode is an experimental feature
+    # and is disabled by default. When users choose to enable audit-mode,
+    # a warning is issued in application/client#reconfigure.
+    # This can be removed when audit-mode is enabled by default.
+    default :audit_mode, :disabled
+
+    # Chef only needs ohai to run the hostname plugin for the most basic
+    # functionality. If the rest of the ohai plugins are not needed (like in
+    # most of our testing scenarios)
+    default :minimal_ohai, false
+
+    ###
+    # Policyfile Settings
+    #
+    # Policyfile is a feature where a node gets its run list and cookbook
+    # version set from a single document on the server instead of expanding the
+    # run list and having the server compute the cookbook version set based on
+    # environment constraints.
+    #
+    # Policyfiles are auto-versioned. The user groups nodes by `policy_name`,
+    # which generally describes a hosts's functional role, and `policy_group`,
+    # which generally groups nodes by deployment phase (a.k.a., "environment").
+    # The Chef Server maps a given set of `policy_name` plus `policy_group` to
+    # a particular revision of a policy.
+
+    default :policy_name, nil
+    default :policy_group, nil
+
+    # Policyfiles can have multiple run lists, via the named run list feature.
+    # Generally this will be set by a CLI option via Chef::Application::Client,
+    # but it could be set in client.rb if desired.
+
+    default :named_run_list, nil
+
+    # During initial development, users were required to set `use_policyfile true`
+    # in `client.rb` to opt-in to policyfile use. Chef Client now examines
+    # configuration, node json, and the stored node to determine if policyfile
+    # usage is desired. This flag is still honored if set, but is unnecessary.
+    default :use_policyfile, false
+
+    # Policyfiles can be used in a native mode (default) or compatibility mode.
+    # Native mode requires Chef Server 12.1 (it can be enabled via feature flag
+    # on some prior versions). In native mode, policies and associated
+    # cookbooks are accessed via feature-specific APIs. In compat mode,
+    # policies are stored as data bags and cookbooks are stored at the
+    # cookbooks/ endpoint. Compatibility mode can be dangerous on existing Chef
+    # Servers; it's recommended to upgrade your Chef Server rather than use
+    # compatibility mode. Compatibility mode remains available so you can use
+    # policyfiles with servers that don't yet support the native endpoints.
+    default :policy_document_native_api, true
+
+    # When policyfiles are used in compatibility mode, `policy_name` and
+    # `policy_group` are instead specified using a combined configuration
+    # setting, `deployment_group`. For example, if policy_name should be
+    # "webserver" and policy_group should be "staging", then `deployment_group`
+    # should be set to "webserver-staging", which is the name of the data bag
+    # item that the policy will be stored as. NOTE: this setting only has an
+    # effect if `policy_document_native_api` is set to `false`.
+    default :deployment_group, nil
+
+    # Set these to enable SSL authentication / mutual-authentication
+    # with the server
+
+    # Client side SSL cert/key for mutual auth
+    default :ssl_client_cert, nil
+    default :ssl_client_key, nil
+
+    # Whether or not to verify the SSL cert for all HTTPS requests. When set to
+    # :verify_peer (default), all HTTPS requests will be validated regardless of other
+    # SSL verification settings. When set to :verify_none no HTTPS requests will
+    # be validated.
+    default :ssl_verify_mode, :verify_peer
+
+    # Whether or not to verify the SSL cert for HTTPS requests to the Chef
+    # server API. If set to `true`, the server's cert will be validated
+    # regardless of the :ssl_verify_mode setting. This is set to `true` when
+    # running in local-mode.
+    # NOTE: This is a workaround until verify_peer is enabled by default.
+    default(:verify_api_cert) { ChefConfig::Config.local_mode }
+
+    # Path to the default CA bundle files.
+    default :ssl_ca_path, nil
+    default(:ssl_ca_file) do
+      if ChefConfig.windows? and embedded_path = embedded_dir
+        cacert_path = File.join(embedded_path, "ssl/certs/cacert.pem")
+        cacert_path if File.exist?(cacert_path)
+      else
+        nil
+      end
+    end
+
+    # A directory that contains additional SSL certificates to trust. Any
+    # certificates in this directory will be added to whatever CA bundle ruby
+    # is using. Use this to add self-signed certs for your Chef Server or local
+    # HTTP file servers.
+    default(:trusted_certs_dir) { PathHelper.join(config_dir, "trusted_certs") }
+
+    # Where should chef-solo download recipes from?
+    default :recipe_url, nil
+
+    # Set to true if Chef is to set OpenSSL to run in FIPS mode
+    default(:fips) { ENV["CHEF_FIPS"] == "1" }
+
+    # Initialize openssl
+    def self.init_openssl
+      if fips
+        self.enable_fips_mode
+      end
+    end
+
+    # Sets the version of the signed header authentication protocol to use (see
+    # the 'mixlib-authorization' project for more detail). Currently, versions
+    # 1.0, 1.1, and 1.3 are available.
+    default :authentication_protocol_version do
+      if fips
+        "1.3"
+      else
+        "1.1"
+      end
+    end
+
+    # This key will be used to sign requests to the Chef server. This location
+    # must be writable by Chef during initial setup when generating a client
+    # identity on the server.
+    #
+    # The chef-server will look up the public key for the client using the
+    # `node_name` of the client.
+    #
+    # If chef-zero is enabled, this defaults to nil (no authentication).
+    default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
+
+    # When registering the client, should we allow the client key location to
+    # be a symlink?  eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
+    # If the path of the key goes through a directory like /tmp this should
+    # never be set to true or its possibly an easily exploitable security hole.
+    default :follow_client_key_symlink, false
+
+    # This secret is used to decrypt encrypted data bag items.
+    default(:encrypted_data_bag_secret) do
+      if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret"))
+        platform_specific_path("/etc/chef/encrypted_data_bag_secret")
+      else
+        nil
+      end
+    end
+
+    # As of Chef 11.0, version "1" is the default encrypted data bag item
+    # format. Version "2" is available which adds encrypt-then-mac protection.
+    # To maintain compatibility, versions other than 1 must be opt-in.
+    #
+    # Set this to `2` if you have chef-client 11.6.0+ in your infrastructure.
+    # Set this to `3` if you have chef-client 11.?.0+, ruby 2 and OpenSSL >= 1.0.1 in your infrastructure. (TODO)
+    default :data_bag_encrypt_version, 1
+
+    # When reading data bag items, any supported version is accepted. However,
+    # if all encrypted data bags have been generated with the version 2 format,
+    # it is recommended to disable support for earlier formats to improve
+    # security. For example, the version 2 format is identical to version 1
+    # except for the addition of an HMAC, so an attacker with MITM capability
+    # could downgrade an encrypted data bag to version 1 as part of an attack.
+    default :data_bag_decrypt_minimum_version, 0
+
+    # If there is no file in the location given by `client_key`, chef-client
+    # will temporarily use the "validator" identity to generate one. If the
+    # `client_key` is not present and the `validation_key` is also not present,
+    # chef-client will not be able to authenticate to the server.
+    #
+    # The `validation_key` is never used if the `client_key` exists.
+    #
+    # If chef-zero is enabled, this defaults to nil (no authentication).
+    default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
+    default :validation_client_name, "chef-validator"
+
+    # When creating a new client via the validation_client account, Chef 11
+    # servers allow the client to generate a key pair locally and send the
+    # public key to the server. This is more secure and helps offload work from
+    # the server, enhancing scalability. If enabled and the remote server
+    # implements only the Chef 10 API, client registration will not work
+    # properly.
+    #
+    # The default value is `true`. Set to `false` to disable client-side key
+    # generation (server generates client keys).
+    default(:local_key_generation) { true }
+
+    # Zypper package provider gpg checks. Set to true to enable package
+    # gpg signature checking. This will be default in the
+    # future. Setting to false disables the warnings.
+    # Leaving this set to nil or false is a security hazard!
+    default :zypper_check_gpg, nil
+
+    # Report Handlers
+    default :report_handlers, []
+
+    # Event Handlers
+    default :event_handlers, []
+
+    default :disable_event_loggers, false
+
+    # Exception Handlers
+    default :exception_handlers, []
+
+    # Start handlers
+    default :start_handlers, []
+
+    # Syntax Check Cache. Knife keeps track of files that is has already syntax
+    # checked by storing files in this directory. `syntax_check_cache_path` is
+    # the new (and preferred) configuration setting. If not set, knife will
+    # fall back to using cache_options[:path], which is deprecated but exists in
+    # many client configs generated by pre-Chef-11 bootstrappers.
+    default(:syntax_check_cache_path) { cache_options[:path] }
+
+    # Deprecated:
+    # Move this to the default value of syntax_cache_path when this is removed.
+    default(:cache_options) { { :path => PathHelper.join(config_dir, "syntaxcache") } }
+
+    # Whether errors should be raised for deprecation warnings. When set to
+    # `false` (the default setting), a warning is emitted but code using
+    # deprecated methods/features/etc. should work normally otherwise. When set
+    # to `true`, usage of deprecated methods/features will raise a
+    # `DeprecatedFeatureError`. This is used by Chef's tests to ensure that
+    # deprecated functionality is not used internally by Chef.  End users
+    # should generally leave this at the default setting (especially in
+    # production), but it may be useful when testing cookbooks or other code if
+    # the user wishes to aggressively address deprecations.
+    default(:treat_deprecation_warnings_as_errors) do
+      # Using an environment variable allows this setting to be inherited in
+      # tests that spawn new processes.
+      ENV.key?("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
+    end
+
+    # knife configuration data
+    config_context :knife do
+      default :ssh_port, nil
+      default :ssh_user, nil
+      default :ssh_attribute, nil
+      default :ssh_gateway, nil
+      default :bootstrap_version, nil
+      default :bootstrap_proxy, nil
+      default :bootstrap_template, nil
+      default :secret, nil
+      default :secret_file, nil
+      default :identity_file, nil
+      default :host_key_verify, nil
+      default :forward_agent, nil
+      default :sort_status_reverse, nil
+      default :hints, {}
+    end
+
+    def self.set_defaults_for_windows
+      # Those lists of regular expressions define what chef considers a
+      # valid user and group name
+      # From http://technet.microsoft.com/en-us/library/cc776019(WS.10).aspx
+      principal_valid_regex_part = '[^"\/\\\\\[\]\:;|=,+*?<>]+'
+      default :user_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
+      default :group_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
+
+      default :fatal_windows_admin_check, false
+    end
+
+    def self.set_defaults_for_nix
+      # Those lists of regular expressions define what chef considers a
+      # valid user and group name
+      #
+      # user/group cannot start with '-', '+' or '~'
+      # user/group cannot contain ':', ',' or non-space-whitespace or null byte
+      # everything else is allowed (UTF-8, spaces, etc) and we delegate to your O/S useradd program to barf or not
+      # copies: http://anonscm.debian.org/viewvc/pkg-shadow/debian/trunk/debian/patches/506_relaxed_usernames?view=markup
+      default :user_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
+      default :group_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
+    end
+
+    # Those lists of regular expressions define what chef considers a
+    # valid user and group name
+    if ChefConfig.windows?
+      set_defaults_for_windows
+    else
+      set_defaults_for_nix
+    end
+
+    # This provides a hook which rspec can stub so that we can avoid twiddling
+    # global state in tests.
+    def self.env
+      ENV
+    end
+
+    def self.windows_home_path
+      ChefConfig.logger.deprecation("Chef::Config.windows_home_path is now deprecated.  Consider using Chef::Util::PathHelper.home instead.")
+      PathHelper.home
+    end
+
+    # returns a platform specific path to the user home dir if set, otherwise default to current directory.
+    default( :user_home ) { PathHelper.home || Dir.pwd }
+
+    # Enable file permission fixup for selinux. Fixup will be done
+    # only if selinux is enabled in the system.
+    default :enable_selinux_file_permission_fixup, true
+
+    # Use atomic updates (i.e. move operation) while updating contents
+    # of the files resources. When set to false copy operation is
+    # used to update files.
+    default :file_atomic_update, true
+
+    # There are 3 possible values for this configuration setting.
+    # true => file staging is done in the destination directory
+    # false => file staging is done via tempfiles under ENV['TMP']
+    # :auto => file staging will try using destination directory if possible and
+    #   will fall back to ENV['TMP'] if destination directory is not usable.
+    default :file_staging_uses_destdir, :auto
+
+    # Exit if another run is in progress and the chef-client is unable to
+    # get the lock before time expires. If nil, no timeout is enforced. (Exits
+    # immediately if 0.)
+    default :run_lock_timeout, nil
+
+    # Number of worker threads for syncing cookbooks in parallel. Increasing
+    # this number can result in gateway errors from the server (namely 503 and 504).
+    # If you are seeing this behavior while using the default setting, reducing
+    # the number of threads will help.
+    default :cookbook_sync_threads, 10
+
+    # At the beginning of the Chef Client run, the cookbook manifests are downloaded which
+    # contain URLs for every file in every relevant cookbook.  Most of the files
+    # (recipes, resources, providers, libraries, etc) are immediately synchronized
+    # at the start of the run.  The handling of "files" and "templates" directories,
+    # however, have two modes of operation.  They can either all be downloaded immediately
+    # at the start of the run (no_lazy_load==true) or else they can be lazily loaded as
+    # cookbook_file or template resources are converged which require them (no_lazy_load==false).
+    #
+    # The advantage of lazily loading these files is that unnecessary files are not
+    # synchronized.  This may be useful to users with large files checked into cookbooks which
+    # are only selectively downloaded to a subset of clients which use the cookbook.  However,
+    # better solutions are to either isolate large files into individual cookbooks and only
+    # include those cookbooks in the run lists of the servers that need them -- or move to
+    # using remote_file and a more appropriate backing store like S3 for large file
+    # distribution.
+    #
+    # The disadvantages of lazily loading files are that users some time find it
+    # confusing that their cookbooks are not fully synchronzied to the cache initially,
+    # and more importantly the time-sensitive URLs which are in the manifest may time
+    # out on long Chef runs before the resource that uses the file is converged
+    # (leading to many confusing 403 errors on template/cookbook_file resources).
+    #
+    default :no_lazy_load, true
+
+    # Default for the chef_gem compile_time attribute.  Nil is the same as true but will emit
+    # warnings on every use of chef_gem prompting the user to be explicit.  If the user sets this to
+    # true then the user will get backcompat behavior but with a single nag warning that cookbooks
+    # may break with this setting in the future.  The false setting is the recommended setting and
+    # will become the default.
+    default :chef_gem_compile_time, nil
+
+    # A whitelisted array of attributes you want sent over the wire when node
+    # data is saved.
+    # The default setting is nil, which collects all data. Setting to [] will not
+    # collect any data for save.
+    default :automatic_attribute_whitelist, nil
+    default :default_attribute_whitelist, nil
+    default :normal_attribute_whitelist, nil
+    default :override_attribute_whitelist, nil
+
+    config_context :windows_service do
+      # Set `watchdog_timeout` to the number of seconds to wait for a chef-client run
+      # to finish
+      default :watchdog_timeout, 2 * (60 * 60) # 2 hours
+    end
+
+    # Add an empty and non-strict config_context for chefdk. This lets the user
+    # have code like `chefdk.generator_cookbook "/path/to/cookbook"` in their
+    # config.rb, and it will be ignored by tools like knife and ohai. ChefDK
+    # itself can define the config options it accepts and enable strict mode,
+    # and that will only apply when running `chef` commands.
+    config_context :chefdk do
+    end
+
+    configurable(:http_proxy)
+    configurable(:http_proxy_user)
+    configurable(:http_proxy_pass)
+    configurable(:https_proxy)
+    configurable(:https_proxy_user)
+    configurable(:https_proxy_pass)
+    configurable(:ftp_proxy)
+    configurable(:ftp_proxy_user)
+    configurable(:ftp_proxy_pass)
+    configurable(:no_proxy)
+
+    # Public method that users should call to export proxies to the appropriate
+    # environment variables.  This method should be called after the config file is
+    # parsed and loaded.
+    # TODO add some post-file-parsing logic that automatically calls this so
+    # users don't have to
+    def self.export_proxies
+      export_proxy("http", http_proxy, http_proxy_user, http_proxy_pass) if http_proxy
+      export_proxy("https", https_proxy, https_proxy_user, https_proxy_pass) if https_proxy
+      export_proxy("ftp", ftp_proxy, ftp_proxy_user, ftp_proxy_pass) if ftp_proxy
+      export_no_proxy(no_proxy) if no_proxy
+    end
+
+    # Builds a proxy uri and exports it to the appropriate environment variables. Examples:
+    #   http://username:password@hostname:port
+    #   https://username@hostname:port
+    #   ftp://hostname:port
+    # when
+    #   scheme = "http", "https", or "ftp"
+    #   hostport = hostname:port or scheme://hostname:port
+    #   user = username
+    #   pass = password
+    # @api private
+    def self.export_proxy(scheme, path, user, pass)
+      path = "#{scheme}://#{path}" unless path.include?("://")
+      # URI.split returns the following parts:
+      # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
+      parts = URI.split(URI.encode(path))
+      # URI::Generic.build requires an integer for the port, but URI::split gives
+      # returns a string for the port.
+      parts[3] = parts[3].to_i if parts[3]
+      if user && !user.empty?
+        userinfo = URI.encode(URI.encode(user), "@:")
+        if pass
+          userinfo << ":#{URI.encode(URI.encode(pass), '@:')}"
+        end
+        parts[1] = userinfo
+      end
+
+      path = URI::Generic.build(parts).to_s
+      ENV["#{scheme}_proxy".downcase] = path unless ENV["#{scheme}_proxy".downcase]
+      ENV["#{scheme}_proxy".upcase] = path unless ENV["#{scheme}_proxy".upcase]
+    end
+
+    # @api private
+    def self.export_no_proxy(value)
+      ENV["no_proxy"] = value unless ENV["no_proxy"]
+      ENV["NO_PROXY"] = value unless ENV["NO_PROXY"]
+    end
+
+    # Chef requires an English-language UTF-8 locale to function properly.  We attempt
+    # to use the 'locale -a' command and search through a list of preferences until we
+    # find one that we can use.  On Ubuntu systems we should find 'C.UTF-8' and be
+    # able to use that even if there is no English locale on the server, but Mac, Solaris,
+    # AIX, etc do not have that locale.  We then try to find an English locale and fall
+    # back to 'C' if we do not.  The choice of fallback is pick-your-poison.  If we try
+    # to do the work to return a non-US UTF-8 locale then we fail inside of providers when
+    # things like 'svn info' return Japanese and we can't parse them.  OTOH, if we pick 'C' then
+    # we will blow up on UTF-8 characters.  Between the warn we throw and the Encoding
+    # exception that ruby will throw it is more obvious what is broken if we drop UTF-8 by
+    # default rather than drop English.
+    #
+    # If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
+    # available English UTF-8 locale.  However, all modern POSIXen should support 'locale -a'.
+    def self.guess_internal_locale
+      # https://github.com/opscode/chef/issues/2181
+      # Some systems have the `locale -a` command, but the result has
+      # invalid characters for the default encoding.
+      #
+      # For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
+      # `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
+      cmd = Mixlib::ShellOut.new("locale -a").run_command
+      cmd.error!
+      locales = cmd.stdout.split
+      case
+      when locales.include?("C.UTF-8")
+        "C.UTF-8"
+      when locales.include?("en_US.UTF-8"), locales.include?("en_US.utf8")
+        "en_US.UTF-8"
+      when locales.include?("en.UTF-8")
+        "en.UTF-8"
+      else
+        # Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
+        guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
+        unless guesses.empty?
+          guessed_locale = guesses.first
+          # Transform into the form en_ZZ.UTF-8
+          guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
+        else
+          ChefConfig.logger.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
+          "C"
+        end
+      end
+    rescue
+      if ChefConfig.windows?
+        ChefConfig.logger.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
+      else
+        ChefConfig.logger.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+      end
+      "en_US.UTF-8"
+    end
+
+    default :internal_locale, guess_internal_locale
+
+    # Force UTF-8 Encoding, for when we fire up in the 'C' locale or other strange locales (e.g.
+    # japanese windows encodings).  If we do not do this, then knife upload will fail when a cookbook's
+    # README.md has UTF-8 characters that do not encode in whatever surrounding encoding we have been
+    # passed.  Effectively, the Chef Ecosystem is globally UTF-8 by default.  Anyone who wants to be
+    # able to upload Shift_JIS or ISO-8859-1 files needs to mark *those* files explicitly with
+    # magic tags to make ruby correctly identify the encoding being used.  Changing this default will
+    # break Chef community cookbooks and is very highly discouraged.
+    default :ruby_encoding, Encoding::UTF_8
+
+    # If installed via an omnibus installer, this gives the path to the
+    # "embedded" directory which contains all of the software packaged with
+    # omnibus. This is used to locate the cacert.pem file on windows.
+    def self.embedded_dir
+      Pathname.new(_this_file).ascend do |path|
+        if path.basename.to_s == "embedded"
+          return path.to_s
+        end
+      end
+
+      nil
+    end
+
+    # Path to this file in the current install.
+    def self._this_file
+      File.expand_path(__FILE__)
+    end
+
+    # Set fips mode in openssl. Do any patching necessary to make
+    # sure Chef runs do not crash.
+    # @api private
+    def self.enable_fips_mode
+      ChefConfig.logger.warn "The `fips` feature is still a work in progress. This feature is incomplete."
+      OpenSSL.fips_mode = true
+      require "digest"
+      require "digest/sha1"
+      require "digest/md5"
+      Digest.const_set("SHA1", OpenSSL::Digest::SHA1)
+      OpenSSL::Digest.const_set("MD5", Digest::MD5)
+    end
+  end
+end
diff --git a/chef-config/lib/chef-config/exceptions.rb b/chef-config/lib/chef-config/exceptions.rb
new file mode 100644
index 0000000..db10a5f
--- /dev/null
+++ b/chef-config/lib/chef-config/exceptions.rb
@@ -0,0 +1,26 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef-config/windows"
+require "chef-config/logger"
+
+module ChefConfig
+
+  class ConfigurationError < ArgumentError; end
+  class InvalidPath < StandardError; end
+
+end
diff --git a/chef-config/lib/chef-config/logger.rb b/chef-config/lib/chef-config/logger.rb
new file mode 100644
index 0000000..d239e85
--- /dev/null
+++ b/chef-config/lib/chef-config/logger.rb
@@ -0,0 +1,59 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module ChefConfig
+
+  # Implements enough of Logger's API that we can use it in place of a real
+  # logger for `ChefConfig.logger`
+  class NullLogger
+
+    def <<(_msg)
+    end
+
+    def add(_severity, _message = nil, _progname = nil)
+    end
+
+    def debug(_progname = nil, &block)
+    end
+
+    def info(_progname = nil, &block)
+    end
+
+    def warn(_progname = nil, &block)
+    end
+
+    def deprecation(_progname = nil, &block)
+    end
+
+    def error(_progname = nil, &block)
+    end
+
+    def fatal(_progname = nil, &block)
+    end
+
+  end
+
+  @logger = NullLogger.new
+
+  def self.logger=(new_logger)
+    @logger = new_logger
+  end
+
+  def self.logger
+    @logger
+  end
+end
diff --git a/chef-config/lib/chef-config/package_task.rb b/chef-config/lib/chef-config/package_task.rb
new file mode 100644
index 0000000..6c7a4d6
--- /dev/null
+++ b/chef-config/lib/chef-config/package_task.rb
@@ -0,0 +1,222 @@
+#
+# Author:: Kartik Null Cating-Subramanian (<ksubramanian at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "rake"
+require "rubygems"
+require "rubygems/package_task"
+
+module ChefConfig
+  class PackageTask < Rake::TaskLib
+
+    # Full path to root of top-level repository.  All other files (like VERSION or
+    # lib/<module_path>/version.rb are rooted at this path).
+    attr_accessor :root_path
+
+    # Name of the top-level module/library build built.  This is used to define
+    # the top level module which contains VERSION and MODULE_ROOT.
+    attr_accessor :module_name
+
+    # Should the generated version.rb be in a class or module?  Default is false (module).
+    attr_accessor :generate_version_class
+
+    # Paths to the roots of any components that also support ChefPackageTask.
+    # If relative paths are provided, they are rooted against root_path.
+    attr_accessor :component_paths
+
+    # This is the module name as it appears on the path "lib/module/".
+    # e.g. for module_name  "ChefDK", you'd want module_path to be "chef-dk".
+    # The default is module_name but lower-cased.
+    attr_writer :module_path
+
+    def module_path
+      @module_path || module_name.downcase
+    end
+
+    # Directory used to store package files and output that is generated.
+    # This has the same meaning (or lack thereof) as package_dir in
+    # rake/packagetask.
+    attr_accessor :package_dir
+
+    # Name of git remote used to push tags during a release.  Default is origin.
+    attr_accessor :git_remote
+
+    def initialize(root_path = nil, module_name = nil)
+      init(root_path, module_name)
+      yield self if block_given?
+      define unless root_path.nil? || module_name.nil?
+    end
+
+    def init(root_path, module_name)
+      @root_path = root_path
+      @module_name = module_name
+      @component_paths = []
+      @module_path = nil
+      @package_dir = "pkg"
+      @git_remote = "origin"
+      @generate_version_class = false
+    end
+
+    def component_full_paths
+      component_paths.map { |path| File.expand_path(path, root_path) }
+    end
+
+    def version_rb_path
+      File.expand_path("lib/#{module_path}/version.rb", root_path)
+    end
+
+    def chef_root_path
+      module_name == "Chef" ? root_path : File.dirname(root_path)
+    end
+
+    def version
+      IO.read(File.join(chef_root_path, "VERSION")).strip
+    end
+
+    def full_package_dir
+      File.expand_path(package_dir, root_path)
+    end
+
+    def class_or_module
+      generate_version_class ? "class" : "module"
+    end
+
+    def with_clean_env(&block)
+      if defined?(Bundler)
+        Bundler.with_clean_env(&block)
+      else
+        block.call
+      end
+    end
+
+    def define
+      raise "Need to provide package root and module name" if root_path.nil? || module_name.nil?
+
+      desc "Build Gems of component dependencies"
+      task :package_components do
+        component_full_paths.each do |component_path|
+          Dir.chdir(component_path) do
+            sh "rake package"
+          end
+        end
+      end
+
+      task :package => :package_components
+
+      desc "Build and install component dependencies"
+      task :install_components => :package_components do
+        component_full_paths.each do |component_path|
+          Dir.chdir(component_path) do
+            sh "rake install"
+          end
+        end
+      end
+
+      task :install => :install_components
+
+      desc "Clean up builds of component dependencies"
+      task :clobber_component_packages do
+        component_full_paths.each do |component_path|
+          Dir.chdir(component_path) do
+            sh "rake clobber_package"
+          end
+        end
+      end
+
+      task :clobber_package => :clobber_component_packages
+
+      desc "Update the version number for component dependencies"
+      task :update_components_versions do
+        component_full_paths.each do |component_path|
+          Dir.chdir(component_path) do
+            sh "rake version"
+          end
+        end
+      end
+
+      desc 'Regenerate lib/#{@module_path}/version.rb from VERSION file'
+      task :version => :update_components_versions do
+        contents = <<-VERSION_RB
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# NOTE: This file is generated by running `rake version` in the top level of
+# this repo. Do not edit this manually. Edit the VERSION file and run the rake
+# task instead.
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+#{class_or_module} #{module_name}
+  #{module_name.upcase}_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
+  VERSION = "#{version}"
+end
+
+#
+# NOTE: the Chef::Version class is defined in version_class.rb
+#
+# NOTE: DO NOT Use the Chef::Version class on #{module_name}::VERSIONs.  The
+#       Chef::Version class is for _cookbooks_ only, and cannot handle
+#       pre-release versions like "10.14.0.rc.2".  Please use Rubygem's
+#       Gem::Version class instead.
+#
+        VERSION_RB
+        IO.write(version_rb_path, contents)
+      end
+
+      Dir[File.expand_path("*gemspec", root_path)].reverse.each do |gemspec_path|
+        gemspec = eval(IO.read(gemspec_path))
+        Gem::PackageTask.new(gemspec) do |task|
+          task.package_dir = full_package_dir
+        end
+      end
+
+      desc "Build and install a #{module_path} gem"
+      task :install => [:package] do
+        with_clean_env do
+          full_module_path = File.join(full_package_dir, module_path)
+          sh %{gem install #{full_module_path}-#{version}.gem --no-rdoc --no-ri}
+        end
+      end
+
+      task :uninstall do
+        sh %{gem uninstall #{module_path} -x -v #{version} }
+      end
+
+      desc "Build it, tag it and ship it"
+      task :ship => [:clobber_package, :gem] do
+        sh("git tag #{version}")
+        sh("git push #{git_remote} --tags")
+        Dir[File.expand_path("*.gem", full_package_dir)].reverse.each do |built_gem|
+          sh("gem push #{built_gem}")
+        end
+      end
+    end
+  end
+
+end
diff --git a/chef-config/lib/chef-config/path_helper.rb b/chef-config/lib/chef-config/path_helper.rb
new file mode 100644
index 0000000..7fc79ba
--- /dev/null
+++ b/chef-config/lib/chef-config/path_helper.rb
@@ -0,0 +1,264 @@
+#
+# Author:: Bryan McLellan <btm at loftninjas.org>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef-config/windows"
+require "chef-config/logger"
+require "chef-config/exceptions"
+
+module ChefConfig
+  class PathHelper
+    # Maximum characters in a standard Windows path (260 including drive letter and NUL)
+    WIN_MAX_PATH = 259
+
+    def self.dirname(path)
+      if ChefConfig.windows?
+        # Find the first slash, not counting trailing slashes
+        end_slash = path.size
+        loop do
+          slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]/, end_slash - 1)
+          if !slash
+            return end_slash == path.size ? "." : path_separator
+          elsif slash == end_slash - 1
+            end_slash = slash
+          else
+            return path[0..slash - 1]
+          end
+        end
+      else
+        ::File.dirname(path)
+      end
+    end
+
+    BACKSLASH = '\\'.freeze
+
+    def self.path_separator
+      if ChefConfig.windows?
+        File::ALT_SEPARATOR || BACKSLASH
+      else
+        File::SEPARATOR
+      end
+    end
+
+    def self.join(*args)
+      path_separator_regex = Regexp.escape(File::SEPARATOR)
+      unless path_separator == File::SEPARATOR
+        path_separator_regex << Regexp.escape(path_separator)
+      end
+
+      trailing_slashes = /[#{path_separator_regex}]+$/
+      leading_slashes = /^[#{path_separator_regex}]+/
+
+      args.flatten.inject() do |joined_path, component|
+        joined_path = joined_path.sub(trailing_slashes, "")
+        component = component.sub(leading_slashes, "")
+        joined_path += "#{path_separator}#{component}"
+      end
+    end
+
+    def self.validate_path(path)
+      if ChefConfig.windows?
+        unless printable?(path)
+          msg = "Path '#{path}' contains non-printable characters. Check that backslashes are escaped with another backslash (e.g. C:\\\\Windows) in double-quoted strings."
+          ChefConfig.logger.error(msg)
+          raise ChefConfig::InvalidPath, msg
+        end
+
+        if windows_max_length_exceeded?(path)
+          ChefConfig.logger.debug("Path '#{path}' is longer than #{WIN_MAX_PATH}, prefixing with'\\\\?\\'")
+          path.insert(0, "\\\\?\\")
+        end
+      end
+
+      path
+    end
+
+    def self.windows_max_length_exceeded?(path)
+      # Check to see if paths without the \\?\ prefix are over the maximum allowed length for the Windows API
+      # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
+      unless path =~ /^\\\\?\\/
+        if path.length > WIN_MAX_PATH
+          return true
+        end
+      end
+
+      false
+    end
+
+    def self.printable?(string)
+      # returns true if string is free of non-printable characters (escape sequences)
+      # this returns false for whitespace escape sequences as well, e.g. \n\t
+      if string =~ /[^[:print:]]/
+        false
+      else
+        true
+      end
+    end
+
+    # Produces a comparable path.
+    def self.canonical_path(path, add_prefix = true)
+      # First remove extra separators and resolve any relative paths
+      abs_path = File.absolute_path(path)
+
+      if ChefConfig.windows?
+        # Add the \\?\ API prefix on Windows unless add_prefix is false
+        # Downcase on Windows where paths are still case-insensitive
+        abs_path.gsub!(::File::SEPARATOR, path_separator)
+        if add_prefix && abs_path !~ /^\\\\?\\/
+          abs_path.insert(0, "\\\\?\\")
+        end
+
+        abs_path.downcase!
+      end
+
+      abs_path
+    end
+
+    def self.cleanpath(path)
+      path = Pathname.new(path).cleanpath.to_s
+      # ensure all forward slashes are backslashes
+      if ChefConfig.windows?
+        path = path.gsub(File::SEPARATOR, path_separator)
+      end
+      path
+    end
+
+    def self.paths_eql?(path1, path2)
+      canonical_path(path1) == canonical_path(path2)
+    end
+
+    # Paths which may contain glob-reserved characters need
+    # to be escaped before globbing can be done.
+    # http://stackoverflow.com/questions/14127343
+    def self.escape_glob(*parts)
+      path = cleanpath(join(*parts))
+      path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\" + x }
+    end
+
+    def self.relative_path_from(from, to)
+      Pathname.new(cleanpath(to)).relative_path_from(Pathname.new(cleanpath(from)))
+    end
+
+    # Retrieves the "home directory" of the current user while trying to ascertain the existence
+    # of said directory.  The path returned uses / for all separators (the ruby standard format).
+    # If the home directory doesn't exist or an error is otherwise encountered, nil is returned.
+    #
+    # If a set of path elements is provided, they are appended as-is to the home path if the
+    # homepath exists.
+    #
+    # If an optional block is provided, the joined path is passed to that block if the home path is
+    # valid and the result of the block is returned instead.
+    #
+    # Home-path discovery is performed once.  If a path is discovered, that value is memoized so
+    # that subsequent calls to home_dir don't bounce around.
+    #
+    # See self.all_homes.
+    def self.home(*args)
+      @@home_dir ||= self.all_homes { |p| break p }
+      if @@home_dir
+        path = File.join(@@home_dir, *args)
+        block_given? ? (yield path) : path
+      end
+    end
+
+    # See self.home.  This method performs a similar operation except that it yields all the different
+    # possible values of 'HOME' that one could have on this platform.  Hence, on windows, if
+    # HOMEDRIVE\HOMEPATH and USERPROFILE are different, the provided block will be called twice.
+    # This method goes out and checks the existence of each location at the time of the call.
+    #
+    # The return is a list of all the returned values from each block invocation or a list of paths
+    # if no block is provided.
+    def self.all_homes(*args)
+      paths = []
+      if ChefConfig.windows?
+        # By default, Ruby uses the the following environment variables to determine Dir.home:
+        # HOME
+        # HOMEDRIVE HOMEPATH
+        # USERPROFILE
+        # Ruby only checks to see if the variable is specified - not if the directory actually exists.
+        # On Windows, HOMEDRIVE HOMEPATH can point to a different location (such as an unavailable network mounted drive)
+        # while USERPROFILE points to the location where the user application settings and profile are stored.  HOME
+        # is not defined as an environment variable (usually).  If the home path actually uses UNC, then the prefix is
+        # HOMESHARE instead of HOMEDRIVE.
+        #
+        # We instead walk down the following and only include paths that actually exist.
+        # HOME
+        # HOMEDRIVE HOMEPATH
+        # HOMESHARE HOMEPATH
+        # USERPROFILE
+
+        paths << ENV["HOME"]
+        paths << ENV["HOMEDRIVE"] + ENV["HOMEPATH"] if ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
+        paths << ENV["HOMESHARE"] + ENV["HOMEPATH"] if ENV["HOMESHARE"] && ENV["HOMEPATH"]
+        paths << ENV["USERPROFILE"]
+      end
+      paths << Dir.home if ENV["HOME"]
+
+      # Depending on what environment variables we're using, the slashes can go in any which way.
+      # Just change them all to / to keep things consistent.
+      # Note: Maybe this is a bad idea on some unixy systems where \ might be a valid character depending on
+      # the particular brand of kool-aid you consume.  This code assumes that \ and / are both
+      # path separators on any system being used.
+      paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
+
+      # Filter out duplicate paths and paths that don't exist.
+      valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path) }
+      valid_paths = valid_paths.uniq
+
+      # Join all optional path elements at the end.
+      # If a block is provided, invoke it - otherwise just return what we've got.
+      joined_paths = valid_paths.map { |home_path| File.join(home_path, *args) }
+      if block_given?
+        joined_paths.each { |p| yield p }
+      else
+        joined_paths
+      end
+    end
+
+    # Determine if the given path is protected by OS X System Integrity Protection.
+    def self.is_sip_path?(path, node)
+      if node["platform"] == "mac_os_x" and Gem::Version.new(node["platform_version"]) >= Gem::Version.new("10.11")
+          # todo: parse rootless.conf for this?
+        sip_paths = [
+          "/System", "/bin", "/sbin", "/usr"
+        ]
+        sip_paths.each do |sip_path|
+          ChefConfig.logger.info("This is a SIP path, checking if it in exceptions list.")
+          return true if path.start_with?(sip_path)
+        end
+        false
+      else
+        false
+      end
+    end
+
+    # Determine if the given path is on the exception list for OS X System Integrity Protection.
+    def self.writable_sip_path?(path)
+      # todo: parse rootless.conf for this?
+      sip_exceptions = [
+        "/System/Library/Caches", "/System/Library/Extensions",
+        "/System/Library/Speech", "/System/Library/User Template",
+        "/usr/libexec/cups", "/usr/local", "/usr/share/man"
+      ]
+      sip_exceptions.each do |exception_path|
+        return true if path.start_with?(exception_path)
+      end
+      ChefConfig.logger.error("Cannot write to a SIP Path on OS X 10.11+")
+      false
+    end
+  end
+end
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
new file mode 100644
index 0000000..2e54dd3
--- /dev/null
+++ b/chef-config/lib/chef-config/version.rb
@@ -0,0 +1,34 @@
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# NOTE: This file is generated by running `rake version` in the top level of
+# this repo. Do not edit this manually. Edit the VERSION file and run the rake
+# task instead.
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+module ChefConfig
+  CHEFCONFIG_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
+  VERSION = "12.7.2"
+end
+
+#
+# NOTE: the Chef::Version class is defined in version_class.rb
+#
+# NOTE: DO NOT Use the Chef::Version class on ChefConfig::VERSIONs.  The
+#       Chef::Version class is for _cookbooks_ only, and cannot handle
+#       pre-release versions like "10.14.0.rc.2".  Please use Rubygem's
+#       Gem::Version class instead.
+#
diff --git a/chef-config/lib/chef-config/windows.rb b/chef-config/lib/chef-config/windows.rb
new file mode 100644
index 0000000..9c60611
--- /dev/null
+++ b/chef-config/lib/chef-config/windows.rb
@@ -0,0 +1,28 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+module ChefConfig
+
+  def self.windows?
+    if RUBY_PLATFORM =~ /mswin|mingw|windows/
+      true
+    else
+      false
+    end
+  end
+
+end
diff --git a/chef-config/lib/chef-config/workstation_config_loader.rb b/chef-config/lib/chef-config/workstation_config_loader.rb
new file mode 100644
index 0000000..34ba6d6
--- /dev/null
+++ b/chef-config/lib/chef-config/workstation_config_loader.rb
@@ -0,0 +1,178 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef-config/config"
+require "chef-config/exceptions"
+require "chef-config/logger"
+require "chef-config/path_helper"
+require "chef-config/windows"
+
+module ChefConfig
+  class WorkstationConfigLoader
+
+    # Path to a config file requested by user, (e.g., via command line option). Can be nil
+    attr_accessor :explicit_config_file
+
+    # TODO: initialize this with a logger for Chef and Knife
+    def initialize(explicit_config_file, logger = nil)
+      @explicit_config_file = explicit_config_file
+      @chef_config_dir = nil
+      @config_location = nil
+      @logger = logger || NullLogger.new
+    end
+
+    def no_config_found?
+      config_location.nil?
+    end
+
+    def config_location
+      @config_location ||= (explicit_config_file || locate_local_config)
+    end
+
+    def chef_config_dir
+      if @chef_config_dir.nil?
+        @chef_config_dir = false
+        full_path = working_directory.split(File::SEPARATOR)
+        (full_path.length - 1).downto(0) do |i|
+          candidate_directory = File.join(full_path[0..i] + [".chef"])
+          if File.exist?(candidate_directory) && File.directory?(candidate_directory)
+            @chef_config_dir = candidate_directory
+            break
+          end
+        end
+      end
+      @chef_config_dir
+    end
+
+    def load
+      # Ignore it if there's no explicit_config_file and can't find one at a
+      # default path.
+      return false if config_location.nil?
+
+      if explicit_config_file && !path_exists?(config_location)
+        raise ChefConfig::ConfigurationError, "Specified config file #{config_location} does not exist"
+      end
+
+      # Have to set Config.config_file b/c other config is derived from it.
+      Config.config_file = config_location
+      read_config(IO.read(config_location), config_location)
+    end
+
+    # (Private API, public for test purposes)
+    def env
+      ENV
+    end
+
+    # (Private API, public for test purposes)
+    def path_exists?(path)
+      Pathname.new(path).expand_path.exist?
+    end
+
+    private
+
+    def have_config?(path)
+      if path_exists?(path)
+        logger.info("Using config at #{path}")
+        true
+      else
+        logger.debug("Config not found at #{path}, trying next option")
+        false
+      end
+    end
+
+    def locate_local_config
+      candidate_configs = []
+
+      # Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine)
+      if env["KNIFE_HOME"]
+        candidate_configs << File.join(env["KNIFE_HOME"], "config.rb")
+        candidate_configs << File.join(env["KNIFE_HOME"], "knife.rb")
+      end
+      # Look for $PWD/knife.rb
+      if Dir.pwd
+        candidate_configs << File.join(Dir.pwd, "config.rb")
+        candidate_configs << File.join(Dir.pwd, "knife.rb")
+      end
+      # Look for $UPWARD/.chef/knife.rb
+      if chef_config_dir
+        candidate_configs << File.join(chef_config_dir, "config.rb")
+        candidate_configs << File.join(chef_config_dir, "knife.rb")
+      end
+      # Look for $HOME/.chef/knife.rb
+      PathHelper.home(".chef") do |dot_chef_dir|
+        candidate_configs << File.join(dot_chef_dir, "config.rb")
+        candidate_configs << File.join(dot_chef_dir, "knife.rb")
+      end
+
+      candidate_configs.find do |candidate_config|
+        have_config?(candidate_config)
+      end
+    end
+
+    def working_directory
+      a = if ChefConfig.windows?
+            env["CD"]
+          else
+            env["PWD"]
+          end || Dir.pwd
+
+      a
+    end
+
+    def read_config(config_content, config_file_path)
+      Config.from_string(config_content, config_file_path)
+    rescue SignalException
+      raise
+    rescue SyntaxError => e
+      message = ""
+      message << "You have invalid ruby syntax in your config file #{config_file_path}\n\n"
+      message << "#{e.class.name}: #{e.message}\n"
+      if file_line = e.message[/#{Regexp.escape(config_file_path)}:[\d]+/]
+        line = file_line[/:([\d]+)$/, 1].to_i
+        message << highlight_config_error(config_file_path, line)
+      end
+      raise ChefConfig::ConfigurationError, message
+    rescue Exception => e
+      message = "You have an error in your config file #{config_file_path}\n\n"
+      message << "#{e.class.name}: #{e.message}\n"
+      filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
+      filtered_trace.each { |bt_line| message << "  " << bt_line << "\n" }
+      if !filtered_trace.empty?
+        line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1]
+        message << highlight_config_error(config_file_path, line_nr.to_i)
+      end
+      raise ChefConfig::ConfigurationError, message
+    end
+
+    def highlight_config_error(file, line)
+      config_file_lines = []
+      IO.readlines(file).each_with_index { |l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}" }
+      if line == 1
+        lines = config_file_lines[0..3]
+      else
+        lines = config_file_lines[Range.new(line - 2, line)]
+      end
+      "Relevant file content:\n" + lines.join("\n") + "\n"
+    end
+
+    def logger
+      @logger
+    end
+
+  end
+end
diff --git a/chef-config/spec/spec_helper.rb b/chef-config/spec/spec_helper.rb
new file mode 100644
index 0000000..107becb
--- /dev/null
+++ b/chef-config/spec/spec_helper.rb
@@ -0,0 +1,75 @@
+require "chef-config/windows"
+
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+  # rspec-expectations config goes here. You can use an alternate
+  # assertion/expectation library such as wrong or the stdlib/minitest
+  # assertions if you prefer.
+  config.expect_with :rspec do |expectations|
+    # This option will default to `true` in RSpec 4. It makes the `description`
+    # and `failure_message` of custom matchers include text for helper methods
+    # defined using `chain`, e.g.:
+    #     be_bigger_than(2).and_smaller_than(4).description
+    #     # => "be bigger than 2 and smaller than 4"
+    # ...rather than:
+    #     # => "be bigger than 2"
+    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+  end
+
+  # rspec-mocks config goes here. You can use an alternate test double
+  # library (such as bogus or mocha) by changing the `mock_with` option here.
+  config.mock_with :rspec do |mocks|
+    # Prevents you from mocking or stubbing a method that does not exist on
+    # a real object. This is generally recommended, and will default to
+    # `true` in RSpec 4.
+    mocks.verify_partial_doubles = true
+  end
+
+  # These two settings work together to allow you to limit a spec run
+  # to individual examples or groups you care about by tagging them with
+  # `:focus` metadata. When nothing is tagged with `:focus`, all examples
+  # get run.
+  config.filter_run :focus
+  config.run_all_when_everything_filtered = true
+
+  config.filter_run_excluding :windows_only => true unless ChefConfig.windows?
+  config.filter_run_excluding :unix_only => true if ChefConfig.windows?
+
+  # Limits the available syntax to the non-monkey patched syntax that is
+  # recommended. For more details, see:
+  #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
+  #   - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+  #   - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
+  config.disable_monkey_patching!
+
+  # This setting enables warnings. It's recommended, but in some cases may
+  # be too noisy due to issues in dependencies.
+  config.warnings = true
+
+  # Many RSpec users commonly either run the entire suite or an individual
+  # file, and it's useful to allow more verbose output when running an
+  # individual spec file.
+  if config.files_to_run.one?
+    # Use the documentation formatter for detailed output,
+    # unless a formatter has already been configured
+    # (e.g. via a command-line flag).
+    config.default_formatter = "doc"
+  end
+
+  # Print the 10 slowest examples and example groups at the
+  # end of the spec run, to help surface which specs are running
+  # particularly slow.
+  # config.profile_examples = 10
+
+  # Run specs in random order to surface order dependencies. If you find an
+  # order dependency and want to debug it, you can fix the order by providing
+  # the seed, which is printed after each run.
+  #     --seed 1234
+  config.order = :random
+
+  # Seed global randomization in this process using the `--seed` CLI option.
+  # Setting this allows you to use `--seed` to deterministically reproduce
+  # test failures related to randomization by passing the same `--seed` value
+  # as the one that triggered the failure.
+  Kernel.srand config.seed
+end
diff --git a/chef-config/spec/unit/config_spec.rb b/chef-config/spec/unit/config_spec.rb
new file mode 100644
index 0000000..dbde3d3
--- /dev/null
+++ b/chef-config/spec/unit/config_spec.rb
@@ -0,0 +1,843 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef-config/config"
+
+RSpec.describe ChefConfig::Config do
+  before(:each) do
+    ChefConfig::Config.reset
+
+    # By default, treat deprecation warnings as errors in tests.
+    ChefConfig::Config.treat_deprecation_warnings_as_errors(true)
+
+    # Set environment variable so the setting persists in child processes
+    ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"] = "1"
+  end
+
+  describe "config attribute writer: chef_server_url" do
+    before do
+      ChefConfig::Config.chef_server_url = "https://junglist.gen.nz"
+    end
+
+    it "sets the server url" do
+      expect(ChefConfig::Config.chef_server_url).to eq("https://junglist.gen.nz")
+    end
+
+    context "when the url has a leading space" do
+      before do
+        ChefConfig::Config.chef_server_url = " https://junglist.gen.nz"
+      end
+
+      it "strips the space from the url when setting" do
+        expect(ChefConfig::Config.chef_server_url).to eq("https://junglist.gen.nz")
+      end
+
+    end
+
+    context "when the url is a frozen string" do
+      before do
+        ChefConfig::Config.chef_server_url = " https://junglist.gen.nz".freeze
+      end
+
+      it "strips the space from the url when setting without raising an error" do
+        expect(ChefConfig::Config.chef_server_url).to eq("https://junglist.gen.nz")
+      end
+    end
+
+    context "when the url is invalid" do
+      it "raises an exception" do
+        expect { ChefConfig::Config.chef_server_url = "127.0.0.1" }.to raise_error(ChefConfig::ConfigurationError)
+      end
+    end
+  end
+
+  describe "when configuring formatters" do
+      # if TTY and not(force-logger)
+      #   formatter = configured formatter or default formatter
+      #   formatter goes to STDOUT/ERR
+      #   if log file is writeable
+      #     log level is configured level or info
+      #     log location is file
+      #   else
+      #     log level is warn
+      #     log location is STDERR
+      #    end
+      # elsif not(TTY) and force formatter
+      #   formatter = configured formatter or default formatter
+      #   if log_location specified
+      #     formatter goes to log_location
+      #   else
+      #     formatter goes to STDOUT/ERR
+      #   end
+      # else
+      #   formatter = "null"
+      #   log_location = configured-value or defualt
+      #   log_level = info or defualt
+      # end
+      #
+    it "has an empty list of formatters by default" do
+      expect(ChefConfig::Config.formatters).to eq([])
+    end
+
+    it "configures a formatter with a short name" do
+      ChefConfig::Config.add_formatter(:doc)
+      expect(ChefConfig::Config.formatters).to eq([[:doc, nil]])
+    end
+
+    it "configures a formatter with a file output" do
+      ChefConfig::Config.add_formatter(:doc, "/var/log/formatter.log")
+      expect(ChefConfig::Config.formatters).to eq([[:doc, "/var/log/formatter.log"]])
+    end
+
+  end
+
+  [ false, true ].each do |is_windows|
+
+    context "On #{is_windows ? 'Windows' : 'Unix'}" do
+      def to_platform(*args)
+        ChefConfig::Config.platform_specific_path(*args)
+      end
+
+      before :each do
+        allow(ChefConfig).to receive(:windows?).and_return(is_windows)
+      end
+
+      describe "class method: platform_specific_path" do
+        if is_windows
+          it "should return a windows path on windows systems" do
+            path = "/etc/chef/cookbooks"
+            allow(ChefConfig::Config).to receive(:env).and_return({ "SYSTEMDRIVE" => "C:" })
+            # match on a regex that looks for the base path with an optional
+            # system drive at the beginning (c:)
+            # system drive is not hardcoded b/c it can change and b/c it is not present on linux systems
+            expect(ChefConfig::Config.platform_specific_path(path)).to eq("C:\\chef\\cookbooks")
+          end
+        else
+          it "should return given path on non-windows systems" do
+            path = "/etc/chef/cookbooks"
+            expect(ChefConfig::Config.platform_specific_path(path)).to eq("/etc/chef/cookbooks")
+          end
+        end
+      end
+
+      describe "default values" do
+        let :primary_cache_path do
+          if is_windows
+            "#{ChefConfig::Config.env['SYSTEMDRIVE']}\\chef"
+          else
+            "/var/chef"
+          end
+        end
+
+        let :secondary_cache_path do
+          if is_windows
+            "#{ChefConfig::Config[:user_home]}\\.chef"
+          else
+            "#{ChefConfig::Config[:user_home]}/.chef"
+          end
+        end
+
+        before do
+          if is_windows
+            allow(ChefConfig::Config).to receive(:env).and_return({ "SYSTEMDRIVE" => "C:" })
+            ChefConfig::Config[:user_home] = 'C:\Users\charlie'
+          else
+            ChefConfig::Config[:user_home] = "/Users/charlie"
+          end
+
+          allow(ChefConfig::Config).to receive(:path_accessible?).and_return(false)
+        end
+
+        describe "ChefConfig::Config[:chef_server_root]" do
+          context "when chef_server_url isn't set manually" do
+            it "returns the default of 'https://localhost:443'" do
+              expect(ChefConfig::Config[:chef_server_root]).to eq("https://localhost:443")
+            end
+          end
+
+          context "when chef_server_url matches '../organizations/*' without a trailing slash" do
+            before do
+              ChefConfig::Config[:chef_server_url] = "https://example.com/organizations/myorg"
+            end
+            it "returns the full URL without /organizations/*" do
+              expect(ChefConfig::Config[:chef_server_root]).to eq("https://example.com")
+            end
+          end
+
+          context "when chef_server_url matches '../organizations/*' with a trailing slash" do
+            before do
+              ChefConfig::Config[:chef_server_url] = "https://example.com/organizations/myorg/"
+            end
+            it "returns the full URL without /organizations/*" do
+              expect(ChefConfig::Config[:chef_server_root]).to eq("https://example.com")
+            end
+          end
+
+          context "when chef_server_url matches '..organizations..' but not '../organizations/*'" do
+            before do
+              ChefConfig::Config[:chef_server_url] = "https://organizations.com/organizations"
+            end
+            it "returns the full URL without any modifications" do
+              expect(ChefConfig::Config[:chef_server_root]).to eq(ChefConfig::Config[:chef_server_url])
+            end
+          end
+
+          context "when chef_server_url is a standard URL without the string organization(s)" do
+            before do
+              ChefConfig::Config[:chef_server_url] = "https://example.com/some_other_string"
+            end
+            it "returns the full URL without any modifications" do
+              expect(ChefConfig::Config[:chef_server_root]).to eq(ChefConfig::Config[:chef_server_url])
+            end
+          end
+        end
+
+        describe "ChefConfig::Config[:cache_path]" do
+          context "when /var/chef exists and is accessible" do
+            it "defaults to /var/chef" do
+              allow(ChefConfig::Config).to receive(:path_accessible?).with(to_platform("/var/chef")).and_return(true)
+              expect(ChefConfig::Config[:cache_path]).to eq(primary_cache_path)
+            end
+          end
+
+          context "when /var/chef does not exist and /var is accessible" do
+            it "defaults to /var/chef" do
+              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
+              allow(ChefConfig::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(true)
+              expect(ChefConfig::Config[:cache_path]).to eq(primary_cache_path)
+            end
+          end
+
+          context "when /var/chef does not exist and /var is not accessible" do
+            it "defaults to $HOME/.chef" do
+              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
+              allow(ChefConfig::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(false)
+              expect(ChefConfig::Config[:cache_path]).to eq(secondary_cache_path)
+            end
+          end
+
+          context "when /var/chef exists and is not accessible" do
+            it "defaults to $HOME/.chef" do
+              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(true)
+              allow(File).to receive(:readable?).with(to_platform("/var/chef")).and_return(true)
+              allow(File).to receive(:writable?).with(to_platform("/var/chef")).and_return(false)
+
+              expect(ChefConfig::Config[:cache_path]).to eq(secondary_cache_path)
+            end
+          end
+
+          context "when chef is running in local mode" do
+            before do
+              ChefConfig::Config.local_mode = true
+            end
+
+            context "and config_dir is /a/b/c" do
+              before do
+                ChefConfig::Config.config_dir to_platform("/a/b/c")
+              end
+
+              it "cache_path is /a/b/c/local-mode-cache" do
+                expect(ChefConfig::Config.cache_path).to eq(to_platform("/a/b/c/local-mode-cache"))
+              end
+            end
+
+            context "and config_dir is /a/b/c/" do
+              before do
+                ChefConfig::Config.config_dir to_platform("/a/b/c/")
+              end
+
+              it "cache_path is /a/b/c/local-mode-cache" do
+                expect(ChefConfig::Config.cache_path).to eq(to_platform("/a/b/c/local-mode-cache"))
+              end
+            end
+          end
+        end
+
+        it "ChefConfig::Config[:stream_execute_output] defaults to false" do
+          expect(ChefConfig::Config[:stream_execute_output]).to eq(false)
+        end
+
+        it "ChefConfig::Config[:file_backup_path] defaults to /var/chef/backup" do
+          allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
+          backup_path = is_windows ? "#{primary_cache_path}\\backup" : "#{primary_cache_path}/backup"
+          expect(ChefConfig::Config[:file_backup_path]).to eq(backup_path)
+        end
+
+        it "ChefConfig::Config[:ssl_verify_mode] defaults to :verify_peer" do
+          expect(ChefConfig::Config[:ssl_verify_mode]).to eq(:verify_peer)
+        end
+
+        it "ChefConfig::Config[:ssl_ca_path] defaults to nil" do
+          expect(ChefConfig::Config[:ssl_ca_path]).to be_nil
+        end
+
+        describe "ChefConfig::Config[:repo_mode]" do
+
+          context "when local mode is enabled" do
+
+            before { ChefConfig::Config[:local_mode] = true }
+
+            it "defaults to 'hosted_everything'" do
+              expect(ChefConfig::Config[:repo_mode]).to eq("hosted_everything")
+            end
+
+            context "and osc_compat is enabled" do
+
+              before { ChefConfig::Config.chef_zero.osc_compat = true }
+
+              it "defaults to 'everything'" do
+                expect(ChefConfig::Config[:repo_mode]).to eq("everything")
+              end
+            end
+          end
+
+          context "when local mode is not enabled" do
+
+            context "and the chef_server_url is multi-tenant" do
+
+              before { ChefConfig::Config[:chef_server_url] = "https://chef.example/organizations/example" }
+
+              it "defaults to 'hosted_everything'" do
+                expect(ChefConfig::Config[:repo_mode]).to eq("hosted_everything")
+              end
+
+            end
+
+            context "and the chef_server_url is not multi-tenant" do
+
+              before { ChefConfig::Config[:chef_server_url] = "https://chef.example/" }
+
+              it "defaults to 'everything'" do
+                expect(ChefConfig::Config[:repo_mode]).to eq("everything")
+              end
+            end
+          end
+        end
+
+        describe "ChefConfig::Config[:chef_repo_path]" do
+
+          context "when cookbook_path is set to a single path" do
+
+            before { ChefConfig::Config[:cookbook_path] = "/home/anne/repo/cookbooks" }
+
+            it "is set to a path one directory up from the cookbook_path" do
+              expected = File.expand_path("/home/anne/repo")
+              expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+            end
+
+          end
+
+          context "when cookbook_path is set to multiple paths" do
+
+            before do
+              ChefConfig::Config[:cookbook_path] = [
+                "/home/anne/repo/cookbooks",
+                "/home/anne/other_repo/cookbooks",
+              ]
+            end
+
+            it "is set to an Array of paths one directory up from the cookbook_paths" do
+              expected = [ "/home/anne/repo", "/home/anne/other_repo"].map { |p| File.expand_path(p) }
+              expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+            end
+
+          end
+
+          context "when cookbook_path is not set but cookbook_artifact_path is set" do
+
+            before do
+              ChefConfig::Config[:cookbook_path] = nil
+              ChefConfig::Config[:cookbook_artifact_path] = "/home/roxie/repo/cookbook_artifacts"
+            end
+
+            it "is set to a path one directory up from the cookbook_artifact_path" do
+              expected = File.expand_path("/home/roxie/repo")
+              expect(ChefConfig::Config[:chef_repo_path]).to eq(expected)
+            end
+
+          end
+
+          context "when cookbook_path is not set" do
+
+            before { ChefConfig::Config[:cookbook_path] = nil }
+
+            it "is set to the cache_path" do
+              expect(ChefConfig::Config[:chef_repo_path]).to eq(ChefConfig::Config[:cache_path])
+            end
+
+          end
+
+        end
+
+        # On Windows, we'll detect an omnibus build and set this to the
+        # cacert.pem included in the package, but it's nil if you're on Windows
+        # w/o omnibus (e.g., doing development on Windows, custom build, etc.)
+        if !is_windows
+          it "ChefConfig::Config[:ssl_ca_file] defaults to nil" do
+            expect(ChefConfig::Config[:ssl_ca_file]).to be_nil
+          end
+        end
+
+        it "ChefConfig::Config[:data_bag_path] defaults to /var/chef/data_bags" do
+          allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
+          data_bag_path = is_windows ? "#{primary_cache_path}\\data_bags" : "#{primary_cache_path}/data_bags"
+          expect(ChefConfig::Config[:data_bag_path]).to eq(data_bag_path)
+        end
+
+        it "ChefConfig::Config[:environment_path] defaults to /var/chef/environments" do
+          allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
+          environment_path = is_windows ? "#{primary_cache_path}\\environments" : "#{primary_cache_path}/environments"
+          expect(ChefConfig::Config[:environment_path]).to eq(environment_path)
+        end
+
+        it "ChefConfig::Config[:cookbook_artifact_path] defaults to /var/chef/cookbook_artifacts" do
+          allow(ChefConfig::Config).to receive(:cache_path).and_return(primary_cache_path)
+          environment_path = is_windows ? "#{primary_cache_path}\\cookbook_artifacts" : "#{primary_cache_path}/cookbook_artifacts"
+          expect(ChefConfig::Config[:cookbook_artifact_path]).to eq(environment_path)
+        end
+
+        describe "setting the config dir" do
+
+          context "when the config file is given with a relative path" do
+
+            before do
+              ChefConfig::Config.config_file = "client.rb"
+            end
+
+            it "expands the path when determining config_dir" do
+              # config_dir goes through PathHelper.canonical_path, which
+              # downcases on windows because the FS is case insensitive, so we
+              # have to downcase expected and actual to make the tests work.
+              expect(ChefConfig::Config.config_dir.downcase).to eq(to_platform(Dir.pwd).downcase)
+            end
+
+            it "does not set derived paths at FS root" do
+              ChefConfig::Config.local_mode = true
+              expect(ChefConfig::Config.cache_path.downcase).to eq(to_platform(File.join(Dir.pwd, "local-mode-cache")).downcase)
+            end
+
+          end
+
+          context "when the config file is /etc/chef/client.rb" do
+
+            before do
+              config_location = to_platform("/etc/chef/client.rb").downcase
+              allow(File).to receive(:absolute_path).with(config_location).and_return(config_location)
+              ChefConfig::Config.config_file = config_location
+            end
+
+            it "config_dir is /etc/chef" do
+              expect(ChefConfig::Config.config_dir).to eq(to_platform("/etc/chef").downcase)
+            end
+
+            context "and chef is running in local mode" do
+              before do
+                ChefConfig::Config.local_mode = true
+              end
+
+              it "config_dir is /etc/chef" do
+                expect(ChefConfig::Config.config_dir).to eq(to_platform("/etc/chef").downcase)
+              end
+            end
+
+            context "when config_dir is set to /other/config/dir/" do
+              before do
+                ChefConfig::Config.config_dir = to_platform("/other/config/dir/")
+              end
+
+              it "yields the explicit value" do
+                expect(ChefConfig::Config.config_dir).to eq(to_platform("/other/config/dir/"))
+              end
+            end
+
+          end
+
+          context "when the user's home dir is /home/charlie/" do
+            before do
+              ChefConfig::Config.user_home = to_platform("/home/charlie")
+            end
+
+            it "config_dir is /home/charlie/.chef/" do
+              expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ""))
+            end
+
+            context "and chef is running in local mode" do
+              before do
+                ChefConfig::Config.local_mode = true
+              end
+
+              it "config_dir is /home/charlie/.chef/" do
+                expect(ChefConfig::Config.config_dir).to eq(ChefConfig::PathHelper.join(to_platform("/home/charlie/.chef"), ""))
+              end
+            end
+          end
+
+        end
+
+        if is_windows
+          describe "finding the windows embedded dir" do
+            let(:default_config_location) { "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
+            let(:alternate_install_location) { "c:/my/alternate/install/place/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
+            let(:non_omnibus_location) { "c:/my/dev/stuff/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
+
+            let(:default_ca_file) { "c:/opscode/chef/embedded/ssl/certs/cacert.pem" }
+
+            it "finds the embedded dir in the default location" do
+              allow(ChefConfig::Config).to receive(:_this_file).and_return(default_config_location)
+              expect(ChefConfig::Config.embedded_dir).to eq("c:/opscode/chef/embedded")
+            end
+
+            it "finds the embedded dir in a custom install location" do
+              allow(ChefConfig::Config).to receive(:_this_file).and_return(alternate_install_location)
+              expect(ChefConfig::Config.embedded_dir).to eq("c:/my/alternate/install/place/chef/embedded")
+            end
+
+            it "doesn't error when not in an omnibus install" do
+              allow(ChefConfig::Config).to receive(:_this_file).and_return(non_omnibus_location)
+              expect(ChefConfig::Config.embedded_dir).to be_nil
+            end
+
+            it "sets the ssl_ca_cert path if the cert file is available" do
+              allow(ChefConfig::Config).to receive(:_this_file).and_return(default_config_location)
+              allow(File).to receive(:exist?).with(default_ca_file).and_return(true)
+              expect(ChefConfig::Config.ssl_ca_file).to eq(default_ca_file)
+            end
+          end
+        end
+      end
+
+      describe "ChefConfig::Config[:user_home]" do
+        it "should set when HOME is provided" do
+          expected = to_platform("/home/kitten")
+          allow(ChefConfig::PathHelper).to receive(:home).and_return(expected)
+          expect(ChefConfig::Config[:user_home]).to eq(expected)
+        end
+
+        it "falls back to the current working directory when HOME and USERPROFILE is not set" do
+          allow(ChefConfig::PathHelper).to receive(:home).and_return(nil)
+          expect(ChefConfig::Config[:user_home]).to eq(Dir.pwd)
+        end
+      end
+
+      describe "ChefConfig::Config[:encrypted_data_bag_secret]" do
+        let(:db_secret_default_path) { to_platform("/etc/chef/encrypted_data_bag_secret") }
+
+        before do
+          allow(File).to receive(:exist?).with(db_secret_default_path).and_return(secret_exists)
+        end
+
+        context "/etc/chef/encrypted_data_bag_secret exists" do
+          let(:secret_exists) { true }
+          it "sets the value to /etc/chef/encrypted_data_bag_secret" do
+            expect(ChefConfig::Config[:encrypted_data_bag_secret]).to eq db_secret_default_path
+          end
+        end
+
+        context "/etc/chef/encrypted_data_bag_secret does not exist" do
+          let(:secret_exists) { false }
+          it "sets the value to nil" do
+            expect(ChefConfig::Config[:encrypted_data_bag_secret]).to be_nil
+          end
+        end
+      end
+
+      describe "ChefConfig::Config[:event_handlers]" do
+        it "sets a event_handlers to an empty array by default" do
+          expect(ChefConfig::Config[:event_handlers]).to eq([])
+        end
+        it "should be able to add custom handlers" do
+          o = Object.new
+          ChefConfig::Config[:event_handlers] << o
+          expect(ChefConfig::Config[:event_handlers]).to be_include(o)
+        end
+      end
+
+      describe "ChefConfig::Config[:user_valid_regex]" do
+        context "on a platform that is not Windows" do
+          it "allows one letter usernames" do
+            any_match = ChefConfig::Config[:user_valid_regex].any? { |regex| regex.match("a") }
+            expect(any_match).to be_truthy
+          end
+        end
+      end
+
+      describe "ChefConfig::Config[:internal_locale]" do
+        let(:shell_out) do
+          cmd = instance_double("Mixlib::ShellOut", exitstatus: 0, stdout: locales, error!: nil)
+          allow(cmd).to receive(:run_command).and_return(cmd)
+          cmd
+        end
+
+        let(:locales) { locale_array.join("\n") }
+
+        before do
+          allow(Mixlib::ShellOut).to receive(:new).with("locale -a").and_return(shell_out)
+        end
+
+        shared_examples_for "a suitable locale" do
+          it "returns an English UTF-8 locale" do
+            expect(ChefConfig.logger).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
+            expect(ChefConfig.logger).to_not receive(:debug).with(/Defaulting to locale en_US.UTF-8 on Windows/)
+            expect(ChefConfig.logger).to_not receive(:debug).with(/No usable locale -a command found/)
+            expect(ChefConfig::Config.guess_internal_locale).to eq expected_locale
+          end
+        end
+
+        context "when the result includes 'C.UTF-8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { [expected_locale, "en_US.UTF-8"] }
+            let(:expected_locale) { "C.UTF-8" }
+          end
+        end
+
+        context "when the result includes 'en_US.UTF-8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { ["en_CA.UTF-8", expected_locale, "en_NZ.UTF-8"] }
+            let(:expected_locale) { "en_US.UTF-8" }
+          end
+        end
+
+        context "when the result includes 'en_US.utf8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { ["en_CA.utf8", "en_US.utf8", "en_NZ.utf8"] }
+            let(:expected_locale) { "en_US.UTF-8" }
+          end
+        end
+
+        context "when the result includes 'en.UTF-8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { ["en.ISO8859-1", expected_locale] }
+            let(:expected_locale) { "en.UTF-8" }
+          end
+        end
+
+        context "when the result includes 'en_*.UTF-8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { [expected_locale, "en_CA.UTF-8", "en_GB.UTF-8"] }
+            let(:expected_locale) { "en_AU.UTF-8" }
+          end
+        end
+
+        context "when the result includes 'en_*.utf8'" do
+          include_examples "a suitable locale" do
+            let(:locale_array) { ["en_AU.utf8", "en_CA.utf8", "en_GB.utf8"] }
+            let(:expected_locale) { "en_AU.UTF-8" }
+          end
+        end
+
+        context "when the result does not include 'en_*.UTF-8'" do
+          let(:locale_array) { ["af_ZA", "af_ZA.ISO8859-1", "af_ZA.ISO8859-15", "af_ZA.UTF-8"] }
+
+          it "should fall back to C locale" do
+            expect(ChefConfig.logger).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
+            expect(ChefConfig::Config.guess_internal_locale).to eq "C"
+          end
+        end
+
+        context "on error" do
+          let(:locale_array) { [] }
+
+          let(:shell_out_cmd) { instance_double("Mixlib::ShellOut") }
+
+          before do
+            allow(Mixlib::ShellOut).to receive(:new).and_return(shell_out_cmd)
+            allow(shell_out_cmd).to receive(:run_command)
+            allow(shell_out_cmd).to receive(:error!).and_raise(Mixlib::ShellOut::ShellCommandFailed, "this is an error")
+          end
+
+          it "should default to 'en_US.UTF-8'" do
+            if is_windows
+              expect(ChefConfig.logger).to receive(:debug).with("Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else.")
+            else
+              expect(ChefConfig.logger).to receive(:debug).with("No usable locale -a command found, assuming you have en_US.UTF-8 installed.")
+            end
+            expect(ChefConfig::Config.guess_internal_locale).to eq "en_US.UTF-8"
+          end
+        end
+      end
+    end
+  end
+
+  describe "export_proxies" do
+    let(:http_proxy) { "http://localhost:7979" }
+    let(:https_proxy) { "https://localhost:7979" }
+    let(:ftp_proxy) { "ftp://localhost:7979" }
+    let(:proxy_user) { "http_user" }
+    let(:proxy_pass) { "http_pass" }
+
+    context "when http_proxy, proxy_pass and proxy_user are set" do
+      before do
+        ChefConfig::Config.http_proxy = http_proxy
+        ChefConfig::Config.http_proxy_user = proxy_user
+        ChefConfig::Config.http_proxy_pass = proxy_pass
+      end
+      it "exports ENV['http_proxy']" do
+        expect(ENV).to receive(:[]=).with("http_proxy", "http://http_user:http_pass@localhost:7979")
+        expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://http_user:http_pass@localhost:7979")
+        ChefConfig::Config.export_proxies
+      end
+    end
+
+    context "when https_proxy, proxy_pass and proxy_user are set" do
+      before do
+        ChefConfig::Config.https_proxy = https_proxy
+        ChefConfig::Config.https_proxy_user = proxy_user
+        ChefConfig::Config.https_proxy_pass = proxy_pass
+      end
+      it "exports ENV['https_proxy']" do
+        expect(ENV).to receive(:[]=).with("https_proxy", "https://http_user:http_pass@localhost:7979")
+        expect(ENV).to receive(:[]=).with("HTTPS_PROXY", "https://http_user:http_pass@localhost:7979")
+        ChefConfig::Config.export_proxies
+      end
+    end
+
+    context "when ftp_proxy, proxy_pass and proxy_user are set" do
+      before do
+        ChefConfig::Config.ftp_proxy = ftp_proxy
+        ChefConfig::Config.ftp_proxy_user = proxy_user
+        ChefConfig::Config.ftp_proxy_pass = proxy_pass
+      end
+      it "exports ENV['ftp_proxy']" do
+        expect(ENV).to receive(:[]=).with("ftp_proxy", "ftp://http_user:http_pass@localhost:7979")
+        expect(ENV).to receive(:[]=).with("FTP_PROXY", "ftp://http_user:http_pass@localhost:7979")
+        ChefConfig::Config.export_proxies
+      end
+    end
+
+    shared_examples "no user pass" do
+      it "does not populate the user or password" do
+        expect(ENV).to receive(:[]=).with("http_proxy", "http://localhost:7979")
+        expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://localhost:7979")
+        ChefConfig::Config.export_proxies
+      end
+    end
+
+    context "when proxy_pass and proxy_user are passed as empty strings" do
+      before do
+        ChefConfig::Config.http_proxy = http_proxy
+        ChefConfig::Config.http_proxy_user = ""
+        ChefConfig::Config.http_proxy_pass = proxy_pass
+      end
+      include_examples "no user pass"
+    end
+
+    context "when proxy_pass and proxy_user are not provided" do
+      before do
+        ChefConfig::Config.http_proxy = http_proxy
+      end
+      include_examples "no user pass"
+    end
+
+    context "when the proxy is provided without a scheme" do
+      before do
+        ChefConfig::Config.http_proxy = "localhost:1111"
+      end
+      it "automatically adds the scheme to the proxy url" do
+        expect(ENV).to receive(:[]=).with("http_proxy", "http://localhost:1111")
+        expect(ENV).to receive(:[]=).with("HTTP_PROXY", "http://localhost:1111")
+        ChefConfig::Config.export_proxies
+      end
+    end
+
+    shared_examples "no export" do
+      it "does not export any proxy settings" do
+        ChefConfig::Config.export_proxies
+        expect(ENV["http_proxy"]).to eq(nil)
+        expect(ENV["https_proxy"]).to eq(nil)
+        expect(ENV["ftp_proxy"]).to eq(nil)
+        expect(ENV["no_proxy"]).to eq(nil)
+      end
+    end
+
+    context "when nothing is set" do
+      include_examples "no export"
+    end
+
+    context "when all the users and passwords are set but no proxies are set" do
+      before do
+        ChefConfig::Config.http_proxy_user = proxy_user
+        ChefConfig::Config.http_proxy_pass = proxy_pass
+        ChefConfig::Config.https_proxy_user = proxy_user
+        ChefConfig::Config.https_proxy_pass = proxy_pass
+        ChefConfig::Config.ftp_proxy_user = proxy_user
+        ChefConfig::Config.ftp_proxy_pass = proxy_pass
+      end
+      include_examples "no export"
+    end
+
+    context "no_proxy is set" do
+      before do
+        ChefConfig::Config.no_proxy = "localhost"
+      end
+      it "exports ENV['no_proxy']" do
+        expect(ENV).to receive(:[]=).with("no_proxy", "localhost")
+        expect(ENV).to receive(:[]=).with("NO_PROXY", "localhost")
+        ChefConfig::Config.export_proxies
+      end
+    end
+  end
+
+  describe "allowing chefdk configuration outside of chefdk" do
+
+    it "allows arbitrary settings in the chefdk config context" do
+      expect { ChefConfig::Config.chefdk.generator_cookbook("/path") }.to_not raise_error
+    end
+
+  end
+
+  describe "Treating deprecation warnings as errors" do
+
+    context "when using our default RSpec configuration" do
+
+      it "defaults to treating deprecation warnings as errors" do
+        expect(ChefConfig::Config[:treat_deprecation_warnings_as_errors]).to be(true)
+      end
+
+      it "sets CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS environment variable" do
+        expect(ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"]).to eq("1")
+      end
+
+      it "treats deprecation warnings as errors in child processes when testing" do
+        # Doing a full integration test where we launch a child process is slow
+        # and liable to break for weird reasons (bundler env stuff, etc.), so
+        # we're just checking that the presence of the environment variable
+        # causes treat_deprecation_warnings_as_errors to be set to true after a
+        # config reset.
+        ChefConfig::Config.reset
+        expect(ChefConfig::Config[:treat_deprecation_warnings_as_errors]).to be(true)
+      end
+
+    end
+
+    context "outside of our test environment" do
+
+      before do
+        ENV.delete("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
+        ChefConfig::Config.reset
+      end
+
+      it "defaults to NOT treating deprecation warnings as errors" do
+        expect(ChefConfig::Config[:treat_deprecation_warnings_as_errors]).to be(false)
+      end
+    end
+
+  end
+
+end
diff --git a/chef-config/spec/unit/path_helper_spec.rb b/chef-config/spec/unit/path_helper_spec.rb
new file mode 100644
index 0000000..b67a074
--- /dev/null
+++ b/chef-config/spec/unit/path_helper_spec.rb
@@ -0,0 +1,290 @@
+#
+# Author:: Bryan McLellan <btm at loftninjas.org>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef-config/path_helper"
+require "spec_helper"
+
+RSpec.describe ChefConfig::PathHelper do
+
+  let(:path_helper) { described_class }
+
+  shared_examples_for "common_functionality" do
+    describe "join" do
+
+      it "joins starting with '' resolve to absolute paths" do
+        expect(path_helper.join("", "a", "b")).to eq("#{path_helper.path_separator}a#{path_helper.path_separator}b")
+      end
+
+      it "joins ending with '' add a / to the end" do
+        expect(path_helper.join("a", "b", "")).to eq("a#{path_helper.path_separator}b#{path_helper.path_separator}")
+      end
+
+    end
+
+    describe "dirname" do
+      it "dirname('abc') is '.'" do
+        expect(path_helper.dirname("abc")).to eq(".")
+      end
+      it "dirname('/') is '/'" do
+        expect(path_helper.dirname(path_helper.path_separator)).to eq(path_helper.path_separator)
+      end
+      it "dirname('a/b/c') is 'a/b'" do
+        expect(path_helper.dirname(path_helper.join("a", "b", "c"))).to eq(path_helper.join("a", "b"))
+      end
+      it "dirname('a/b/c/') is 'a/b'" do
+        expect(path_helper.dirname(path_helper.join("a", "b", "c", ""))).to eq(path_helper.join("a", "b"))
+      end
+      it "dirname('/a/b/c') is '/a/b'" do
+        expect(path_helper.dirname(path_helper.join("", "a", "b", "c"))).to eq(path_helper.join("", "a", "b"))
+      end
+    end
+  end
+
+  context "on windows" do
+
+    before(:each) do
+      allow(ChefConfig).to receive(:windows?).and_return(true)
+    end
+
+    include_examples("common_functionality")
+
+    it "path_separator is \\" do
+      expect(path_helper.path_separator).to eq('\\')
+    end
+
+    describe "platform-specific #join behavior" do
+
+      it "joins components on Windows when some end with unix separators" do
+        expect(path_helper.join('C:\\foo/', "bar", "baz")).to eq('C:\\foo\\bar\\baz')
+      end
+
+      it "joins components when some end with separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expected = "C:#{expected}"
+        expect(path_helper.join('C:\\foo\\', "bar", "baz")).to eq(expected)
+      end
+
+      it "joins components when some end and start with separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expected = "C:#{expected}"
+        expect(path_helper.join('C:\\foo\\', "bar/", "/baz")).to eq(expected)
+      end
+
+      it "joins components that don't end in separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expected = "C:#{expected}"
+        expect(path_helper.join('C:\\foo', "bar", "baz")).to eq(expected)
+      end
+
+    end
+
+    it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
+      expect(path_helper.cleanpath('/a/b\\c/d/')).to eq('\\a\\b\\c\\d')
+    end
+
+    it "cleanpath does not remove leading double backslash" do
+      expect(path_helper.cleanpath('\\\\a/b\\c/d/')).to eq('\\\\a\\b\\c\\d')
+    end
+
+  end
+
+  context "on unix" do
+
+    before(:each) do
+      allow(ChefConfig).to receive(:windows?).and_return(false)
+    end
+
+    include_examples("common_functionality")
+
+    it "path_separator is /" do
+      expect(path_helper.path_separator).to eq("/")
+    end
+
+    it "cleanpath removes extra slashes alone" do
+      expect(path_helper.cleanpath("/a///b/c/d/")).to eq("/a/b/c/d")
+    end
+
+    describe "platform-specific #join behavior" do
+
+      it "joins components when some end with separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expect(path_helper.join("/foo/", "bar", "baz")).to eq(expected)
+      end
+
+      it "joins components when some end and start with separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expect(path_helper.join("/foo/", "bar/", "/baz")).to eq(expected)
+      end
+
+      it "joins components that don't end in separators" do
+        expected = path_helper.cleanpath("/foo/bar/baz")
+        expect(path_helper.join("/foo", "bar", "baz")).to eq(expected)
+      end
+
+    end
+
+  end
+
+  describe "validate_path" do
+    context "on windows" do
+      before(:each) do
+        # pass by default
+        allow(ChefConfig).to receive(:windows?).and_return(true)
+        allow(path_helper).to receive(:printable?).and_return(true)
+        allow(path_helper).to receive(:windows_max_length_exceeded?).and_return(false)
+      end
+
+      it "returns the path if the path passes the tests" do
+        expect(path_helper.validate_path("C:\\ThisIsRigged")).to eql("C:\\ThisIsRigged")
+      end
+
+      it "does not raise an error if everything looks great" do
+        expect { path_helper.validate_path("C:\\cool path\\dude.exe") }.not_to raise_error
+      end
+
+      it "raises an error if the path has invalid characters" do
+        allow(path_helper).to receive(:printable?).and_return(false)
+        expect { path_helper.validate_path("Newline!\n") }.to raise_error(ChefConfig::InvalidPath)
+      end
+
+      it "Adds the \\\\?\\ prefix if the path exceeds MAX_LENGTH and does not have it" do
+        long_path = "C:\\" + "a" * 250 + "\\" + "b" * 250
+        prefixed_long_path = "\\\\?\\" + long_path
+        allow(path_helper).to receive(:windows_max_length_exceeded?).and_return(true)
+        expect(path_helper.validate_path(long_path)).to eql(prefixed_long_path)
+      end
+    end
+  end
+
+  describe "windows_max_length_exceeded?" do
+    it "returns true if the path is too long (259 + NUL) for the API" do
+      expect(path_helper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 6)).to be_truthy
+    end
+
+    it "returns false if the path is not too long (259 + NUL) for the standard API" do
+      expect(path_helper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 5)).to be_falsey
+    end
+
+    it "returns false if the path is over 259 characters but uses the \\\\?\\ prefix" do
+      expect(path_helper.windows_max_length_exceeded?("\\\\?\\C:\\" + "a" * 250 + "\\" + "b" * 250)).to be_falsey
+    end
+  end
+
+  describe "printable?" do
+    it "returns true if the string contains no non-printable characters" do
+      expect(path_helper.printable?("C:\\Program Files (x86)\\Microsoft Office\\Files.lst")).to be_truthy
+    end
+
+    it "returns true when given 'abc' in unicode" do
+      expect(path_helper.printable?("\u0061\u0062\u0063")).to be_truthy
+    end
+
+    it "returns true when given japanese unicode" do
+      expect(path_helper.printable?("\uff86\uff87\uff88")).to be_truthy
+    end
+
+    it "returns false if the string contains a non-printable character" do
+      expect(path_helper.printable?("\my files\work\notes.txt")).to be_falsey
+    end
+
+    # This isn't necessarily a requirement, but here to be explicit about functionality.
+    it "returns false if the string contains a newline or tab" do
+      expect(path_helper.printable?("\tThere's no way,\n\t *no* way,\n\t that you came from my loins.\n")).to be_falsey
+    end
+  end
+
+  describe "canonical_path" do
+    context "on windows", :windows_only do
+      it "returns an absolute path with backslashes instead of slashes" do
+        expect(path_helper.canonical_path("\\\\?\\C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
+      end
+
+      it "adds the \\\\?\\ prefix if it is missing" do
+        expect(path_helper.canonical_path("C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
+      end
+
+      it "returns a lowercase path" do
+        expect(path_helper.canonical_path("\\\\?\\C:\\CASE\\INSENSITIVE")).to eq("\\\\?\\c:\\case\\insensitive")
+      end
+    end
+
+    context "not on windows", :unix_only do
+      it "returns a canonical path" do
+        expect(path_helper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default")
+      end
+    end
+  end
+
+  describe "paths_eql?" do
+    it "returns true if the paths are the same" do
+      allow(path_helper).to receive(:canonical_path).with("bandit").and_return("c:/bandit/bandit")
+      allow(path_helper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
+      expect(path_helper.paths_eql?("bandit", "../bandit/bandit")).to be_truthy
+    end
+
+    it "returns false if the paths are different" do
+      allow(path_helper).to receive(:canonical_path).with("bandit").and_return("c:/Bo/Bandit")
+      allow(path_helper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
+      expect(path_helper.paths_eql?("bandit", "../bandit/bandit")).to be_falsey
+    end
+  end
+
+  describe "escape_glob" do
+    it "escapes characters reserved by glob" do
+      path = "C:\\this\\*path\\[needs]\\escaping?"
+      escaped_path = "C:\\\\this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
+      expect(path_helper.escape_glob(path)).to eq(escaped_path)
+    end
+
+    context "when given more than one argument" do
+      it "joins, cleanpaths, and escapes characters reserved by glob" do
+        args = ["this/*path", "[needs]", "escaping?"]
+        escaped_path = if ChefConfig.windows?
+                         "this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
+                       else
+                         "this/\\*path/\\[needs\\]/escaping\\?"
+                       end
+        expect(path_helper).to receive(:join).with(*args).and_call_original
+        expect(path_helper).to receive(:cleanpath).and_call_original
+        expect(path_helper.escape_glob(*args)).to eq(escaped_path)
+      end
+    end
+  end
+
+  describe "all_homes" do
+    before do
+      stub_const("ENV", env)
+      allow(ChefConfig).to receive(:windows?).and_return(is_windows)
+    end
+
+    context "on windows" do
+      let (:is_windows) { true }
+    end
+
+    context "on unix" do
+      let (:is_windows) { false }
+
+      context "when HOME is not set" do
+        let (:env) { {} }
+        it "returns an empty array" do
+          expect(path_helper.all_homes).to eq([])
+        end
+      end
+    end
+  end
+end
diff --git a/chef-config/spec/unit/workstation_config_loader_spec.rb b/chef-config/spec/unit/workstation_config_loader_spec.rb
new file mode 100644
index 0000000..df53f87
--- /dev/null
+++ b/chef-config/spec/unit/workstation_config_loader_spec.rb
@@ -0,0 +1,289 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "tempfile"
+
+require "chef-config/exceptions"
+require "chef-config/windows"
+require "chef-config/workstation_config_loader"
+
+RSpec.describe ChefConfig::WorkstationConfigLoader do
+
+  let(:explicit_config_location) { nil }
+
+  let(:env) { {} }
+
+  let(:config_loader) do
+    described_class.new(explicit_config_location).tap do |c|
+      allow(c).to receive(:env).and_return(env)
+    end
+  end
+
+  # Test methods that do I/O or reference external state which are stubbed out
+  # elsewhere.
+  describe "external dependencies" do
+    let(:config_loader) { described_class.new(nil) }
+
+    it "delegates to ENV for env" do
+      expect(config_loader.env).to equal(ENV)
+    end
+
+    it "tests a path's existence" do
+      expect(config_loader.path_exists?("/nope/nope/nope/nope/frab/jab/nab")).to be(false)
+      expect(config_loader.path_exists?(__FILE__)).to be(true)
+    end
+
+  end
+
+  describe "locating the config file" do
+    context "without an explicit config" do
+
+      before do
+        allow(config_loader).to receive(:path_exists?).with(an_instance_of(String)).and_return(false)
+      end
+
+      it "has no config if HOME is not set" do
+        expect(config_loader.config_location).to be(nil)
+        expect(config_loader.no_config_found?).to be(true)
+      end
+
+      context "when HOME is set and contains a knife.rb" do
+
+        let(:home) { "/Users/example.user" }
+
+        before do
+          allow(ChefConfig::PathHelper).to receive(:home).with(".chef").and_yield(File.join(home, ".chef"))
+          allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/knife.rb").and_return(true)
+        end
+
+        it "uses the config in HOME/.chef/knife.rb" do
+          expect(config_loader.config_location).to eq("#{home}/.chef/knife.rb")
+        end
+
+        context "and has a config.rb" do
+
+          before do
+            allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/config.rb").and_return(true)
+          end
+
+          it "uses the config in HOME/.chef/config.rb" do
+            expect(config_loader.config_location).to eq("#{home}/.chef/config.rb")
+          end
+
+          context "and/or a parent dir contains a .chef dir" do
+
+            let(:env_pwd) { "/path/to/cwd" }
+
+            before do
+              if ChefConfig.windows?
+                env["CD"] = env_pwd
+              else
+                env["PWD"] = env_pwd
+              end
+
+              allow(config_loader).to receive(:path_exists?).with("#{env_pwd}/.chef/knife.rb").and_return(true)
+              allow(File).to receive(:exist?).with("#{env_pwd}/.chef").and_return(true)
+              allow(File).to receive(:directory?).with("#{env_pwd}/.chef").and_return(true)
+            end
+
+            it "prefers the config from parent_dir/.chef" do
+              expect(config_loader.config_location).to eq("#{env_pwd}/.chef/knife.rb")
+            end
+
+            context "and the parent dir's .chef dir has a config.rb" do
+
+              before do
+                allow(config_loader).to receive(:path_exists?).with("#{env_pwd}/.chef/config.rb").and_return(true)
+              end
+
+              it "prefers the config from parent_dir/.chef" do
+                expect(config_loader.config_location).to eq("#{env_pwd}/.chef/config.rb")
+              end
+
+              context "and/or the current working directory contains a .chef dir" do
+
+                let(:cwd) { Dir.pwd }
+
+                before do
+                  allow(config_loader).to receive(:path_exists?).with("#{cwd}/knife.rb").and_return(true)
+                end
+
+                it "prefers a knife.rb located in the cwd" do
+                  expect(config_loader.config_location).to eq("#{cwd}/knife.rb")
+                end
+
+                context "and the CWD's .chef dir has a config.rb" do
+
+                  before do
+                    allow(config_loader).to receive(:path_exists?).with("#{cwd}/config.rb").and_return(true)
+                  end
+
+                  it "prefers a config located in the cwd" do
+                    expect(config_loader.config_location).to eq("#{cwd}/config.rb")
+                  end
+
+                  context "and/or KNIFE_HOME is set" do
+
+                    let(:knife_home) { "/path/to/knife/home" }
+
+                    before do
+                      env["KNIFE_HOME"] = knife_home
+                      allow(config_loader).to receive(:path_exists?).with("#{knife_home}/knife.rb").and_return(true)
+                    end
+
+                    it "prefers a knife located in KNIFE_HOME" do
+                      expect(config_loader.config_location).to eq("/path/to/knife/home/knife.rb")
+                    end
+
+                    context "and KNIFE_HOME contains a config.rb" do
+
+                      before do
+                        env["KNIFE_HOME"] = knife_home
+                        allow(config_loader).to receive(:path_exists?).with("#{knife_home}/config.rb").and_return(true)
+                      end
+
+                      it "prefers a config.rb located in KNIFE_HOME" do
+                        expect(config_loader.config_location).to eq("/path/to/knife/home/config.rb")
+                      end
+
+                    end
+
+                  end
+                end
+              end
+            end
+          end
+        end
+      end
+
+      context "when the current working dir is inside a symlinked directory" do
+        before do
+          # pwd according to your shell is /home/someuser/prod/chef-repo, but
+          # chef-repo is a symlink to /home/someuser/codes/chef-repo
+          env["CD"] = "/home/someuser/prod/chef-repo" # windows
+          env["PWD"] = "/home/someuser/prod/chef-repo" # unix
+
+          allow(Dir).to receive(:pwd).and_return("/home/someuser/codes/chef-repo")
+        end
+
+        it "loads the config from the non-dereferenced directory path" do
+          expect(File).to receive(:exist?).with("/home/someuser/prod/chef-repo/.chef").and_return(false)
+          expect(File).to receive(:exist?).with("/home/someuser/prod/.chef").and_return(true)
+          expect(File).to receive(:directory?).with("/home/someuser/prod/.chef").and_return(true)
+
+          expect(config_loader).to receive(:path_exists?).with("/home/someuser/prod/.chef/knife.rb").and_return(true)
+
+          expect(config_loader.config_location).to eq("/home/someuser/prod/.chef/knife.rb")
+        end
+      end
+    end
+
+    context "when given an explicit config to load" do
+
+      let(:explicit_config_location) { "/path/to/explicit/config.rb" }
+
+      it "prefers the explicit config" do
+        expect(config_loader.config_location).to eq(explicit_config_location)
+      end
+
+    end
+  end
+
+  describe "loading the config file" do
+
+    context "when no explicit config is specifed and no implicit config is found" do
+
+      before do
+        allow(config_loader).to receive(:path_exists?).with(an_instance_of(String)).and_return(false)
+      end
+
+      it "skips loading" do
+        expect(config_loader.config_location).to be(nil)
+        expect(config_loader.load).to be(false)
+      end
+
+    end
+
+    context "when an explicit config is given but it doesn't exist" do
+
+      let(:explicit_config_location) { "/nope/nope/nope/frab/jab/nab" }
+
+      it "raises a configuration error" do
+        expect { config_loader.load }.to raise_error(ChefConfig::ConfigurationError)
+      end
+
+    end
+
+    context "when the config file exists" do
+
+      let(:config_content) { "" }
+
+      # We need to keep a reference to the tempfile because while #close does
+      # not unlink the file, the object being GC'd will.
+      let(:tempfile) do
+        Tempfile.new("Chef-WorkstationConfigLoader-rspec-test").tap do |t|
+          t.print(config_content)
+          t.close
+        end
+      end
+
+      let(:explicit_config_location) do
+        tempfile.path
+      end
+
+      after { File.unlink(explicit_config_location) if File.exist?(explicit_config_location) }
+
+      context "and is valid" do
+
+        let(:config_content) { "config_file_evaluated(true)" }
+
+        it "loads the config" do
+          expect(config_loader.load).to be(true)
+          expect(ChefConfig::Config.config_file_evaluated).to be(true)
+        end
+
+        it "sets ChefConfig::Config.config_file" do
+          config_loader.load
+          expect(ChefConfig::Config.config_file).to eq(explicit_config_location)
+        end
+      end
+
+      context "and has a syntax error" do
+
+        let(:config_content) { "{{{{{:{{" }
+
+        it "raises a ConfigurationError" do
+          expect { config_loader.load }.to raise_error(ChefConfig::ConfigurationError)
+        end
+      end
+
+      context "and raises a ruby exception during evaluation" do
+
+        let(:config_content) { ":foo\n:bar\nraise 'oops'\n:baz\n" }
+
+        it "raises a ConfigurationError" do
+          expect { config_loader.load }.to raise_error(ChefConfig::ConfigurationError)
+        end
+      end
+
+    end
+
+  end
+
+end
diff --git a/chef.gemspec b/chef.gemspec
new file mode 100644
index 0000000..c55b242
--- /dev/null
+++ b/chef.gemspec
@@ -0,0 +1,58 @@
+$:.unshift(File.dirname(__FILE__) + "/lib")
+require "chef/version"
+
+Gem::Specification.new do |s|
+  s.name = "chef"
+  s.version = Chef::VERSION
+  s.platform = Gem::Platform::RUBY
+  s.extra_rdoc_files = ["README.md", "CONTRIBUTING.md", "LICENSE" ]
+  s.summary = "A systems integration framework, built to bring the benefits of configuration management to your entire infrastructure."
+  s.description = s.summary
+  s.license = "Apache-2.0"
+  s.author = "Adam Jacob"
+  s.email = "adam at chef.io"
+  s.homepage = "http://www.chef.io"
+
+  s.required_ruby_version = ">= 2.0.0"
+
+  s.add_dependency "chef-config", "= #{Chef::VERSION}"
+
+  s.add_dependency "mixlib-cli", "~> 1.4"
+  s.add_dependency "mixlib-log", "~> 1.3"
+  s.add_dependency "mixlib-authentication", "~> 1.4"
+  s.add_dependency "mixlib-shellout", "~> 2.0"
+  s.add_dependency "ohai", ">= 8.6.0.alpha.1", "< 9"
+
+  s.add_dependency "ffi-yajl", "~> 2.2"
+  s.add_dependency "net-ssh", ">= 2.9", "< 4.0"
+  s.add_dependency "net-ssh-multi", "~> 1.1"
+  s.add_dependency "highline", "~> 1.6", ">= 1.6.9"
+  s.add_dependency "erubis", "~> 2.7"
+  s.add_dependency "diff-lcs", "~> 1.2", ">= 1.2.4"
+
+  s.add_dependency "chef-zero", "~> 4.5"
+
+  s.add_dependency "plist", "~> 3.1.0"
+
+  # Audit mode requires these, so they are non-developmental dependencies now
+  %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_dependency gem, "~> 3.4" }
+  s.add_dependency "rspec_junit_formatter", "~> 0.2.0"
+  s.add_dependency "serverspec", "~> 2.7"
+  s.add_dependency "specinfra", "~> 2.10"
+
+  s.add_dependency "syslog-logger", "~> 1.6"
+  s.add_dependency "uuidtools", "~> 2.1.5"
+
+  s.add_dependency "proxifier", "~> 1.0"
+
+  s.add_development_dependency "rack"
+  s.add_development_dependency "cheffish", ">= 1.1", "< 3.0"
+
+  s.add_development_dependency "rake", "~> 10.1"
+
+  s.bindir       = "bin"
+  s.executables  = %w{ chef-client chef-solo knife chef-shell chef-apply }
+
+  s.require_paths = %w{ lib lib-backcompat }
+  s.files = %w{Gemfile Rakefile LICENSE README.md CONTRIBUTING.md VERSION} + Dir.glob("{distro,lib,lib-backcompat,tasks,acceptance,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } + Dir.glob("*.gemspec")
+end
diff --git a/ci/verify-chef.bat b/ci/verify-chef.bat
new file mode 100755
index 0000000..769d368
--- /dev/null
+++ b/ci/verify-chef.bat
@@ -0,0 +1,64 @@
+
+ at ECHO OFF
+
+REM ; %PROJECT_NAME% is set by Jenkins, this allows us to use the same script to verify
+REM ; Chef and Angry Chef
+cd C:\opscode\%PROJECT_NAME%\bin
+
+REM ; We don't want to add the embedded bin dir to the main PATH as this
+REM ; could mask issues in our binstub shebangs.
+SET EMBEDDED_BIN_DIR=C:\opscode\%PROJECT_NAME%\embedded\bin
+
+ECHO.
+
+REM ; Set the temporary directory to a custom location, and wipe it before
+REM ; and after the tests run.
+SET TEMP=%TEMP%\cheftest
+SET TMP=%TMP%\cheftest
+RMDIR /S /Q %TEMP%
+MKDIR %TEMP%
+
+FOR %%b IN (
+  chef-client
+  knife
+  chef-solo
+  ohai
+) DO (
+
+
+  ECHO Checking for existence of binfile `%%b`...
+
+  IF EXIST %%b (
+    ECHO ...FOUND IT!
+  ) ELSE (
+    GOTO :error
+  )
+  ECHO.
+)
+
+call chef-client --version
+
+REM ; Exercise various packaged tools to validate binstub shebangs
+call %EMBEDDED_BIN_DIR%\ruby --version
+call %EMBEDDED_BIN_DIR%\gem --version
+call %EMBEDDED_BIN_DIR%\bundle --version
+call %EMBEDDED_BIN_DIR%\rspec --version
+
+SET PATH=C:\opscode\%PROJECT_NAME%\bin;C:\opscode\%PROJECT_NAME%\embedded\bin;%PATH%
+
+REM ; Test against the vendored chef gem
+cd C:\opscode\%PROJECT_NAME%\embedded\lib\ruby\gems\2*\gems\chef-*-mingw32
+
+IF NOT EXIST "Gemfile.lock" (
+  ECHO "Chef gem does not contain a Gemfile.lock! This is needed to run any tests."
+  GOTO :error
+)
+
+IF "%PIPELINE_NAME%" == "chef-fips" (
+	set CHEF_FIPS=1
+)
+call bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o %WORKSPACE%\test.xml -f documentation spec/unit spec/functional
+
+REM ; Destroy everything at the end for good measure.
+RMDIR /S /Q %TEMP%
+MKDIR %TEMP%
diff --git a/ci/verify-chef.sh b/ci/verify-chef.sh
new file mode 100755
index 0000000..117bf6b
--- /dev/null
+++ b/ci/verify-chef.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+# Set up a custom tmpdir, and clean it up before and after the tests
+TMPDIR="${TMPDIR:-/tmp}/cheftest"
+export TMPDIR
+rm -rf $TMPDIR
+mkdir -p $TMPDIR
+
+# $PROJECT_NAME is set by Jenkins, this allows us to use the same script to verify
+# Chef and Angry Chef
+PATH=/opt/$PROJECT_NAME/bin:$PATH
+export PATH
+
+BIN_DIR=/opt/$PROJECT_NAME/bin
+export BIN_DIR
+
+# We don't want to add the embedded bin dir to the main PATH as this
+# could mask issues in our binstub shebangs.
+EMBEDDED_BIN_DIR=/opt/$PROJECT_NAME/embedded/bin
+export EMBEDDED_BIN_DIR
+
+# If we are on Mac our symlinks are located under /usr/local/bin
+# otherwise they are under /usr/bin
+if [ -f /usr/bin/sw_vers ]; then
+  USR_BIN_DIR="/usr/local/bin"
+else
+  USR_BIN_DIR="/usr/bin"
+fi
+export USR_BIN_DIR
+
+# sanity check that we're getting the correct symlinks from the pre-install script
+# solaris doesn't have readlink or test -e. ls -n is different on BSD. proceed with caution.
+if [ ! -L $USR_BIN_DIR/chef-client ] || [ `ls -l $USR_BIN_DIR/chef-client | awk '{print$NF}'` != "$BIN_DIR/chef-client" ]; then
+  echo "$USR_BIN_DIR/chef-client symlink to $BIN_DIR/chef-client was not correctly created by the pre-install script!"
+  exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/knife ] || [ `ls -l $USR_BIN_DIR/knife | awk '{print$NF}'` != "$BIN_DIR/knife" ]; then
+  echo "$USR_BIN_DIR/knife symlink to $BIN_DIR/knife was not correctly created by the pre-install script!"
+  exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/chef-solo ] || [ `ls -l $USR_BIN_DIR/chef-solo | awk '{print$NF}'` != "$BIN_DIR/chef-solo" ]; then
+  echo "$USR_BIN_DIR/chef-solo symlink to $BIN_DIR/chef-solo was not correctly created by the pre-install script!"
+  exit 1
+fi
+
+if [ ! -L $USR_BIN_DIR/ohai ] || [ `ls -l $USR_BIN_DIR/ohai | awk '{print$NF}'` != "$BIN_DIR/ohai" ]; then
+  echo "$USR_BIN_DIR/ohai symlink to $BIN_DIR/ohai was not correctly created by the pre-install script!"
+  exit 1
+fi
+
+# Ensure the calling environment (disapproval look Bundler) does not
+# infect our Ruby environment created by the `chef-client` cli.
+for ruby_env_var in _ORIGINAL_GEM_PATH \
+                    BUNDLE_BIN_PATH \
+                    BUNDLE_GEMFILE \
+                    GEM_HOME \
+                    GEM_PATH \
+                    GEM_ROOT \
+                    RUBYLIB \
+                    RUBYOPT \
+                    RUBY_ENGINE \
+                    RUBY_ROOT \
+                    RUBY_VERSION
+
+do
+  unset $ruby_env_var
+done
+
+chef-client --version
+
+# Exercise various packaged tools to validate binstub shebangs
+$EMBEDDED_BIN_DIR/ruby --version
+$EMBEDDED_BIN_DIR/gem --version
+$EMBEDDED_BIN_DIR/bundle --version
+$EMBEDDED_BIN_DIR/rspec --version
+
+# ffi-yajl must run in c-extension mode or we take perf hits, so we force it
+# before running rspec so that we don't wind up testing the ffi mode
+FORCE_FFI_YAJL=ext
+export FORCE_FFI_YAJL
+
+# ACCEPTANCE environment variable will be set on acceptance testers.
+# If is it set; we run the acceptance tests, otherwise run rspec tests.
+if [ "x$ACCEPTANCE" != "x" ]; then
+  # On acceptance testers we have Chef DK. We will use its Ruby environment
+  # to cut down the gem installation time.
+  PATH=/opt/chefdk/bin:/opt/chefdk/embedded/bin:$PATH
+  export PATH
+
+  # Test against the vendored Chef gem
+  cd /opt/$PROJECT_NAME/embedded/lib/ruby/gems/*/gems/chef-[0-9]*/acceptance
+  sudo env PATH=$PATH AWS_SSH_KEY_ID=$AWS_SSH_KEY_ID ARTIFACTORY_USERNAME=$ARTIFACTORY_USERNAME ARTIFACTORY_PASSWORD=$ARTIFACTORY_PASSWORD bundle install
+  sudo env PATH=$PATH AWS_SSH_KEY_ID=$AWS_SSH_KEY_ID ARTIFACTORY_USERNAME=$ARTIFACTORY_USERNAME ARTIFACTORY_PASSWORD=$ARTIFACTORY_PASSWORD KITCHEN_DRIVER=ec2 bundle exec chef-acceptance test
+else
+  PATH=/opt/$PROJECT_NAME/bin:/opt/$PROJECT_NAME/embedded/bin:$PATH
+  export PATH
+
+  # Test against the vendored Chef gem
+  cd /opt/$PROJECT_NAME/embedded/lib/ruby/gems/*/gems/chef-[0-9]*
+
+  if [ ! -f "Gemfile.lock" ]; then
+    echo "Chef gem does not contain a Gemfile.lock! This is needed to run any tests."
+    exit 1
+  fi
+
+  unset CHEF_FIPS
+  if [ "$PIPELINE_NAME" = "chef-fips" ]; then
+      echo "Setting fips mode"
+      CHEF_FIPS=1
+      export CHEF_FIPS
+  fi
+  sudo env PATH=$PATH TERM=xterm CHEF_FIPS=$CHEF_FIPS bundle exec rspec -r rspec_junit_formatter -f RspecJunitFormatter -o $WORKSPACE/test.xml -f documentation spec/functional spec/unit
+fi
+
+# Clean up the tmpdir at the end for good measure.
+rm -rf $TMPDIR
diff --git a/distro/common/man/man1/knife-cookbook-site.1 b/distro/common/man/man1/knife-cookbook-site.1
index a90a530..acfcf6b 100644
--- a/distro/common/man/man1/knife-cookbook-site.1
+++ b/distro/common/man/man1/knife-cookbook-site.1
@@ -364,17 +364,17 @@ to return something like:
 .nf
 .ft C
 apache2:
-  cookbook:              http://cookbooks.opscode.com/api/v1/cookbooks/apache2
+  cookbook:              https://supermarket.chef.io/api/v1/cookbooks/apache2
   cookbook_description:  Installs and configures apache2 using Debian symlinks with helper definitions
   cookbook_maintainer:   opscode
   cookbook_name:         apache2
 instiki:
-  cookbook:              http://cookbooks.opscode.com/api/v1/cookbooks/instiki
+  cookbook:              https://supermarket.chef.io/api/v1/cookbooks/instiki
   cookbook_description:  Installs instiki, a Ruby on Rails wiki server under passenger+Apache2.
   cookbook_maintainer:   jtimberman
   cookbook_name:         instiki
 kickstart:
-  cookbook:              http://cookbooks.opscode.com/api/v1/cookbooks/kickstart
+  cookbook:              https://supermarket.chef.io/api/v1/cookbooks/kickstart
   cookbook_description:  Creates apache2 vhost and serves a kickstart file.
   cookbook_maintainer:   opscode
   cookbook_name:         kickstart
@@ -481,18 +481,18 @@ category:        Networking
 created_at:      2009\-10\-25T23:51:07Z
 description:     Installs and configures haproxy
 external_url:
-latest_version:  http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_3
+latest_version:  https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/1_0_3
 maintainer:      opscode
 name:            haproxy
 updated_at:      2011\-06\-30T21:53:25Z
 versions:
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_3
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_2
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_1
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_0
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_8_1
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_8_0
-   http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_7_0
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/1_0_3
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/1_0_2
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/1_0_1
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/1_0_0
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/0_8_1
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/0_8_0
+   https://supermarket.chef.io/api/v1/cookbooks/haproxy/versions/0_7_0
 .ft P
 .fi
 .UNINDENT
diff --git a/distro/common/markdown/man1/chef-shell.mkd b/distro/common/markdown/man1/chef-shell.mkd
index 5525ef8..216dc73 100644
--- a/distro/common/markdown/man1/chef-shell.mkd
+++ b/distro/common/markdown/man1/chef-shell.mkd
@@ -131,8 +131,8 @@ Recipe mode implements Chef's recipe DSL. Exhaustively documenting this
 DSL is outside the scope of this document. See the following pages in
 the Chef documentation for more information:
 
-  * <http://wiki.opscode.com/display/chef/Resources>
-  * <http://wiki.opscode.com/display/chef/Recipes>
+  * <http://docs.chef.io/resources.html>
+  * <http://docs.chef.io/recipes.html>
 
 Once you have defined resources in the recipe, you can trigger a
 convergence run via `run_chef`
@@ -176,7 +176,7 @@ libraries.
 ## SEE ALSO
 
   chef-client(8) knife(1)
-  <http://wiki.opscode.com/display/chef/Chef+Shell>
+  <http://docs.chef.io/ctl_chef_shell.html>
 
 ## AUTHOR
 
@@ -192,4 +192,4 @@ libraries.
 
 ## CHEF
 
-   chef-shell is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   chef-shell is distributed with Chef. <http://docs.chef.io>
diff --git a/distro/common/markdown/man1/knife-bootstrap.mkd b/distro/common/markdown/man1/knife-bootstrap.mkd
index cb292de..a1a2d34 100644
--- a/distro/common/markdown/man1/knife-bootstrap.mkd
+++ b/distro/common/markdown/man1/knife-bootstrap.mkd
@@ -138,4 +138,4 @@ to other users via the process list using tools such as ps(1).
 
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
diff --git a/distro/common/markdown/man1/knife-client.mkd b/distro/common/markdown/man1/knife-client.mkd
index e7b732e..b95a578 100644
--- a/distro/common/markdown/man1/knife-client.mkd
+++ b/distro/common/markdown/man1/knife-client.mkd
@@ -99,5 +99,5 @@ setting up a host for management with Chef.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-configure.mkd b/distro/common/markdown/man1/knife-configure.mkd
index 507d30d..f3a4ef0 100644
--- a/distro/common/markdown/man1/knife-configure.mkd
+++ b/distro/common/markdown/man1/knife-configure.mkd
@@ -66,5 +66,5 @@ the specified _directory_.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-cookbook-site.mkd b/distro/common/markdown/man1/knife-cookbook-site.mkd
index 9496cf1..68bc843 100644
--- a/distro/common/markdown/man1/knife-cookbook-site.mkd
+++ b/distro/common/markdown/man1/knife-cookbook-site.mkd
@@ -119,5 +119,5 @@ Uploading cookbooks to the Opscode cookbooks site:
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-cookbook.mkd b/distro/common/markdown/man1/knife-cookbook.mkd
index deaf004..6a56059 100644
--- a/distro/common/markdown/man1/knife-cookbook.mkd
+++ b/distro/common/markdown/man1/knife-cookbook.mkd
@@ -236,7 +236,7 @@ to specify alternate files to be used on a specific OS platform or host.
 The default specificity setting is _default_, that is files in
 `COOKBOOK/files/default` will be used when a more specific copy is not
 available. Further documentation for this feature is available on the
-Chef wiki: <http://wiki.opscode.com/display/chef/File+Distribution#FileDistribution-FileSpecificity>
+Chef wiki: <https://docs.chef.io/resource_cookbook_file.html#file-specificity>
 
 Cookbooks also contain a metadata file that defines various properties
 of the cookbook. The most important of these are the _version_ and the
@@ -248,8 +248,8 @@ cookbook.
 
 ## SEE ALSO
    __knife-environment(1)__ __knife-cookbook-site(1)__
-   <http://wiki.opscode.com/display/chef/Cookbooks>
-   <http://wiki.opscode.com/display/chef/Metadata>
+   <http://docs.chef.io/cookbooks.html>
+   <http://docs.chef.io/cookbook_repo.html>
 
 ## AUTHOR
    Chef was written by Adam Jacob <adam at opscode.com> with many contributions from the community.
@@ -260,4 +260,4 @@ cookbook.
 
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
diff --git a/distro/common/markdown/man1/knife-data-bag.mkd b/distro/common/markdown/man1/knife-data-bag.mkd
index 53abf95..cab28a2 100644
--- a/distro/common/markdown/man1/knife-data-bag.mkd
+++ b/distro/common/markdown/man1/knife-data-bag.mkd
@@ -117,5 +117,5 @@ encryption keys.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home
+   Knife is distributed with Chef. http://docs.chef.io/
 
diff --git a/distro/common/markdown/man1/knife-environment.mkd b/distro/common/markdown/man1/knife-environment.mkd
index 98ca499..06bf423 100644
--- a/distro/common/markdown/man1/knife-environment.mkd
+++ b/distro/common/markdown/man1/knife-environment.mkd
@@ -137,8 +137,8 @@ The Ruby format of an environment is as follows:
 
 ## SEE ALSO
    __knife-node(1)__ __knife-cookbook(1)__ __knife-role(1)__
-  <http://wiki.opscode.com/display/chef/Environments>
-  <http://wiki.opscode.com/display/chef/Version+Constraints>
+  <http://docs.chef.io/environments.html>
+  <http://docs.chef.io/cookbook_versions.html>
 
 ## AUTHOR
    Chef was written by Adam Jacob <adam at opscode.com> with many contributions from the community.
@@ -148,4 +148,4 @@ The Ruby format of an environment is as follows:
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
diff --git a/distro/common/markdown/man1/knife-exec.mkd b/distro/common/markdown/man1/knife-exec.mkd
index d4aa87c..1b60177 100644
--- a/distro/common/markdown/man1/knife-exec.mkd
+++ b/distro/common/markdown/man1/knife-exec.mkd
@@ -39,4 +39,4 @@ description of the commands available.
 
 ## CHEF
 
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
diff --git a/distro/common/markdown/man1/knife-index.mkd b/distro/common/markdown/man1/knife-index.mkd
index 812f3fe..f1425b8 100644
--- a/distro/common/markdown/man1/knife-index.mkd
+++ b/distro/common/markdown/man1/knife-index.mkd
@@ -26,5 +26,5 @@ time for all objects to be indexed and available for search.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-node.mkd b/distro/common/markdown/man1/knife-node.mkd
index 72b7d00..0262d64 100644
--- a/distro/common/markdown/man1/knife-node.mkd
+++ b/distro/common/markdown/man1/knife-node.mkd
@@ -126,5 +126,5 @@ When adding a recipe to a run list, there are several valid formats:
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-role.mkd b/distro/common/markdown/man1/knife-role.mkd
index 7e0dac9..e202c52 100644
--- a/distro/common/markdown/man1/knife-role.mkd
+++ b/distro/common/markdown/man1/knife-role.mkd
@@ -70,8 +70,8 @@ run\_list.
 
 ## SEE ALSO
    __knife-node(1)__ __knife-environment(1)__
-   <http://wiki.opscode.com/display/chef/Roles>
-   <http://wiki.opscode.com/display/chef/Attributes>
+   <http://docs.chef.io/roles.html>
+   <http://docs.chef.io/attributes.html>
 
 ## AUTHOR
    Chef was written by Adam Jacob <adam at opscode.com> with many contributions from the community.
@@ -81,5 +81,5 @@ run\_list.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife-search.mkd b/distro/common/markdown/man1/knife-search.mkd
index d6729be..b289b2c 100644
--- a/distro/common/markdown/man1/knife-search.mkd
+++ b/distro/common/markdown/man1/knife-search.mkd
@@ -164,7 +164,7 @@ Find all nodes running CentOS in the production environment:
 
 ## SEE ALSO
    __knife-ssh__(1)
-   <http://wiki.opscode.com/display/chef/Attributes>
+   <http://docs.chef.io/attributes.html>
    [Lucene Query Parser Syntax](http://lucene.apache.org/java/2_3_2/queryparsersyntax.html)
 
 ## AUTHOR
@@ -175,6 +175,6 @@ Find all nodes running CentOS in the production environment:
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
 
diff --git a/distro/common/markdown/man1/knife-ssh.mkd b/distro/common/markdown/man1/knife-ssh.mkd
index 07fc594..7d37075 100644
--- a/distro/common/markdown/man1/knife-ssh.mkd
+++ b/distro/common/markdown/man1/knife-ssh.mkd
@@ -64,6 +64,6 @@ The available multiplexers are:
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
 
diff --git a/distro/common/markdown/man1/knife-status.mkd b/distro/common/markdown/man1/knife-status.mkd
index 07f0ff3..0a969e4 100644
--- a/distro/common/markdown/man1/knife-status.mkd
+++ b/distro/common/markdown/man1/knife-status.mkd
@@ -31,6 +31,6 @@ may not be publicly reachable.
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
 
diff --git a/distro/common/markdown/man1/knife-tag.mkd b/distro/common/markdown/man1/knife-tag.mkd
index 6a1a2c4..b5bbb82 100644
--- a/distro/common/markdown/man1/knife-tag.mkd
+++ b/distro/common/markdown/man1/knife-tag.mkd
@@ -35,5 +35,5 @@ Lists the tags applied to _node_
    Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io>
 
diff --git a/distro/common/markdown/man1/knife.mkd b/distro/common/markdown/man1/knife.mkd
index c3add16..3d7c095 100644
--- a/distro/common/markdown/man1/knife.mkd
+++ b/distro/common/markdown/man1/knife.mkd
@@ -186,7 +186,7 @@ recommended though, and git fits with a lot of the workflow paradigms.
   __knife-node(1)__ __knife-recipe(1)__ __knife-role(1)__
   __knife-search(1)__ __knife-ssh(1)__ __knife-tag(1)__
 
-  Complete Chef documentation is available online: <http://wiki.opscode.com/display/chef/Home/>
+  Complete Chef documentation is available online: <http://docs.chef.io/>
 
   JSON is JavaScript Object Notation <http://json.org/>
 
@@ -209,5 +209,5 @@ recommended though, and git fits with a lot of the workflow paradigms.
    On some systems, the complete text of the Apache 2.0 License may be found in `/usr/share/common-licenses/Apache-2.0`.
 
 ## CHEF
-   Knife is distributed with Chef. <http://wiki.opscode.com/display/chef/Home>
+   Knife is distributed with Chef. <http://docs.chef.io/>
 
diff --git a/distro/common/markdown/man8/chef-client.mkd b/distro/common/markdown/man8/chef-client.mkd
index e37d283..ffe444e 100644
--- a/distro/common/markdown/man8/chef-client.mkd
+++ b/distro/common/markdown/man8/chef-client.mkd
@@ -59,8 +59,7 @@ are largely services that exist only to provide the Client with information.
 
 ## SEE ALSO
 
-Full  documentation  for  Chef  and  chef-client is located on the Chef
-wiki, http://wiki.opscode.com/display/chef/Home.
+Full  documentation  for  Chef  and  chef-client is located on docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-expander.mkd b/distro/common/markdown/man8/chef-expander.mkd
index 9190a9a..a2bb7d7 100644
--- a/distro/common/markdown/man8/chef-expander.mkd
+++ b/distro/common/markdown/man8/chef-expander.mkd
@@ -67,8 +67,7 @@ See __chef-expanderctl__(8) for details.
 __chef-expanderctl__(8)
 __chef-solr__(8)
 
-Full documentation for Chef and chef-server is located on the Chef
-wiki, http://wiki.opscode.com/display/chef/Home.
+Full documentation for Chef and chef-server is located on docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-expanderctl.mkd b/distro/common/markdown/man8/chef-expanderctl.mkd
index 03ce6af..db593cb 100644
--- a/distro/common/markdown/man8/chef-expanderctl.mkd
+++ b/distro/common/markdown/man8/chef-expanderctl.mkd
@@ -43,8 +43,7 @@ be restarted by the master process.
 __chef-expander-cluster__(8)
 __chef-solr__(8)
 
-Full documentation for Chef and chef-server is located on the Chef
-wiki, http://wiki.opscode.com/display/chef/Home.
+Full documentation for Chef and chef-server is located on docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-server-webui.mkd b/distro/common/markdown/man8/chef-server-webui.mkd
index 977e149..b176d12 100644
--- a/distro/common/markdown/man8/chef-server-webui.mkd
+++ b/distro/common/markdown/man8/chef-server-webui.mkd
@@ -106,7 +106,7 @@ The default credentials are:
 ## SEE ALSO
 
 Full documentation for Chef and chef-server-webui (Management Console)
-is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.
+is located on the Chef docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-server.mkd b/distro/common/markdown/man8/chef-server.mkd
index 1b0f35e..46a5ea4 100644
--- a/distro/common/markdown/man8/chef-server.mkd
+++ b/distro/common/markdown/man8/chef-server.mkd
@@ -106,8 +106,7 @@ __chef-client__(8)
 __chef-server-webui__(8)
 __knife__(1)
 
-Full documentation for Chef and chef-server is located on the Chef
-wiki, http://wiki.opscode.com/display/chef/Home.
+Full documentation for Chef and chef-server is located on docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-solo.mkd b/distro/common/markdown/man8/chef-solo.mkd
index 861a0fa..9d5d9a4 100644
--- a/distro/common/markdown/man8/chef-solo.mkd
+++ b/distro/common/markdown/man8/chef-solo.mkd
@@ -92,8 +92,8 @@ and use the run_list from ~/node.json.
 
 ## SEE ALSO
 
-Full documentation for Chef and  chef-solo  is  located  on  the  Chef  wiki,
-http://wiki.opscode.com/display/chef/Home.
+Full documentation for Chef and  chef-solo  is  located  on  the  Chef  docs site,
+http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/common/markdown/man8/chef-solr.mkd b/distro/common/markdown/man8/chef-solr.mkd
index 02e7d62..a210a90 100644
--- a/distro/common/markdown/man8/chef-solr.mkd
+++ b/distro/common/markdown/man8/chef-solr.mkd
@@ -75,7 +75,7 @@ when prompted for confirmation. The process should look like this:
 __chef-expander-cluster__(8)
 
 Full documentation for Chef and chef-server is located on the Chef
-wiki, http://wiki.opscode.com/display/chef/Home.
+Docs site, http://docs.chef.io/.
 
 ## AUTHOR
 
diff --git a/distro/powershell/chef/chef.psm1 b/distro/powershell/chef/chef.psm1
new file mode 100644
index 0000000..6646226
--- /dev/null
+++ b/distro/powershell/chef/chef.psm1
@@ -0,0 +1,327 @@
+
+function Load-Win32Bindings {
+  Add-Type -TypeDefinition @"
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace Chef
+{
+
+[StructLayout(LayoutKind.Sequential)]
+public struct PROCESS_INFORMATION
+{
+  public IntPtr hProcess;
+  public IntPtr hThread;
+  public uint dwProcessId;
+  public uint dwThreadId;
+}
+
+[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+public struct STARTUPINFO
+{
+  public uint cb;
+  public string lpReserved;
+  public string lpDesktop;
+  public string lpTitle;
+  public uint dwX;
+  public uint dwY;
+  public uint dwXSize;
+  public uint dwYSize;
+  public uint dwXCountChars;
+  public uint dwYCountChars;
+  public uint dwFillAttribute;
+  public STARTF dwFlags;
+  public ShowWindow wShowWindow;
+  public short cbReserved2;
+  public IntPtr lpReserved2;
+  public IntPtr hStdInput;
+  public IntPtr hStdOutput;
+  public IntPtr hStdError;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public struct SECURITY_ATTRIBUTES
+{
+  public int length;
+  public IntPtr lpSecurityDescriptor;
+  public bool bInheritHandle;
+}
+
+[Flags]
+public enum CreationFlags : int
+{
+  NONE = 0,
+  DEBUG_PROCESS = 0x00000001,
+  DEBUG_ONLY_THIS_PROCESS = 0x00000002,
+  CREATE_SUSPENDED = 0x00000004,
+  DETACHED_PROCESS = 0x00000008,
+  CREATE_NEW_CONSOLE = 0x00000010,
+  CREATE_NEW_PROCESS_GROUP = 0x00000200,
+  CREATE_UNICODE_ENVIRONMENT = 0x00000400,
+  CREATE_SEPARATE_WOW_VDM = 0x00000800,
+  CREATE_SHARED_WOW_VDM = 0x00001000,
+  CREATE_PROTECTED_PROCESS = 0x00040000,
+  EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
+  CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
+  CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
+  CREATE_DEFAULT_ERROR_MODE = 0x04000000,
+  CREATE_NO_WINDOW = 0x08000000,
+}
+
+[Flags]
+public enum STARTF : uint
+{
+  STARTF_USESHOWWINDOW = 0x00000001,
+  STARTF_USESIZE = 0x00000002,
+  STARTF_USEPOSITION = 0x00000004,
+  STARTF_USECOUNTCHARS = 0x00000008,
+  STARTF_USEFILLATTRIBUTE = 0x00000010,
+  STARTF_RUNFULLSCREEN = 0x00000020,  // ignored for non-x86 platforms
+  STARTF_FORCEONFEEDBACK = 0x00000040,
+  STARTF_FORCEOFFFEEDBACK = 0x00000080,
+  STARTF_USESTDHANDLES = 0x00000100,
+}
+
+public enum ShowWindow : short
+{
+    SW_HIDE = 0,
+    SW_SHOWNORMAL = 1,
+    SW_NORMAL = 1,
+    SW_SHOWMINIMIZED = 2,
+    SW_SHOWMAXIMIZED = 3,
+    SW_MAXIMIZE = 3,
+    SW_SHOWNOACTIVATE = 4,
+    SW_SHOW = 5,
+    SW_MINIMIZE = 6,
+    SW_SHOWMINNOACTIVE = 7,
+    SW_SHOWNA = 8,
+    SW_RESTORE = 9,
+    SW_SHOWDEFAULT = 10,
+    SW_FORCEMINIMIZE = 11,
+    SW_MAX = 11
+}
+
+public enum StandardHandle : int
+{
+  Input = -10,
+  Output = -11,
+  Error = -12
+}
+
+public static class Kernel32
+{
+  [DllImport("kernel32.dll", SetLastError=true)]
+  [return: MarshalAs(UnmanagedType.Bool)]
+  public static extern bool CreateProcess(
+    string lpApplicationName,
+    string lpCommandLine,
+    ref SECURITY_ATTRIBUTES lpProcessAttributes,
+    ref SECURITY_ATTRIBUTES lpThreadAttributes,
+    [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
+    CreationFlags dwCreationFlags,
+    IntPtr lpEnvironment,
+    string lpCurrentDirectory,
+    ref STARTUPINFO lpStartupInfo,
+    out PROCESS_INFORMATION lpProcessInformation);
+
+  [DllImport("kernel32.dll", SetLastError=true)]
+  public static extern IntPtr GetStdHandle(
+    StandardHandle nStdHandle);
+
+  [DllImport("kernel32", SetLastError=true)]
+  public static extern int WaitForSingleObject(
+    IntPtr hHandle,
+    int dwMilliseconds);
+
+  [DllImport("kernel32", SetLastError=true)]
+  [return: MarshalAs(UnmanagedType.Bool)]
+  public static extern bool CloseHandle(
+    IntPtr hObject);
+
+  [DllImport("kernel32", SetLastError=true)]
+  [return: MarshalAs(UnmanagedType.Bool)]
+  public static extern bool GetExitCodeProcess(
+    IntPtr hProcess,
+    out int lpExitCode);
+}
+}
+"@
+}
+
+function Run-ExecutableAndWait($AppPath, $ArgumentString) {
+  # Use the Win32 API to create a new process and wait for it to terminate.
+  $null = Load-Win32Bindings
+
+  $si = New-Object Chef.STARTUPINFO
+  $pi = New-Object Chef.PROCESS_INFORMATION
+
+  $si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
+  $si.wShowWindow = [Chef.ShowWindow]::SW_SHOW
+  $si.dwFlags = [Chef.STARTF]::STARTF_USESTDHANDLES
+  $si.hStdError = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Error)
+  $si.hStdOutput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Output)
+  $si.hStdInput = [Chef.Kernel32]::GetStdHandle([Chef.StandardHandle]::Input)
+
+  $pSec = New-Object Chef.SECURITY_ATTRIBUTES
+  $pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
+  $pSec.bInheritHandle = $true
+  $tSec = New-Object Chef.SECURITY_ATTRIBUTES
+  $tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
+  $tSec.bInheritHandle = $true
+
+  $success = [Chef.Kernel32]::CreateProcess($AppPath, $ArgumentString, [ref] $pSec, [ref] $tSec, $true, [Chef.CreationFlags]::NONE, [IntPtr]::Zero, $pwd, [ref] $si, [ref] $pi)
+  if (-Not $success) {
+    $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+    throw "Unable to create process [$ArgumentString].  Error code $reason."
+  }
+  $waitReason = [Chef.Kernel32]::WaitForSingleObject($pi.hProcess, -1)
+  if ($waitReason -ne 0) {
+    if ($waitReason -eq -1) {
+      $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+      throw "Could not wait for process to terminate.  Error code $reason."
+    } else {
+      throw "WaitForSingleObject failed with return code $waitReason - it's impossible!"
+    }
+  }
+  $success = [Chef.Kernel32]::GetExitCodeProcess($pi.hProcess, [ref] $global:LASTEXITCODE)
+  if (-Not $success) {
+    $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+    throw "Process exit code unavailable.  Error code $reason."
+  }
+  $success = [Chef.Kernel32]::CloseHandle($pi.hProcess)
+  if (-Not $success) {
+    $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+    throw "Unable to release process handle.  Error code $reason."
+  }
+  $success = [Chef.Kernel32]::CloseHandle($pi.hThread)
+  if (-Not $success) {
+    $reason = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+    throw "Unable to release thread handle.  Error code $reason."
+  }
+}
+
+function Get-ScriptDirectory {
+  if (!$PSScriptRoot) {
+    $Invocation = (Get-Variable MyInvocation -Scope 1).Value
+    $PSScriptRoot = Split-Path $Invocation.MyCommand.Path
+  }
+  $PSScriptRoot
+}
+
+function Run-RubyCommand($command, $argList) {
+  # This method exists to take the given list of arguments and get it past ruby's command-line
+  # interpreter unscathed and untampered.  See https://github.com/ruby/ruby/blob/trunk/win32/win32.c#L1582
+  # for a list of transformations that ruby attempts to perform with your command-line arguments
+  # before passing it onto a script.  The most important task is to defeat the globbing
+  # and wild-card expansion that ruby performs.  Note that ruby does not use MSVCRT's argc/argv
+  # and deliberately reparses the raw command-line instead.
+  #
+  # To stop ruby from interpreting command-line arguments as globs, they need to be enclosed in '
+  # Ruby doesn't allow any escape characters inside '.  This unfortunately prevents us from sending
+  # any strings which themselves contain '.  Ruby does allow multi-fragment arguments though.
+  # "foo bar"'baz qux'123"foo" is interpreted as 1 argument because there are no un-escaped
+  # whitespace there.  The argument would be interpreted as the string "foo barbaz qux123foo".
+  # This lets us escape ' characters by exiting the ' quoted string, injecting a "'" fragment and
+  # then resuming the ' quoted string again.
+  #
+  # In the process of defeating ruby, one must also defeat the helpfulness of powershell.
+  # When arguments come into this method, the standard PS rules for interpreting cmdlet arguments
+  # apply.  When using & (call operator) and providing an array of arguments, powershell (verified
+  # on PS 4.0 on Windows Server 2012R2) will not evaluate them but (contrary to documentation),
+  # it will still marginally interpret them.  The behaviour of PS 5.0 seems to be different but
+  # ignore that for now.  If any of the provided arguments has a space in it, powershell checks
+  # the first and last character to ensure that they are " characters (and that's all it checks).
+  # If they are not, it will blindly surround that argument with " characters.  It won't do this
+  # operation if no space is present, even if other special characters are present. If it notices
+  # leading and trailing " characters, it won't actually check to see if there are other "
+  # characters in the string.  Since PS 5.0 changes this behavior, we could consider using the --%
+  # "stop screwing up my arguments" operator, which is available since PS 3.0.  When encountered
+  # --% indicates that the rest of line is to be sent literally...  except if the parser encounters
+  # %FOO% cmd style environment variables.  Because reasons.  And there is no way to escape the
+  # % character in *any* waym shape or form.
+  # https://connect.microsoft.com/PowerShell/feedback/details/376207/executing-commands-which-require-quotes-and-variables-is-practically-impossible
+  #
+  # In case you think that you're either reading this incorrectly or that I'm full of shit, here
+  # are some examples.  These use EchoArgs.exe from the PowerShell Community Extensions package.
+  # I have not included the argument parsing output from EchoArgs.exe to prevent confusing you with
+  # more details about MSVCRT's parsing algorithm.
+  #
+  # $x = "foo '' bar `"baz`""
+  # & EchoArgs @($x, $x)
+  # Command line:
+  # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe"  "foo '' bar "baz"" "foo '' bar "baz""
+  #
+  # $x = "abc'123'nospace`"lulz`"!!!"
+  # & EchoArgs @($x, $x)
+  # Command line:
+  # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe"  abc'123'nospace"lulz"!!! abc'123'nospace"lulz"!!!
+  #
+  # $x = "`"`"Look ma! Tonnes of spaces! 'foo' 'bar'`"`""
+  # & EchoArgs @($x, $x)
+  # Command line:
+  # "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe"  ""Look ma! Tonnes of spaces! 'foo' 'bar'"" ""Look ma! Tonnes of spaces! 'foo' 'bar'""
+  #
+  # Given all this, we can now device a strategy to work around all these immensely helpful, well
+  # documented and useful tools by looking at each incoming argument, escaping any ' characters
+  # with a '"'"' sequence, surrounding each argument with ' & joining them with a space separating
+  # them.
+  # There is another bug (https://bugs.ruby-lang.org/issues/11142) that causes ruby to mangle any
+  # "" two-character double quote sequence but since we always emit our strings inside ' except for
+  # ' characters, this should be ok.  Just remember that an argument '' should get translated to
+  # ''"'"''"'"'' on the command line.  If those intervening empty ''s are not present, the presence
+  # of "" will cause ruby to mangle that argument.
+  $transformedList = $argList | foreach { "'" + ( $_ -replace "'","'`"'`"'" ) + "'" }
+  $fortifiedArgString = $transformedList -join ' '
+
+  # Use the correct embedded ruby path.  We'll be deployed at a path that looks like
+  # [C:\opscode or some other prefix]\chef\modules\chef
+  $ruby = Join-Path (Get-ScriptDirectory)  "..\..\embedded\bin\ruby.exe"
+  $commandPath = Join-Path (Get-ScriptDirectory) "..\..\bin\$command"
+
+  Run-ExecutableAndWait $ruby """$ruby"" '$commandPath' $fortifiedArgString"
+}
+
+
+function chef-apply {
+  Run-RubyCommand 'chef-apply' $args
+}
+
+function chef-client {
+  Run-RubyCommand 'chef-client' $args
+}
+
+function chef-service-manager {
+  Run-RubyCommand 'chef-service-manager' $args
+}
+
+function chef-shell {
+  Run-RubyCommand 'chef-shell' $args
+}
+
+function chef-solo {
+  Run-RubyCommand 'chef-solo' $args
+}
+
+function chef-windows-service {
+  Run-RubyCommand 'chef-windows-service' $args
+}
+
+function knife {
+  Run-RubyCommand 'knife' $args
+}
+
+Export-ModuleMember -function chef-apply
+Export-ModuleMember -function chef-client
+Export-ModuleMember -function chef-service-manager
+Export-ModuleMember -function chef-shell
+Export-ModuleMember -function chef-solo
+Export-ModuleMember -function chef-windows-service
+Export-ModuleMember -function knife
+
+# To debug this module, uncomment the line below and then run the following.
+# Export-ModuleMember -function Run-RubyCommand
+# Remove-Module chef
+# Import-Module chef
+# "puts ARGV" | Out-File C:\opscode\chef\bin\puts_args
+# Run-RubyCommand puts_args 'Here' "are" some '"very interesting"' 'arguments[to]' "`"try out`""
diff --git a/ext/win32-eventlog/Rakefile b/ext/win32-eventlog/Rakefile
new file mode 100644
index 0000000..4788d73
--- /dev/null
+++ b/ext/win32-eventlog/Rakefile
@@ -0,0 +1,53 @@
+require "rubygems"
+require "rake"
+require "mkmf"
+
+desc "Building event log dll"
+
+def ensure_present(commands)
+  commands.each do |c|
+    unless find_executable c
+      warn "Could not find #{c}. Windows Event Logging will not correctly function."
+    end
+  end
+end
+
+EVT_MC_FILE = "chef-log.man"
+EVT_RC_FILE = "chef-log.rc"
+EVT_RESOURCE_OBJECT = "resource.o"
+EVT_SHARED_OBJECT = "chef-log.dll"
+MC = "windmc"
+RC = "windres"
+CC = "gcc"
+
+ensure_present [MC, RC, CC]
+
+task :build => [EVT_RESOURCE_OBJECT, EVT_SHARED_OBJECT]
+task :default => [:build, :register]
+
+file EVT_RC_FILE => EVT_MC_FILE do
+  sh "#{MC} #{EVT_MC_FILE}"
+end
+
+file EVT_RESOURCE_OBJECT => EVT_RC_FILE do
+  sh "#{RC} -i #{EVT_RC_FILE} -o #{EVT_RESOURCE_OBJECT}"
+end
+
+file EVT_SHARED_OBJECT => EVT_RESOURCE_OBJECT do
+  sh "#{CC} -o #{EVT_SHARED_OBJECT} -shared #{EVT_RESOURCE_OBJECT}"
+end
+
+task :register => EVT_SHARED_OBJECT do
+  require "win32/eventlog"
+  dll_file = File.expand_path(EVT_SHARED_OBJECT)
+  begin
+    Win32::EventLog.add_event_source(
+      :source => "Application",
+      :key_name => "Chef",
+      :event_message_file => dll_file,
+      :category_message_file => dll_file,
+    )
+  rescue Errno::EIO => e
+    puts "Skipping event log registration due to missing privileges: #{e}"
+  end
+end
diff --git a/ext/win32-eventlog/chef-log.man b/ext/win32-eventlog/chef-log.man
new file mode 100644
index 0000000..10c28e7
--- /dev/null
+++ b/ext/win32-eventlog/chef-log.man
@@ -0,0 +1,56 @@
+MessageId=10000
+SymbolicName=RUN_START
+Language=English
+Starting Chef Client run v%1
+.
+
+MessageId=10001
+SymbolicName=RUN_STARTED
+Language=English
+Started Chef Client run %1
+.
+
+MessageId=10002
+SymbolicName=RUN_COMPLETED
+Language=English
+Completed Chef Client run %1 in %2 seconds
+.
+
+MessageId=10003
+SymbolicName=RUN_FAILED
+Language=English
+Failed Chef Client run %1 in %2 seconds.%n
+Exception type: %3%n
+Exception message: %4%n
+Exception backtrace: %5%n
+.
+
+MessageId=10100
+SymbolicName=INFO
+Language=English
+[INFO] %1
+.
+
+MessageId=10101
+SymbolicName=WARN
+Language=English
+[WARN] %1
+.
+
+MessageId=10102
+SymbolicName=DEBUG
+Language=English
+[DEBUG] %1
+.
+
+MessageId=10103
+SymbolicName=ERROR
+Language=English
+[ERROR] %1
+.
+
+MessageId=10104
+SymbolicName=FATAL
+Language=English
+[FATAL] %1
+.
diff --git a/kitchen-tests/.chef/client.rb b/kitchen-tests/.chef/client.rb
new file mode 100644
index 0000000..be46e2e
--- /dev/null
+++ b/kitchen-tests/.chef/client.rb
@@ -0,0 +1,10 @@
+
+chef_dir = File.expand_path(File.dirname(__FILE__))
+repo_dir = File.expand_path(File.join(chef_dir, '..'))
+
+log_level       :info
+chef_repo_path  repo_dir
+local_mode      true
+cache_path      "#{ENV['HOME']}/.cache/chef"
+
+audit_mode :enabled
\ No newline at end of file
diff --git a/kitchen-tests/.kitchen.travis.yml b/kitchen-tests/.kitchen.travis.yml
new file mode 100644
index 0000000..2c3de60
--- /dev/null
+++ b/kitchen-tests/.kitchen.travis.yml
@@ -0,0 +1,42 @@
+---
+driver:
+  name: ec2
+  aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
+  aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
+  aws_ssh_key_id: <%= ENV['AWS_KEYPAIR_NAME'] %>
+  region: "us-west-2"
+  availability_zone: "us-west-2a"
+  security_group_ids: ["travis-ci"]
+  instance_type: "m3.medium"
+
+provisioner:
+  name: chef_github
+  github_owner: "chef"
+  github_repo: "chef"
+  refname: <%= ENV['TRAVIS_COMMIT'] %>
+  github_access_token: <%= ENV['KITCHEN_GITHUB_TOKEN'] %>
+  data_path: test/fixtures
+# disable file provider diffs so we don't overflow travis' line limit
+  client_rb:
+    diff_disabled: true
+
+transport:
+  ssh_key: <%= ENV['EC2_SSH_KEY_PATH'] %>
+
+platforms:
+  - name: ubuntu-12.04
+    driver:
+      # http://cloud-images.ubuntu.com/locator/ec2/
+      # 12.04 amd64 us-west-2 hvm:ssd
+      image_id: ami-f3635fc3
+  - name: rhel-6
+    driver:
+      # https://github.com/chef/releng-chef-repo/blob/master/script/ci#L93-L96
+      image_id: ami-7df0bd4d
+
+suites:
+  - name: webapp
+    run_list:
+      - recipe[apt::default]
+      - recipe[webapp::default]
+    attributes:
diff --git a/kitchen-tests/.kitchen.yml b/kitchen-tests/.kitchen.yml
new file mode 100644
index 0000000..c853f51
--- /dev/null
+++ b/kitchen-tests/.kitchen.yml
@@ -0,0 +1,38 @@
+---
+driver:
+  name: vagrant
+  customize:
+    cpus: 4
+    memory: 2048
+
+provisioner:
+  name: chef_github
+  github_owner: "chef"
+  github_repo: "chef"
+  refname: <%= %x(git rev-parse HEAD) %>
+  data_path: test/fixtures
+  client_rb:
+    diff_disabled: true
+
+platforms:
+  # upstream community mysql cookbook broken on 10.04
+  #- name: ubuntu-10.04
+  #  run_list: apt::default
+  - name: ubuntu-12.04
+    run_list: apt::default
+  - name: ubuntu-14.04
+    run_list: apt::default
+  # upstream community mysql cookbook also broken on 14.10
+  #- name: ubuntu-14.10
+  #  run_list: apt::default
+  - name: centos-6.4
+    run_list: yum-epel::default
+  - name: centos-5.10
+    run_list: yum-epel::default
+
+suites:
+  - name: webapp
+    run_list:
+      - recipe[apt::default]
+      - recipe[webapp::default]
+    attributes:
diff --git a/kitchen-tests/Berksfile b/kitchen-tests/Berksfile
new file mode 100644
index 0000000..decb85a
--- /dev/null
+++ b/kitchen-tests/Berksfile
@@ -0,0 +1,5 @@
+source "https://supermarket.getchef.com"
+
+cookbook "webapp", :path => "cookbooks/webapp"
+
+cookbook "php", "~> 1.5.0"
diff --git a/kitchen-tests/Gemfile b/kitchen-tests/Gemfile
new file mode 100644
index 0000000..acc6215
--- /dev/null
+++ b/kitchen-tests/Gemfile
@@ -0,0 +1,10 @@
+source "https://rubygems.org"
+
+group :end_to_end do
+  gem "berkshelf"
+  gem "test-kitchen", "~> 1.4"
+  gem "kitchen-appbundle-updater"
+  gem "kitchen-vagrant", "~> 0.17"
+  gem "kitchen-ec2", github: "test-kitchen/kitchen-ec2"
+  gem "vagrant-wrapper"
+end
diff --git a/kitchen-tests/README.md b/kitchen-tests/README.md
new file mode 100644
index 0000000..2d03b19
--- /dev/null
+++ b/kitchen-tests/README.md
@@ -0,0 +1,89 @@
+# End-To-End Testing for Chef Client
+Here we seek to provide end-to-end testing of Chef Client through cookbooks which
+exercise many of the available resources, providers, and common patterns. The cookbooks
+here are designed to ensure certain capabilities remain functional with updates
+to the client code base.
+
+## Getting started
+All the gems needed to run these tests can be installed with Bundler.
+
+```shell
+chef/kitchen-tests$ bundle install
+```
+
+To ensure everything is working properly, and to see which platforms can have tests
+executed on them, run
+
+```shell
+chef/kitchen-tests$ bundle exec kitchen list
+```
+
+You should see output similar to
+
+```shell
+Instance            Driver    Provisioner  Last Action
+webapp-ubuntu-1204  Vagrant   ChefSolo     <Not Created>
+```
+
+## Testing
+We use Test Kitchen to build instances, test client code, and destroy instances. If
+you are unfamiliar with Test Kitchen we recommend checking out the [tutorial](http://kitchen.ci/)
+along with the `kitchen-vagrant` [driver documentation](https://github.com/test-kitchen/kitchen-vagrant).
+Test Kitchen is configured to manipulate instances using [Vagrant](http://www.vagrantup.com/)
+when testing locally, and [Amazon EC2](http://aws.amazon.com/ec2/) when testing
+pull requests on [Travis CI](https://travis-ci.com).
+
+### Commands
+Kitchen instances are led through a series of states. The instance states, and the actions
+taken to transition into each state, are in order:
+* `destroy`: Delete all information for and terminate one or more instances.
+  * This is equivalent to running `vagrant destroy` to stop and delete a Vagrant machine.
+* `create`: Start one or more instances.
+  * This is equivalent to running `vagrant up --no-provision` to start a Vagrant instance.
+* `converge`: Use a provisioner to configure one or more instances.
+  * By default, Test Kitchen is configured to use the `ChefSolo` provisioner which:
+    * Prepares local files for transfer,
+    * Installs the latest release of Chef Omnibus,
+    * Downloads Chef Client source code from the prescribed GitHub repository and reference,
+    * Builds and installs a `chef` gem from the downloaded source,
+    * Runs `chef-client`.
+* `setup`: Prepare to run automated tests. Installs `busser` and related gems on one or more instances.
+* `verify`: Run automated tests on one or more instances.
+
+When transitioning between states, actions for any and all intermediate states will performed.
+Executing the `create` then the `verify` commands is equivalent to executing `create`, `converge`,
+`setup`, and `verify` one-by-one and in order. The only exception is `destroy`, which will
+immediately transfer that machine's state to destroyed.
+
+The `test` command takes one or more instances through all the states, in order: `destroy`, `create`,
+`converge`, `setup`, `verify`, `destroy`.
+
+To see a list of available commands, type `bundle exec kitchen help`. To see more information
+about a particular command, type `bundle exec kitchen help <command>`.
+
+### Configuring your tests
+Test Kitchen is configured for local testing in the `.kitchen.yml` file which resides in this directory.
+You will need to configure the provisioner before running the tests.
+
+The provisioner can be configured to pull client source code from a GitHub repository using any
+valid Git reference. You are encouraged to modify any of these settings, but please return them
+to their original values before submitting a pull request for review (unless, of course, your
+changes are enhancements to the default provisioner settings).
+
+By default, the provisioner is configured to pull your most recent commit to `opscode/chef`. You
+can change this by modifying the `github` and `branch` provisioner options:
+* `github`: Set this to `"<your_username>/<your_chef_repo>"`. The default is `"opscode/chef"`.
+* `branch`: This can be any valid git reference (e.g., branch name, tag, or commit SHA). If omitted, it defaults to `master`.
+
+The branch you choose must be accessible on GitHub. You cannot use a local commit at this time.
+
+### Testing pull requests
+These end-to-end tests are also configured to run with Travis on EC2 instances when you submit a pull request
+to `opscode/chef`. Kitchen is configured to pull chef client source code from the branch it is testing. There
+is no need to modify `.kitchen.travis.yml` unless you are contributing tests.
+
+## Contributing
+We would love to fill out our end-to-end testing coverage! If you have cookbooks and tests that you would
+like to see become a part of client testing, we encourage you to submit a pull request with your additions.
+We request that you do not add platforms to `.kitchen.travis.yml`. Please file a request to add a
+platform under [Issues](https://github.com/opscode/chef/issues).
diff --git a/kitchen-tests/cookbooks/audit_test/.gitignore b/kitchen-tests/cookbooks/audit_test/.gitignore
new file mode 100644
index 0000000..ec2a890
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/.gitignore
@@ -0,0 +1,16 @@
+.vagrant
+Berksfile.lock
+*~
+*#
+.#*
+\#*#
+.*.sw[a-z]
+*.un~
+
+# Bundler
+Gemfile.lock
+bin/*
+.bundle/*
+
+.kitchen/
+.kitchen.local.yml
diff --git a/kitchen-tests/cookbooks/audit_test/.kitchen.yml b/kitchen-tests/cookbooks/audit_test/.kitchen.yml
new file mode 100644
index 0000000..be11e33
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/.kitchen.yml
@@ -0,0 +1,16 @@
+---
+driver:
+  name: vagrant
+
+provisioner:
+  name: chef_zero
+
+platforms:
+  - name: ubuntu-12.04
+  - name: centos-6.5
+
+suites:
+  - name: default
+    run_list:
+      - recipe[audit_test::default]
+    attributes:
diff --git a/kitchen-tests/cookbooks/audit_test/Berksfile b/kitchen-tests/cookbooks/audit_test/Berksfile
new file mode 100644
index 0000000..0ac9b78
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/Berksfile
@@ -0,0 +1,3 @@
+source "https://supermarket.getchef.com"
+
+metadata
diff --git a/kitchen-tests/cookbooks/audit_test/README.md b/kitchen-tests/cookbooks/audit_test/README.md
new file mode 100644
index 0000000..75e2f44
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/README.md
@@ -0,0 +1,12 @@
+# audit_test
+
+This cookbook has some basic recipes to test audit mode.
+
+In order to run these tests on your dev box:
+
+```
+$ bundle install
+$ bundle exec chef-client -c kitchen-tests/.chef/client.rb -z -o audit_test::default -l debug
+```
+
+Expected JSON output for the tests will be printed to `debug` log.
diff --git a/kitchen-tests/cookbooks/audit_test/chefignore b/kitchen-tests/cookbooks/audit_test/chefignore
new file mode 100644
index 0000000..80dc2d2
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/chefignore
@@ -0,0 +1,95 @@
+# Put files/directories that should be ignored in this file when uploading
+# or sharing to the community site.
+# Lines that start with '# ' are comments.
+
+# OS generated files #
+######################
+.DS_Store
+Icon?
+nohup.out
+ehthumbs.db
+Thumbs.db
+
+# SASS #
+########
+.sass-cache
+
+# EDITORS #
+###########
+\#*
+.#*
+*~
+*.sw[a-z]
+*.bak
+REVISION
+TAGS*
+tmtags
+*_flymake.*
+*_flymake
+*.tmproj
+.project
+.settings
+mkmf.log
+
+## COMPILED ##
+##############
+a.out
+*.o
+*.pyc
+*.so
+*.com
+*.class
+*.dll
+*.exe
+*/rdoc/
+
+# Testing #
+###########
+.watchr
+.rspec
+spec/*
+spec/fixtures/*
+test/*
+features/*
+Guardfile
+Procfile
+
+# SCM #
+#######
+.git
+*/.git
+.gitignore
+.gitmodules
+.gitconfig
+.gitattributes
+.svn
+*/.bzr/*
+*/.hg/*
+*/.svn/*
+
+# Berkshelf #
+#############
+Berksfile
+Berksfile.lock
+cookbooks/*
+tmp
+
+# Cookbooks #
+#############
+CONTRIBUTING
+
+# Strainer #
+############
+Colanderfile
+Strainerfile
+.colander
+.strainer
+
+# Vagrant #
+###########
+.vagrant
+Vagrantfile
+
+# Travis #
+##########
+.travis.yml
diff --git a/kitchen-tests/cookbooks/audit_test/metadata.rb b/kitchen-tests/cookbooks/audit_test/metadata.rb
new file mode 100644
index 0000000..3fbda5d
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/metadata.rb
@@ -0,0 +1,7 @@
+name             "audit_test"
+maintainer       "The Authors"
+maintainer_email "you at example.com"
+license          "all_rights"
+description      "Installs/Configures audit_test"
+long_description "Installs/Configures audit_test"
+version          "0.1.0"
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/default.rb b/kitchen-tests/cookbooks/audit_test/recipes/default.rb
new file mode 100644
index 0000000..886c2cd
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/default.rb
@@ -0,0 +1,26 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: default
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+control_group "basic control group" do
+  control "basic math" do
+    it "should pass" do
+      expect(2 - 2).to eq(0)
+    end
+  end
+end
+
+control_group "control group without top level control" do
+  it "should pass" do
+    expect(2 - 2).to eq(0)
+  end
+end
+
+control_group "control group with empty control" do
+  control "empty"
+end
+
+control_group "empty control group with block" do
+end
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb
new file mode 100644
index 0000000..2b5b8b5
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_duplicate_control_groups.rb
@@ -0,0 +1,17 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: error_duplicate_control_groups
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+control_group "basic control group" do
+  it "should pass" do
+    expect(2 - 2).to eq(0)
+  end
+end
+
+control_group "basic control group" do
+  it "should pass" do
+    expect(2 - 2).to eq(0)
+  end
+end
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb
new file mode 100644
index 0000000..e4c444e
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_no_block.rb
@@ -0,0 +1,7 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: error_no_block
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+control_group "empty control group without block"
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb b/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb
new file mode 100644
index 0000000..61d809a
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/error_orphan_control.rb
@@ -0,0 +1,13 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: error_orphan_control
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+control_group "basic control group" do
+  it "should pass" do
+    expect(2 - 2).to eq(0)
+  end
+end
+
+control "orphan control"
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb b/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb
new file mode 100644
index 0000000..9e6adfe
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/failed_specs.rb
@@ -0,0 +1,14 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: failed_specs
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+control_group "basic control group" do
+  control "basic math" do
+    # Can not write a good control :(
+    it "should pass" do
+      expect(2 - 0).to eq(0)
+    end
+  end
+end
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb
new file mode 100644
index 0000000..36dd714
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_collision.rb
@@ -0,0 +1,31 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: serverspec_collision
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+file "/tmp/audit_test_file" do
+  action :create
+  content "Welcome to audit mode."
+end
+
+control_group "file auditing" do
+  describe "test file" do
+    it "says welcome" do
+      expect(file("/tmp/audit_test_file")).to contain("Welcome")
+    end
+  end
+end
+
+file "/tmp/audit_test_file_2" do
+  action :create
+  content "Bye to audit mode."
+end
+
+control_group "end file auditing" do
+  describe "end file" do
+    it "says bye" do
+      expect(file("/tmp/audit_test_file_2")).to contain("Bye")
+    end
+  end
+end
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb
new file mode 100644
index 0000000..fc44fb3
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/serverspec_support.rb
@@ -0,0 +1,37 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: serverspec_support
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+file "/tmp/audit_test_file" do
+  action :create
+  content "Welcome to audit mode."
+end
+
+# package "curl" do
+#   action :install
+# end
+
+control_group "serverspec helpers with types" do
+  control "file helper" do
+    it "says welcome" do
+      expect(file("/tmp/audit_test_file")).to contain("Welcome")
+    end
+  end
+
+  control service("com.apple.CoreRAID") do
+    it { is_expected.to be_enabled }
+    it { is_expected.not_to be_running }
+  end
+
+  # describe "package helper" do
+  #   it "works" do
+  #     expect(package("curl")).to be_installed
+  #   end
+  # end
+
+  control package("postgresql") do
+    it { is_expected.to_not be_installed }
+  end
+end
diff --git a/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb b/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb
new file mode 100644
index 0000000..7727c57
--- /dev/null
+++ b/kitchen-tests/cookbooks/audit_test/recipes/with_include_recipe.rb
@@ -0,0 +1,16 @@
+#
+# Cookbook Name:: audit_test
+# Recipe:: with_include_recipe
+#
+# Copyright 2014-2016, The Authors, All Rights Reserved.
+
+include_recipe "audit_test::serverspec_collision"
+
+control_group "basic example" do
+  it "should pass" do
+    expect(2 - 2).to eq(0)
+  end
+end
+
+include_recipe "audit_test::serverspec_collision"
+include_recipe "audit_test::default"
diff --git a/kitchen-tests/cookbooks/webapp/Berksfile b/kitchen-tests/cookbooks/webapp/Berksfile
new file mode 100644
index 0000000..4b60790
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/Berksfile
@@ -0,0 +1,5 @@
+source "https://api.berkshelf.com"
+
+metadata
+
+cookbook "apt"
diff --git a/kitchen-tests/cookbooks/webapp/README.md b/kitchen-tests/cookbooks/webapp/README.md
new file mode 100644
index 0000000..f19ab46
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/README.md
@@ -0,0 +1,3 @@
+# webapp
+
+TODO: Enter the cookbook description here.
diff --git a/kitchen-tests/cookbooks/webapp/attributes/default.rb b/kitchen-tests/cookbooks/webapp/attributes/default.rb
new file mode 100644
index 0000000..2ff7a6c
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/attributes/default.rb
@@ -0,0 +1,14 @@
+default["apache"]["remote_host_ip"] = "127.0.0.1"
+
+default["webapp"]["database"] = "webapp"
+default["webapp"]["db_username"] = "webapp"
+default["webapp"]["path"] = "/srv/webapp"
+
+# XXX: apache2 cookbook 2.0.0 has bugs around changing the mpm and then attempting a graceful restart
+# which fails and leaves the service down.
+case node["platform"]
+when "ubuntu"
+  if node["platform_version"].to_f >= 14.04
+    default[:apache][:mpm] = "event"
+  end
+end
diff --git a/kitchen-tests/cookbooks/webapp/metadata.rb b/kitchen-tests/cookbooks/webapp/metadata.rb
new file mode 100644
index 0000000..f1f07d9
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/metadata.rb
@@ -0,0 +1,12 @@
+name             "webapp"
+maintainer       ""
+maintainer_email ""
+license          ""
+description      "Installs/Configures webapp"
+long_description "Installs/Configures webapp"
+version          "0.1.0"
+
+depends "apache2"
+depends "database", "~> 2.3.1"
+depends "mysql"
+depends "php"
diff --git a/kitchen-tests/cookbooks/webapp/recipes/default.rb b/kitchen-tests/cookbooks/webapp/recipes/default.rb
new file mode 100644
index 0000000..2b3459b
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/recipes/default.rb
@@ -0,0 +1,64 @@
+#
+# Cookbook Name:: webapp
+# Recipe:: default
+#
+# Copyright (C) 2014
+#
+
+include_recipe "apache2"
+include_recipe "database::mysql"
+include_recipe "php"
+
+creds = Hash.new
+%w{mysql webapp}.each do |item_name|
+  creds[item_name] = data_bag_item("passwords", item_name)
+end
+
+web_app "webapp" do
+  server_name "localhost"
+  server_aliases [node["fqdn"], node["hostname"], "localhost.localdomain"]
+  docroot node["webapp"]["path"]
+  cookbook "apache2"
+end
+
+mysql_service "default" do
+  server_root_password creds["mysql"]["server_root_password"]
+  server_repl_password creds["mysql"]["server_repl_password"]
+end
+
+mysql_database node["webapp"]["database"] do
+  connection ({
+    :host => "localhost",
+    :username => "root",
+    :password => creds["mysql"]["server_root_password"],
+  })
+  action :create
+end
+
+mysql_database_user node["webapp"]["db_username"] do
+  connection ({
+    :host => "localhost",
+    :username => "root",
+    :password => creds["mysql"]["server_root_password"],
+  })
+  password creds["webapp"]["db_password"]
+  database_name node["webapp"]["database"]
+  privileges [:select, :update, :insert, :create, :delete]
+  action :grant
+end
+
+directory node["webapp"]["path"] do
+  owner "root"
+  group "root"
+  mode "0755"
+  action :create
+  recursive true
+end
+
+template "#{node['webapp']['path']}/index.html" do
+  source "index.html.erb"
+end
+
+template "#{node['webapp']['path']}/index.php" do
+  source "index.php.erb"
+end
diff --git a/kitchen-tests/cookbooks/webapp/templates/default/index.html.erb b/kitchen-tests/cookbooks/webapp/templates/default/index.html.erb
new file mode 100644
index 0000000..6da0629
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/templates/default/index.html.erb
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <h1>Hello, World!</h1>
+  </body>
+</html>
diff --git a/kitchen-tests/cookbooks/webapp/templates/default/index.php.erb b/kitchen-tests/cookbooks/webapp/templates/default/index.php.erb
new file mode 100644
index 0000000..b08b076
--- /dev/null
+++ b/kitchen-tests/cookbooks/webapp/templates/default/index.php.erb
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>PHP Test</title>
+  </head>
+  <body>
+    <?php echo '<p>Hello, World!</p>'; ?>
+  </body>
+</html>
diff --git a/kitchen-tests/data_bags/passwords/mysql.json b/kitchen-tests/data_bags/passwords/mysql.json
new file mode 100644
index 0000000..af02a6a
--- /dev/null
+++ b/kitchen-tests/data_bags/passwords/mysql.json
@@ -0,0 +1,5 @@
+{
+  "id": "mysql",
+  "server_root_password": "ilikerandompasswordstoo",
+  "server_repl_password": "itoolikerandompasswords"
+}
diff --git a/kitchen-tests/data_bags/passwords/webapp.json b/kitchen-tests/data_bags/passwords/webapp.json
new file mode 100644
index 0000000..43c0ae1
--- /dev/null
+++ b/kitchen-tests/data_bags/passwords/webapp.json
@@ -0,0 +1,4 @@
+{
+  "id": "webapp",
+  "db_password": "supersecretdbpassword"
+}
diff --git a/kitchen-tests/test/fixtures/platforms/centos/5.json b/kitchen-tests/test/fixtures/platforms/centos/5.json
new file mode 100644
index 0000000..9d324a2
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/centos/5.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "httpd",
+    "service_name": "httpd"
+  },
+  "mysql": {
+    "server_package": "mysql-server",
+    "client_package": "mysql",
+    "service_name": "mysqld"
+  },
+  "php" : {
+    "package": "php53"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/platforms/centos/6.json b/kitchen-tests/test/fixtures/platforms/centos/6.json
new file mode 100644
index 0000000..4f74a3e
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/centos/6.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "httpd",
+    "service_name": "httpd"
+  },
+  "mysql": {
+    "server_package": "mysql-server",
+    "client_package": "mysql",
+    "service_name": "mysqld"
+  },
+  "php" : {
+    "package": "php"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/platforms/ubuntu/10.04.json b/kitchen-tests/test/fixtures/platforms/ubuntu/10.04.json
new file mode 100644
index 0000000..a9677c7
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/ubuntu/10.04.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "apache2",
+    "service_name": "apache2"
+  },
+  "mysql": {
+    "server_package": "mysql-server-5.1",
+    "client_package": "mysql-client-5.1",
+    "service_name": "mysql"
+  },
+  "php" : {
+    "package": "php5"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/platforms/ubuntu/12.04.json b/kitchen-tests/test/fixtures/platforms/ubuntu/12.04.json
new file mode 100644
index 0000000..eab46db
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/ubuntu/12.04.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "apache2",
+    "service_name": "apache2"
+  },
+  "mysql": {
+    "server_package": "mysql-server-5.5",
+    "client_package": "mysql-client-5.5",
+    "service_name": "mysql"
+  },
+  "php" : {
+    "package": "php5"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/platforms/ubuntu/14.04.json b/kitchen-tests/test/fixtures/platforms/ubuntu/14.04.json
new file mode 100644
index 0000000..eab46db
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/ubuntu/14.04.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "apache2",
+    "service_name": "apache2"
+  },
+  "mysql": {
+    "server_package": "mysql-server-5.5",
+    "client_package": "mysql-client-5.5",
+    "service_name": "mysql"
+  },
+  "php" : {
+    "package": "php5"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/platforms/ubuntu/14.10.json b/kitchen-tests/test/fixtures/platforms/ubuntu/14.10.json
new file mode 100644
index 0000000..eab46db
--- /dev/null
+++ b/kitchen-tests/test/fixtures/platforms/ubuntu/14.10.json
@@ -0,0 +1,14 @@
+{
+  "apache": {
+    "package": "apache2",
+    "service_name": "apache2"
+  },
+  "mysql": {
+    "server_package": "mysql-server-5.5",
+    "client_package": "mysql-client-5.5",
+    "service_name": "mysql"
+  },
+  "php" : {
+    "package": "php5"
+  }
+}
diff --git a/kitchen-tests/test/fixtures/serverspec_helper.rb b/kitchen-tests/test/fixtures/serverspec_helper.rb
new file mode 100644
index 0000000..feb4c21
--- /dev/null
+++ b/kitchen-tests/test/fixtures/serverspec_helper.rb
@@ -0,0 +1,32 @@
+# Shamelessly copied from https://github.com/onehealth-cookbooks/apache2/blob/master/test/fixtures/serverspec_helper.rb
+# The commented-out platforms in the osmapping hash can be added once we have added them into
+# our .kitchen.yml and .kitchen.travis.yml and added the appropriate JSON under test/fixtures/platforms.
+
+require "serverspec"
+require "json"
+require "ffi_yajl"
+
+set :backend, :exec
+
+include Specinfra::Helper::Properties
+
+require "pp"
+pp os
+
+def load_nodestub
+  case os[:family]
+  when "ubuntu", "debian"
+    platform = os[:family]
+    platform_version = os[:release]
+  when "redhat"
+    platform = "centos"
+    platform_version = os[:release].to_i
+  end
+  FFI_Yajl::Parser.parse(IO.read("#{ENV['BUSSER_ROOT']}/../kitchen/data/platforms/#{platform}/#{platform_version}.json"), :symbolize_names => true)
+end
+
+# centos-59 doesn't have /sbin in the default path,
+# so we must ensure it's on serverspec's path
+set :path, "$PATH:/sbin"
+
+set_property load_nodestub
diff --git a/kitchen-tests/test/integration/webapp/serverspec/Gemfile b/kitchen-tests/test/integration/webapp/serverspec/Gemfile
new file mode 100644
index 0000000..eef1450
--- /dev/null
+++ b/kitchen-tests/test/integration/webapp/serverspec/Gemfile
@@ -0,0 +1,4 @@
+# This Gemfile is only needed so that busser will install gems it needs for serverspec_helper.rb to work
+source "https://rubygems.org"
+
+gem "ffi-yajl", "~> 1.1" # Go away, JSON gem
diff --git a/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb b/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb
new file mode 100644
index 0000000..992e4f7
--- /dev/null
+++ b/kitchen-tests/test/integration/webapp/serverspec/localhost/default_spec.rb
@@ -0,0 +1,127 @@
+
+require "net/http"
+require "uri"
+
+require "#{ENV['BUSSER_ROOT']}/../kitchen/data/serverspec_helper"
+
+describe "webapp::default", :end_to_end => true do
+
+  describe "installed packages" do
+    shared_examples_for "a package" do
+      it "is installed" do
+        expect(package(package_name)).to be_installed
+      end
+    end
+
+    describe "#{property[:apache][:package]} package" do
+      include_examples "a package" do
+        let(:package_name) { property[:apache][:package] }
+      end
+    end
+
+    describe "#{property[:mysql][:server_package]} package" do
+      include_examples "a package" do
+        let(:package_name) { property[:mysql][:server_package] }
+      end
+    end
+
+    describe "#{property[:mysql][:client_package]} package" do
+      include_examples "a package" do
+        let(:package_name) { property[:mysql][:client_package] }
+      end
+    end
+
+    describe "php package" do
+      include_examples "a package" do
+        let(:package_name) { property[:php][:package] }
+      end
+    end
+  end
+
+  describe "enabled/running services" do
+    shared_examples_for "a service" do
+      it "is enabled" do
+        expect(service(service_name)).to be_enabled
+      end
+
+      it "is running" do
+        expect(service(service_name)).to be_enabled
+      end
+    end
+
+    describe "#{property[:apache][:service_name]} service" do
+      include_examples "a service" do
+        let(:service_name) { property[:apache][:service_name] }
+      end
+    end
+
+    describe "mysql service" do
+      include_examples "a service" do
+        let(:service_name) { property[:mysql][:service_name] }
+      end
+    end
+
+  end
+
+  describe "mysql database" do
+    let(:db_query) { "mysql -u root -pilikerandompasswordstoo -e \"#{statement}\"" }
+    let(:statement) { "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='webapp'" }
+    it "creates a database called 'webapp'" do
+      expect(command(db_query).stdout).to match /webapp/
+    end
+
+    describe "mysql database user 'webapp'" do
+      let(:statement) { "SELECT Host, Db FROM mysql.db WHERE User='webapp'\\G" }
+      it "adds user 'webapp' to database 'webapp at localhost'" do
+        expect(command(db_query).stdout).to match /Host: localhost\n  Db: webapp/
+      end
+
+      describe "grants" do
+        shared_examples_for "a privilege" do |priv|
+          let(:statement) {
+            "SELECT #{priv_query}" \
+            " FROM mysql.db" \
+            " WHERE Host='localhost' AND Db='webapp' AND User='webapp'\\G"
+          }
+          let(:priv_query) { "#{priv.capitalize}_priv" }
+
+          it "has privilege #{priv} on 'webapp at localhost'" do
+            expect(command(db_query).stdout).to match /#{priv_query}: Y/
+          end
+        end
+
+        %w{select update insert delete create}.each do |priv|
+          include_examples "a privilege", priv do
+          end
+        end
+      end
+    end
+  end
+
+  describe "generated webpages" do
+    let(:get_response) { Net::HTTP.get_response(uri) }
+    shared_examples_for "a webpage" do
+      it "exists" do
+        expect(get_response).to be_kind_of(Net::HTTPSuccess)
+      end
+
+      it "displays content" do
+        expect(get_response.body).to include(content)
+      end
+    end
+
+    describe "http://localhost/index.html" do
+      include_examples "a webpage" do
+        let(:uri) { URI.parse("http://localhost/index.html") }
+        let(:content) { "Hello, World!" }
+      end
+    end
+
+    describe "http://localhost/index.php" do
+      include_examples "a webpage" do
+        let(:uri) { URI.parse("http://localhost/index.php") }
+        let(:content) { "Hello, World!" }
+      end
+    end
+  end
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb b/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb
new file mode 100644
index 0000000..f28b9f8
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/acl_entry.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+
+module Chef::ChefFS::FileSystem
+  AclEntry = ChefServer::AclEntry
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
new file mode 100644
index 0000000..123fb9e
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir"
+
+module Chef::ChefFS::FileSystem
+  ChefRepositoryFileSystemRootDir = Repository::ChefRepositoryFileSystemRootDir
+end
diff --git a/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb
new file mode 100644
index 0000000..acb81dd
--- /dev/null
+++ b/lib-backcompat/chef/chef_fs/file_system/chef_server_root_dir.rb
@@ -0,0 +1,5 @@
+require "chef/chef_fs/file_system/chef_server/chef_server_root_dir"
+
+module Chef::ChefFS::FileSystem
+  ChefServerRootDir = ChefServer::ChefServerRootDir
+end
diff --git a/lib/chef.rb b/lib/chef.rb
index 6bce976..3e161dc 100644
--- a/lib/chef.rb
+++ b/lib/chef.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,20 @@
 # limitations under the License.
 #
 
-require 'chef/version'
-require 'chef/nil_argument'
-require 'chef/mash'
-require 'chef/exceptions'
-require 'chef/log'
-require 'chef/config'
-require 'chef/providers'
-require 'chef/resources'
-require 'chef/shell_out'
+require "chef/version"
+require "chef/nil_argument"
+require "chef/mash"
+require "chef/exceptions"
+require "chef/log"
+require "chef/config"
+require "chef/providers"
+require "chef/resources"
+require "chef/shell_out"
 
-require 'chef/daemon'
+require "chef/daemon"
 
-require 'chef/run_status'
-require 'chef/handler'
-require 'chef/handler/json_file'
-
-require 'chef/chef_class'
+require "chef/run_status"
+require "chef/handler"
+require "chef/handler/json_file"
+require "chef/event_dispatch/dsl"
+require "chef/chef_class"
diff --git a/lib/chef/api_client.rb b/lib/chef/api_client.rb
index ce9ceb3..27701c6 100644
--- a/lib/chef/api_client.rb
+++ b/lib/chef/api_client.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,19 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/server_api"
 
+# DEPRECATION NOTE
+#
+# This code will be removed in Chef 13 in favor of the code in Chef::ApiClientV1,
+# which will be moved to this namespace. New development should occur in
+# Chef::ApiClientV1 until the time before Chef 13.
 class Chef
   class ApiClient
 
@@ -32,7 +38,7 @@ class Chef
 
     # Create a new Chef::ApiClient object.
     def initialize
-      @name = ''
+      @name = ""
       @public_key = nil
       @private_key = nil
       @admin = false
@@ -43,11 +49,11 @@ class Chef
     #
     # @params [Optional String] The name must be alpha-numeric plus - and _.
     # @return [String] The current value of the name.
-    def name(arg=nil)
+    def name(arg = nil)
       set_or_return(
         :name,
         arg,
-        :regex => /^[\-[:alnum:]_\.]+$/
+        :regex => /^[\-[:alnum:]_\.]+$/,
       )
     end
 
@@ -55,11 +61,11 @@ class Chef
     #
     # @params [Optional True/False] Should be true or false - default is false.
     # @return [True/False] The current value
-    def admin(arg=nil)
+    def admin(arg = nil)
       set_or_return(
         :admin,
         arg,
-        :kind_of => [ TrueClass, FalseClass ]
+        :kind_of => [ TrueClass, FalseClass ],
       )
     end
 
@@ -67,11 +73,11 @@ class Chef
     #
     # @params [Optional String] The string representation of the public key.
     # @return [String] The current value.
-    def public_key(arg=nil)
+    def public_key(arg = nil)
       set_or_return(
         :public_key,
         arg,
-        :kind_of => String
+        :kind_of => String,
       )
     end
 
@@ -80,11 +86,11 @@ class Chef
     # @params [Boolean] whether or not the client is a validator.  If
     #   `nil`, retrieves the already-set value.
     # @return [Boolean] The current value
-    def validator(arg=nil)
+    def validator(arg = nil)
       set_or_return(
         :validator,
         arg,
-        :kind_of => [TrueClass, FalseClass]
+        :kind_of => [TrueClass, FalseClass],
       )
     end
 
@@ -92,11 +98,11 @@ class Chef
     #
     # @params [Optional String] The string representation of the private key.
     # @return [String] The current value.
-    def private_key(arg=nil)
+    def private_key(arg = nil)
       set_or_return(
         :private_key,
         arg,
-        :kind_of => [String, FalseClass]
+        :kind_of => [String, FalseClass],
       )
     end
 
@@ -110,8 +116,8 @@ class Chef
         "public_key" => @public_key,
         "validator" => @validator,
         "admin" => @admin,
-        'json_class' => self.class.name,
-        "chef_type" => "client"
+        "json_class" => self.class.name,
+        "chef_type" => "client",
       }
       result["private_key"] = @private_key if @private_key
       result
@@ -135,6 +141,7 @@ class Chef
     end
 
     def self.json_create(data)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::ApiClient#from_hash")
       from_hash(data)
     end
 
@@ -143,7 +150,7 @@ class Chef
     end
 
     def self.http_api
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
     end
 
     def self.reregister(name)
@@ -151,7 +158,7 @@ class Chef
       api_client.reregister
     end
 
-    def self.list(inflate=false)
+    def self.list(inflate = false)
       if inflate
         response = Hash.new
         Chef::Search::Query.new.search(:client) do |n|
@@ -170,7 +177,7 @@ class Chef
       if response.kind_of?(Chef::ApiClient)
         response
       else
-        json_create(response)
+        from_hash(response)
       end
     end
 
@@ -182,11 +189,11 @@ class Chef
     # Save this client via the REST API, returns a hash including the private key
     def save
       begin
-        http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator})
+        http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator })
       rescue Net::HTTPServerException => e
         # If that fails, go ahead and try and update it
         if e.response.code == "404"
-          http_api.post("clients", {:name => self.name, :admin => self.admin, :validator => self.validator })
+          http_api.post("clients", { :name => self.name, :admin => self.admin, :validator => self.validator })
         else
           raise e
         end
@@ -215,11 +222,11 @@ class Chef
 
     def inspect
       "Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' validator:'#{validator}' " +
-      "public_key:'#{public_key}' private_key:'#{private_key}'"
+        "public_key:'#{public_key}' private_key:'#{private_key}'"
     end
 
     def http_api
-      @http_api ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
     end
 
   end
diff --git a/lib/chef/api_client/registration.rb b/lib/chef/api_client/registration.rb
index de5fc7a..8547b4a 100644
--- a/lib/chef/api_client/registration.rb
+++ b/lib/chef/api_client/registration.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/rest'
-require 'chef/exceptions'
+require "chef/config"
+require "chef/server_api"
+require "chef/exceptions"
 
 class Chef
   class ApiClient
@@ -45,7 +45,7 @@ class Chef
       #--
       # If client creation fails with a 5xx, it is retried up to 5 times. These
       # retries are on top of the retries with randomized exponential backoff
-      # built in to Chef::REST. The retries here are a workaround for failures
+      # built in to Chef::ServerAPI. The retries here are a workaround for failures
       # caused by resource contention in Hosted Chef when creating a very large
       # number of clients simultaneously, (e.g., spinning up 100s of ec2 nodes
       # at once). Future improvements to the affected component should make
@@ -53,8 +53,9 @@ class Chef
       def run
         assert_destination_writable!
         retries = Config[:client_registration_retries] || 5
+        client = nil
         begin
-          create_or_update
+          client = api_client(create_or_update)
         rescue Net::HTTPFatalError => e
           # HTTPFatalError implies 5xx.
           raise if retries <= 0
@@ -64,11 +65,13 @@ class Chef
           retry
         end
         write_key
+        client
       end
 
       def assert_destination_writable!
         if (File.exists?(destination) && !File.writable?(destination)) or !File.writable?(File.dirname(destination))
-          raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination} - check permissions?"
+          abs_path = File.expand_path(destination)
+          raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?"
         end
       end
 
@@ -105,6 +108,28 @@ class Chef
         response
       end
 
+      def api_client(response)
+        return response if response.is_a?(Chef::ApiClient)
+
+        client = Chef::ApiClient.new
+        client.name(name)
+        client.public_key(api_client_key(response, "public_key"))
+        client.private_key(api_client_key(response, "private_key"))
+        client
+      end
+
+      def api_client_key(response, key_name)
+        if response[key_name]
+          if response[key_name].respond_to?(:to_pem)
+            response[key_name].to_pem
+          else
+            response[key_name]
+          end
+        elsif response["chef_key"]
+          response["chef_key"][key_name]
+        end
+      end
+
       def put_data
         base_put_data = { :name => name, :admin => false }
         if self_generate_keys?
@@ -122,9 +147,13 @@ class Chef
       end
 
       def http_api
-        @http_api ||= Chef::REST.new(Chef::Config[:chef_server_url],
-                                     Chef::Config[:validation_client_name],
-                                     Chef::Config[:validation_key])
+        @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url],
+                                          {
+                                            :api_version => "0",
+                                            :client_name => Chef::Config[:validation_client_name],
+                                            :signing_key_filename => Chef::Config[:validation_key],
+                                          },
+                                         )
       end
 
       # Whether or not to generate keys locally and post the public key to the
@@ -151,7 +180,7 @@ class Chef
       end
 
       def file_flags
-        base_flags = File::CREAT|File::TRUNC|File::RDWR
+        base_flags = File::CREAT | File::TRUNC | File::RDWR
         # Windows doesn't have symlinks, so it doesn't have NOFOLLOW
         if defined?(File::NOFOLLOW) && !Chef::Config[:follow_client_key_symlink]
           base_flags |= File::NOFOLLOW
diff --git a/lib/chef/api_client_v1.rb b/lib/chef/api_client_v1.rb
new file mode 100644
index 0000000..ce624ad
--- /dev/null
+++ b/lib/chef/api_client_v1.rb
@@ -0,0 +1,325 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/exceptions"
+require "chef/mixin/api_version_request_handling"
+require "chef/server_api"
+require "chef/api_client"
+
+# COMPATIBILITY NOTE
+#
+# This ApiClientV1 code attempts to make API V1 requests and falls back to
+# API V0 requests when it fails. New development should occur here instead
+# of Chef::ApiClient as this will replace that namespace when Chef 13 is released.
+#
+# If you need to default to API V0 behavior (i.e. you need GET client to return
+# a public key, etc), please use Chef::ApiClient and update your code to support
+# API V1 before you pull in Chef 13.
+class Chef
+  class ApiClientV1
+
+    include Chef::Mixin::FromFile
+    include Chef::Mixin::ParamsValidate
+    include Chef::Mixin::ApiVersionRequestHandling
+
+    SUPPORTED_API_VERSIONS = [0, 1]
+
+    # Create a new Chef::ApiClientV1 object.
+    def initialize
+      @name = ""
+      @public_key = nil
+      @private_key = nil
+      @admin = false
+      @validator = false
+      @create_key = nil
+    end
+
+    def chef_rest_v0
+      @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0", :inflate_json_class => false })
+    end
+
+    def chef_rest_v1
+      @chef_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1", :inflate_json_class => false })
+    end
+
+    def self.http_api
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1", :inflate_json_class => false })
+    end
+
+    # Gets or sets the client name.
+    #
+    # @params [Optional String] The name must be alpha-numeric plus - and _.
+    # @return [String] The current value of the name.
+    def name(arg = nil)
+      set_or_return(
+        :name,
+        arg,
+        :regex => /^[\-[:alnum:]_\.]+$/,
+      )
+    end
+
+    # Gets or sets whether this client is an admin.
+    #
+    # @params [Optional True/False] Should be true or false - default is false.
+    # @return [True/False] The current value
+    def admin(arg = nil)
+      set_or_return(
+        :admin,
+        arg,
+        :kind_of => [ TrueClass, FalseClass ],
+      )
+    end
+
+    # Gets or sets the public key.
+    #
+    # @params [Optional String] The string representation of the public key.
+    # @return [String] The current value.
+    def public_key(arg = nil)
+      set_or_return(
+        :public_key,
+        arg,
+        :kind_of => String,
+      )
+    end
+
+    # Gets or sets whether this client is a validator.
+    #
+    # @params [Boolean] whether or not the client is a validator.  If
+    #   `nil`, retrieves the already-set value.
+    # @return [Boolean] The current value
+    def validator(arg = nil)
+      set_or_return(
+        :validator,
+        arg,
+        :kind_of => [TrueClass, FalseClass],
+      )
+    end
+
+    # Private key. The server will return it as a string.
+    # Set to true under API V0 to have the server regenerate the default key.
+    #
+    # @params [Optional String] The string representation of the private key.
+    # @return [String] The current value.
+    def private_key(arg = nil)
+      set_or_return(
+        :private_key,
+        arg,
+        :kind_of => [String, TrueClass, FalseClass],
+      )
+    end
+
+    # Used to ask server to generate key pair under api V1
+    #
+    # @params [Optional True/False] Should be true or false - default is false.
+    # @return [True/False] The current value
+    def create_key(arg = nil)
+      set_or_return(
+        :create_key,
+        arg,
+        :kind_of => [ TrueClass, FalseClass ],
+      )
+    end
+
+    # The hash representation of the object. Includes the name and public_key.
+    # Private key is included if available.
+    #
+    # @return [Hash]
+    def to_hash
+      result = {
+        "name" => @name,
+        "validator" => @validator,
+        "admin" => @admin,
+        "chef_type" => "client",
+      }
+      result["private_key"] = @private_key unless @private_key.nil?
+      result["public_key"] = @public_key unless @public_key.nil?
+      result["create_key"] = @create_key unless @create_key.nil?
+      result
+    end
+
+    # The JSON representation of the object.
+    #
+    # @return [String] the JSON string.
+    def to_json(*a)
+      Chef::JSONCompat.to_json(to_hash, *a)
+    end
+
+    def self.from_hash(o)
+      client = Chef::ApiClientV1.new
+      client.name(o["name"] || o["clientname"])
+      client.admin(o["admin"])
+      client.validator(o["validator"])
+      client.private_key(o["private_key"]) if o.key?("private_key")
+      client.public_key(o["public_key"]) if o.key?("public_key")
+      client.create_key(o["create_key"]) if o.key?("create_key")
+      client
+    end
+
+    def self.from_json(j)
+      Chef::ApiClientV1.from_hash(Chef::JSONCompat.from_json(j))
+    end
+
+    def self.reregister(name)
+      api_client = Chef::ApiClientV1.load(name)
+      api_client.reregister
+    end
+
+    def self.list(inflate = false)
+      if inflate
+        response = Hash.new
+        Chef::Search::Query.new.search(:client) do |n|
+          n = self.from_hash(n) if n.instance_of?(Hash)
+          response[n.name] = n
+        end
+        response
+      else
+        http_api.get("clients")
+      end
+    end
+
+    # Load a client by name via the API
+    def self.load(name)
+      response = http_api.get("clients/#{name}")
+      Chef::ApiClientV1.from_hash(response)
+    end
+
+    # Remove this client via the REST API
+    def destroy
+      chef_rest_v1.delete("clients/#{@name}")
+    end
+
+    # Save this client via the REST API, returns a hash including the private key
+    def save
+      begin
+        update
+      rescue Net::HTTPServerException => e
+        # If that fails, go ahead and try and update it
+        if e.response.code == "404"
+          create
+        else
+          raise e
+        end
+      end
+    end
+
+    def reregister
+      # Try API V0 and if it fails due to V0 not being supported, raise the proper error message.
+      # reregister only supported in API V0 or lesser.
+      reregistered_self = chef_rest_v0.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true })
+      if reregistered_self.respond_to?(:[])
+        private_key(reregistered_self["private_key"])
+      else
+        private_key(reregistered_self.private_key)
+      end
+      self
+    rescue Net::HTTPServerException => e
+      # if there was a 406 related to versioning, give error explaining that
+      # only API version 0 is supported for reregister command
+      if e.response.code == "406" && e.response["x-ops-server-api-version"]
+        version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"])
+        min_version = version_header["min_version"]
+        max_version = version_header["max_version"]
+        error_msg = reregister_only_v0_supported_error_msg(max_version, min_version)
+        raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg)
+      else
+        raise e
+      end
+    end
+
+    # Updates the client via the REST API
+    def update
+      # NOTE: API V1 dropped support for updating client keys via update (aka PUT),
+      # but this code never supported key updating in the first place. Since
+      # it was never implemented, we will simply ignore that functionality
+      # as it is being deprecated.
+      # Delete this comment after V0 support is dropped.
+      payload = { :name => name }
+      payload[:validator] = validator unless validator.nil?
+
+      # DEPRECATION
+      # This field is ignored in API V1, but left for backwards-compat,
+      # can remove after API V0 is no longer supported.
+      payload[:admin] = admin unless admin.nil?
+
+      begin
+        new_client = chef_rest_v1.put("clients/#{name}", payload)
+      rescue Net::HTTPServerException => e
+        # rescue API V0 if 406 and the server supports V0
+        supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
+        raise e unless supported_versions && supported_versions.include?(0)
+        new_client = chef_rest_v0.put("clients/#{name}", payload)
+      end
+
+      Chef::ApiClientV1.from_hash(new_client)
+    end
+
+    # Create the client via the REST API
+    def create
+      payload = {
+        :name => name,
+        :validator => validator,
+        # this field is ignored in API V1, but left for backwards-compat,
+        # can remove after OSC 11 support is finished?
+        :admin => admin,
+      }
+      begin
+        # try API V1
+        raise Chef::Exceptions::InvalidClientAttribute, "You cannot set both public_key and create_key for create." if !create_key.nil? && !public_key.nil?
+
+        payload[:public_key] = public_key unless public_key.nil?
+        payload[:create_key] = create_key unless create_key.nil?
+
+        new_client = chef_rest_v1.post("clients", payload)
+
+        # get the private_key out of the chef_key hash if it exists
+        if new_client["chef_key"]
+          if new_client["chef_key"]["private_key"]
+            new_client["private_key"] = new_client["chef_key"]["private_key"]
+          end
+          new_client["public_key"] = new_client["chef_key"]["public_key"]
+          new_client.delete("chef_key")
+        end
+
+      rescue Net::HTTPServerException => e
+        # rescue API V0 if 406 and the server supports V0
+        supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
+        raise e unless supported_versions && supported_versions.include?(0)
+
+        # under API V0, a key pair will always be created unless public_key is
+        # passed on initial POST
+        payload[:public_key] = public_key unless public_key.nil?
+
+        new_client = chef_rest_v0.post("clients", payload)
+      end
+      Chef::ApiClientV1.from_hash(self.to_hash.merge(new_client))
+    end
+
+    # As a string
+    def to_s
+      "client[#{@name}]"
+    end
+
+  end
+end
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 297e46e..c2adcda 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -1,7 +1,7 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Mark Mzyk (mmzyk at opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Mark Mzyk (mmzyk at chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'pp'
-require 'uri'
-require 'socket'
-require 'chef/config'
-require 'chef/config_fetcher'
-require 'chef/exceptions'
-require 'chef/local_mode'
-require 'chef/log'
-require 'chef/platform'
-require 'mixlib/cli'
-require 'tmpdir'
-require 'rbconfig'
+require "pp"
+require "socket"
+require "chef/config"
+require "chef/config_fetcher"
+require "chef/exceptions"
+require "chef/local_mode"
+require "chef/log"
+require "chef/platform"
+require "mixlib/cli"
+require "tmpdir"
+require "rbconfig"
 
 class Chef
   class Application
@@ -47,7 +46,6 @@ class Chef
     def reconfigure
       configure_chef
       configure_logging
-      configure_proxy_environment_variables
       configure_encoding
       emit_warnings
     end
@@ -85,15 +83,23 @@ class Chef
     def configure_chef
       parse_options
       load_config_file
+      Chef::Config.export_proxies
+      Chef::Config.init_openssl
     end
 
     # Parse the config file
     def load_config_file
       config_fetcher = Chef::ConfigFetcher.new(config[:config_file])
+
+      # Some config settings are derived relative to the config file path; if
+      # given as a relative path, this is computed relative to cwd, but
+      # chef-client will later chdir to root, so we need to get the absolute path
+      # here.
+      config[:config_file] = config_fetcher.expanded_path
+
       if config[:config_file].nil?
         Chef::Log.warn("No config file found or specified on command line, using command line options.")
       elsif config_fetcher.config_missing?
-        pp config_missing: true
         Chef::Log.warn("*****************************************")
         Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
         Chef::Log.warn("*****************************************")
@@ -148,7 +154,7 @@ class Chef
     def configure_stdout_logger
       stdout_logger = MonoLogger.new(STDOUT)
       stdout_logger.formatter = Chef::Log.logger.formatter
-      Chef::Log.loggers <<  stdout_logger
+      Chef::Log.loggers << stdout_logger
     end
 
     # Based on config and whether or not STDOUT is a tty, should we setup a
@@ -181,14 +187,6 @@ class Chef
       end
     end
 
-    # Configure and set any proxy environment variables according to the config.
-    def configure_proxy_environment_variables
-      configure_http_proxy
-      configure_https_proxy
-      configure_ftp_proxy
-      configure_no_proxy
-    end
-
     # Sets the default external encoding to UTF-8 (users can change this, but they shouldn't)
     def configure_encoding
       Encoding.default_external = Chef::Config[:ruby_encoding]
@@ -196,18 +194,18 @@ class Chef
 
     # Called prior to starting the application, by the run method
     def setup_application
-      raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application"
+      raise Chef::Exceptions::Application, "#{self}: you must override setup_application"
     end
 
     # Actually run the application
     def run_application
-      raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application"
+      raise Chef::Exceptions::Application, "#{self}: you must override run_application"
     end
 
     # Initializes Chef::Client instance and runs it
     def run_chef_client(specific_recipes = [])
       unless specific_recipes.respond_to?(:size)
-        raise ArgumentError, 'received non-Array like specific_recipes argument'
+        raise ArgumentError, "received non-Array like specific_recipes argument"
       end
 
       Chef::LocalMode.with_server_connectivity do
@@ -217,7 +215,7 @@ class Chef
           @chef_client_json,
           override_runlist: override_runlist,
           specific_recipes: specific_recipes,
-          runlist: config[:runlist]
+          runlist: config[:runlist],
         )
         @chef_client_json = nil
 
@@ -234,6 +232,7 @@ class Chef
     end
 
     private
+
     def can_fork?
       # win32-process gem exposes some form of :fork for Process
       # class. So we are separately ensuring that the platform we're
@@ -245,7 +244,7 @@ class Chef
     # signal to finish the converge and exists.
     def run_with_graceful_exit_option
       # Override the TERM signal.
-      trap('TERM') do
+      trap("TERM") do
         Chef::Log.debug("SIGTERM received during converge," +
           " finishing converge to exit normally (send SIGINT to terminate immediately)")
       end
@@ -259,7 +258,7 @@ class Chef
       pid = fork do
         # Want to allow forked processes to finish converging when
         # TERM singal is received (exit gracefully)
-        trap('TERM') do
+        trap("TERM") do
           Chef::Log.debug("SIGTERM received during converge," +
             " finishing converge to exit normally (send SIGINT to terminate immediately)")
         end
@@ -299,83 +298,10 @@ class Chef
     rescue Exception => error
       Chef::Log.fatal("Configuration error #{error.class}: #{error.message}")
       filtered_trace = error.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
-      filtered_trace.each {|line| Chef::Log.fatal("  " + line )}
+      filtered_trace.each { |line| Chef::Log.fatal("  " + line ) }
       Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", 2)
     end
 
-    # Set ENV['http_proxy']
-    def configure_http_proxy
-      if http_proxy = Chef::Config[:http_proxy]
-        http_proxy_string = configure_proxy("http", http_proxy,
-          Chef::Config[:http_proxy_user], Chef::Config[:http_proxy_pass])
-        env['http_proxy'] = http_proxy_string unless env['http_proxy']
-        env['HTTP_PROXY'] = http_proxy_string unless env['HTTP_PROXY']
-      end
-    end
-
-    # Set ENV['https_proxy']
-    def configure_https_proxy
-      if https_proxy = Chef::Config[:https_proxy]
-        https_proxy_string = configure_proxy("https", https_proxy,
-          Chef::Config[:https_proxy_user], Chef::Config[:https_proxy_pass])
-        env['https_proxy'] = https_proxy_string unless env['https_proxy']
-        env['HTTPS_PROXY'] = https_proxy_string unless env['HTTPS_PROXY']
-      end
-    end
-
-    # Set ENV['ftp_proxy']
-    def configure_ftp_proxy
-      if ftp_proxy = Chef::Config[:ftp_proxy]
-        ftp_proxy_string = configure_proxy("ftp", ftp_proxy,
-          Chef::Config[:ftp_proxy_user], Chef::Config[:ftp_proxy_pass])
-        env['ftp_proxy'] = ftp_proxy_string unless env['ftp_proxy']
-        env['FTP_PROXY'] = ftp_proxy_string unless env['FTP_PROXY']
-      end
-    end
-
-    # Set ENV['no_proxy']
-    def configure_no_proxy
-      if Chef::Config[:no_proxy]
-        env['no_proxy'] = Chef::Config[:no_proxy] unless env['no_proxy']
-        env['NO_PROXY'] = Chef::Config[:no_proxy] unless env['NO_PROXY']
-      end
-    end
-
-    # Builds a proxy uri. Examples:
-    #   http://username:password@hostname:port
-    #   https://username@hostname:port
-    #   ftp://hostname:port
-    # when
-    #   scheme = "http", "https", or "ftp"
-    #   hostport = hostname:port
-    #   user = username
-    #   pass = password
-    def configure_proxy(scheme, path, user, pass)
-      begin
-        path = "#{scheme}://#{path}" unless path.include?('://')
-        # URI.split returns the following parts:
-        # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
-        parts = URI.split(URI.encode(path))
-        # URI::Generic.build requires an integer for the port, but URI::split gives
-        # returns a string for the port.
-        parts[3] = parts[3].to_i if parts[3]
-        if user
-          userinfo = URI.encode(URI.encode(user), '@:')
-          if pass
-            userinfo << ":#{URI.encode(URI.encode(pass), '@:')}"
-          end
-          parts[1] = userinfo
-        end
-
-        return URI::Generic.build(parts).to_s
-      rescue URI::Error => e
-        # URI::Error messages generally include the offending string. Including a message
-        # for which proxy config item has the issue should help deduce the issue when
-        # the URI::Error message is vague.
-        raise Chef::Exceptions::BadProxyURI, "Cannot configure #{scheme} proxy. Does not comply with URI scheme. #{e.message}"
-      end
-    end
-
     # This is a hook for testing
     def env
       ENV
@@ -383,18 +309,19 @@ class Chef
 
     def emit_warnings
       if Chef::Config[:chef_gem_compile_time]
-        Chef::Log.deprecation "setting chef_gem_compile_time to true is deprecated"
+        Chef.log_deprecation "setting chef_gem_compile_time to true is deprecated"
       end
     end
 
     class << self
       def debug_stacktrace(e)
         message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
-        chef_stacktrace_out = "Generated at #{Time.now.to_s}\n"
+        chef_stacktrace_out = "Generated at #{Time.now}\n"
         chef_stacktrace_out += message
 
         Chef::FileCache.store("chef-stacktrace.out", chef_stacktrace_out)
         Chef::Log.fatal("Stacktrace dumped to #{Chef::FileCache.load("chef-stacktrace.out", false)}")
+        Chef::Log.fatal("Please provide the contents of the stacktrace.out file if you file a bug report")
         Chef::Log.debug(message)
         true
       end
diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb
index e9768b2..38b00f2 100644
--- a/lib/chef/application/apply.rb
+++ b/lib/chef/application/apply.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Bryan W. Berry (<bryan.berry at gmail.com>)
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
-# Copyright:: Copyright (c) 2012 Daniel DeLeo
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/log'
-require 'fileutils'
-require 'tempfile'
-require 'chef/providers'
-require 'chef/resources'
+require "chef"
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/log"
+require "fileutils"
+require "tempfile"
+require "chef/providers"
+require "chef/resources"
 
 class Chef::Application::Apply < Chef::Application
 
-  banner "Usage: chef-apply [RECIPE_FILE] [-e RECIPE_TEXT] [-s]"
+  banner "Usage: chef-apply [RECIPE_FILE | -e RECIPE_TEXT | -s] [OPTIONS]"
 
   option :execute,
     :short        => "-e RECIPE_TEXT",
@@ -49,6 +49,24 @@ class Chef::Application::Apply < Chef::Application
     :description => "Load attributes from a JSON file or URL",
     :proc => nil
 
+  option :force_logger,
+    :long         => "--force-logger",
+    :description  => "Use logger output instead of formatter output",
+    :boolean      => true,
+    :default      => false
+
+  option :force_formatter,
+    :long         => "--force-formatter",
+    :description  => "Use formatter output instead of logger output",
+    :boolean      => true,
+    :default      => false
+
+  option :formatter,
+    :short        => "-F FORMATTER",
+    :long         => "--format FORMATTER",
+    :description  => "output format to use",
+    :proc         => lambda { |format| Chef::Config.add_formatter(format) }
+
   option :log_level,
     :short        => "-l LEVEL",
     :long         => "--log_level LEVEL",
@@ -64,25 +82,30 @@ class Chef::Application::Apply < Chef::Application
     :show_options => true,
     :exit         => 0
 
-
   option :version,
     :short        => "-v",
     :long         => "--version",
     :description  => "Show chef version",
     :boolean      => true,
-    :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+    :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
     :exit         => 0
 
   option :why_run,
-    :short        => '-W',
-    :long         => '--why-run',
-    :description  => 'Enable whyrun mode',
+    :short        => "-W",
+    :long         => "--why-run",
+    :description  => "Enable whyrun mode",
     :boolean      => true
 
+  option :profile_ruby,
+    :long         => "--[no-]profile-ruby",
+    :description  => "Dump complete Ruby call graph stack of entire Chef run (expert only)",
+    :boolean      => true,
+    :default      => false
+
   option :color,
-    :long         => '--[no-]color',
+    :long         => "--[no-]color",
     :boolean      => true,
-    :default      => !Chef::Platform.windows?,
+    :default      => true,
     :description  => "Use colored output, defaults to enabled"
 
   option :minimal_ohai,
@@ -100,7 +123,8 @@ class Chef::Application::Apply < Chef::Application
     parse_options
     Chef::Config.merge!(config)
     configure_logging
-    configure_proxy_environment_variables
+    Chef::Config.export_proxies
+    Chef::Config.init_openssl
     parse_json
   end
 
@@ -143,7 +167,7 @@ class Chef::Application::Apply < Chef::Application
   # write recipe to temp file, so in case of error,
   # user gets error w/ context
   def temp_recipe_file
-    @recipe_fh = Tempfile.open('recipe-temporary-file')
+    @recipe_fh = Tempfile.open("recipe-temporary-file")
     @recipe_fh.write(@recipe_text)
     @recipe_fh.rewind
     @recipe_filename = @recipe_fh.path
@@ -162,9 +186,9 @@ class Chef::Application::Apply < Chef::Application
         Chef::Application.exit! "No recipe file provided", 1
       end
       @recipe_filename = ARGV[0]
-      @recipe_text, at recipe_fh = read_recipe_file @recipe_filename
+      @recipe_text, @recipe_fh = read_recipe_file @recipe_filename
     end
-    recipe,run_context = get_recipe_and_run_context
+    recipe, run_context = get_recipe_and_run_context
     recipe.instance_eval(@recipe_text, @recipe_filename, 1)
     runner = Chef::Runner.new(run_context)
     begin
@@ -172,6 +196,7 @@ class Chef::Application::Apply < Chef::Application
     ensure
       @recipe_fh.close
     end
+    Chef::Platform::Rebooter.reboot_if_needed!(runner)
   end
 
   def run_application
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index a5faee9..1a7d8d0 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -1,8 +1,8 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Mark Mzyk (mmzyk at opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Mark Mzyk (mmzyk at chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,14 +17,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/daemon'
-require 'chef/log'
-require 'chef/config_fetcher'
-require 'chef/handler/error_report'
-require 'chef/workstation_config_loader'
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/daemon"
+require "chef/log"
+require "chef/config_fetcher"
+require "chef/handler/error_report"
+require "chef/workstation_config_loader"
+require "chef/mixin/shell_out"
 
 class Chef::Application::Client < Chef::Application
   include Chef::Mixin::ShellOut
@@ -55,11 +56,17 @@ class Chef::Application::Client < Chef::Application
     :boolean      => true,
     :default      => false
 
+  option :profile_ruby,
+    :long         => "--[no-]profile-ruby",
+    :description  => "Dump complete Ruby call graph stack of entire Chef run (expert only)",
+    :boolean      => true,
+    :default      => false
+
   option :color,
-    :long         => '--[no-]color',
+    :long         => "--[no-]color",
     :boolean      => true,
-    :default      => !Chef::Platform.windows?,
-    :description  => "Use colored output, defaults to false on Windows, true otherwise"
+    :default      => true,
+    :description  => "Use colored output, defaults to enabled"
 
   option :log_level,
     :short        => "-l LEVEL",
@@ -160,26 +167,31 @@ class Chef::Application::Client < Chef::Application
     :description  => "Set the client key file location",
     :proc         => nil
 
+  option :named_run_list,
+    :short        => "-n NAMED_RUN_LIST",
+    :long         => "--named-run-list NAMED_RUN_LIST",
+    :description  => "Use a policyfile's named run list instead of the default run list"
+
   option :environment,
-    :short        => '-E ENVIRONMENT',
-    :long         => '--environment ENVIRONMENT',
-    :description  => 'Set the Chef Environment on the node'
+    :short        => "-E ENVIRONMENT",
+    :long         => "--environment ENVIRONMENT",
+    :description  => "Set the Chef Environment on the node"
 
   option :version,
     :short        => "-v",
     :long         => "--version",
     :description  => "Show chef version",
     :boolean      => true,
-    :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+    :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
     :exit         => 0
 
   option :override_runlist,
     :short        => "-o RunlistItem,RunlistItem...",
     :long         => "--override-runlist RunlistItem,RunlistItem...",
     :description  => "Replace current run list with specified items for a single run",
-    :proc         => lambda{|items|
-      items = items.split(',')
-      items.compact.map{|item|
+    :proc         => lambda {|items|
+      items = items.split(",")
+      items.compact.map {|item|
         Chef::RunList::RunListItem.new(item)
       }
     }
@@ -188,16 +200,16 @@ class Chef::Application::Client < Chef::Application
     :short        => "-r RunlistItem,RunlistItem...",
     :long         => "--runlist RunlistItem,RunlistItem...",
     :description  => "Permanently replace current run list with specified items",
-    :proc         => lambda{|items|
-      items = items.split(',')
-      items.compact.map{|item|
+    :proc         => lambda {|items|
+      items = items.split(",")
+      items.compact.map {|item|
         Chef::RunList::RunListItem.new(item)
       }
     }
   option :why_run,
-    :short        => '-W',
-    :long         => '--why-run',
-    :description  => 'Enable whyrun mode',
+    :short        => "-W",
+    :long         => "--why-run",
+    :description  => "Enable whyrun mode",
     :boolean      => true
 
   option :client_fork,
@@ -263,6 +275,16 @@ class Chef::Application::Client < Chef::Application
     :description    => "Whether a local mode (-z) server binds to a port",
     :boolean        => true
 
+  option :fips,
+    :long         => "--fips",
+    :description  => "Enable fips mode",
+    :boolean      => true
+
+  option :delete_entire_chef_repo,
+    :long           => "--delete-entire-chef-repo",
+    :description    => "DANGEROUS: does what it says, only useful with --recipe-url",
+    :boolean        => true
+
   IMMEDIATE_RUN_SIGNAL = "1".freeze
 
   attr_reader :chef_client_json
@@ -272,26 +294,40 @@ class Chef::Application::Client < Chef::Application
   def reconfigure
     super
 
-    raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || '' ), (Chef::Config[:lockfile] || '')
+    raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || "" ), (Chef::Config[:lockfile] || "")
 
     set_specific_recipes
 
+    Chef::Config[:fips] = config[:fips] if config.has_key? :fips
+
     Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url
 
     Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
+
+    if Chef::Config.has_key?(:chef_repo_path) && Chef::Config.chef_repo_path.nil?
+      Chef::Config.delete(:chef_repo_path)
+      Chef::Log.warn "chef_repo_path was set in a config file but was empty. Assuming #{Chef::Config.chef_repo_path}"
+    end
+
     if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
       Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
     end
 
-    if !Chef::Config.local_mode && Chef::Config.has_key?(:recipe_url)
-      Chef::Application.fatal!("chef-client recipe-url can be used only in local-mode", 1)
-    elsif Chef::Config.local_mode && Chef::Config.has_key?(:recipe_url)
-      Chef::Log.debug "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
-      FileUtils.mkdir_p(Chef::Config.chef_repo_path)
-      tarball_path = File.join(Chef::Config.chef_repo_path, 'recipes.tgz')
-      fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
-      result = shell_out!("tar zxvf #{tarball_path} -C #{Chef::Config.chef_repo_path}")
-      Chef::Log.debug "#{result.stdout}"
+    if Chef::Config[:recipe_url]
+      if !Chef::Config.local_mode
+        Chef::Application.fatal!("chef-client recipe-url can be used only in local-mode", 1)
+      else
+        if Chef::Config[:delete_entire_chef_repo]
+          Chef::Log.debug "Cleanup path #{Chef::Config.chef_repo_path} before extract recipes into it"
+          FileUtils.rm_rf(recipes_path, :secure => true)
+        end
+        Chef::Log.debug "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
+        FileUtils.mkdir_p(Chef::Config.chef_repo_path)
+        tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz")
+        fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
+        result = shell_out!("tar zxvf #{tarball_path} -C #{Chef::Config.chef_repo_path}")
+        Chef::Log.debug "#{result.stdout}"
+      end
     end
 
     Chef::Config.chef_zero.host = config[:chef_zero_host] if config[:chef_zero_host]
@@ -320,12 +356,6 @@ class Chef::Application::Client < Chef::Application
       unless expected_modes.include?(mode)
         Chef::Application.fatal!(unrecognized_audit_mode(mode))
       end
-
-      unless mode == :disabled
-        # This should be removed when audit-mode is enabled by default/no longer
-        # an experimental feature.
-        Chef::Log.warn(audit_mode_experimental_message)
-      end
     end
   end
 
@@ -384,6 +414,7 @@ class Chef::Application::Client < Chef::Application
   end
 
   private
+
   def interval_run_chef_client
     if Chef::Config[:daemonize]
       Chef::Daemon.daemonize("chef-client")
@@ -443,36 +474,25 @@ class Chef::Application::Client < Chef::Application
 
   def unforked_interval_error_message
     "Unforked chef-client interval runs are disabled in Chef 12." +
-    "\nConfiguration settings:" +
-    "#{"\n  interval  = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
-    "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
+      "\nConfiguration settings:" +
+      "#{"\n  interval  = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
+      "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
   end
 
-  def audit_mode_settings_explaination
-    "\n* To enable audit mode after converge, use command line option `--audit-mode enabled` or set `:audit_mode = :enabled` in your config file." +
-    "\n* To disable audit mode, use command line option `--audit-mode disabled` or set `:audit_mode = :disabled` in your config file." +
-    "\n* To only run audit mode, use command line option `--audit-mode audit-only` or set `:audit_mode = :audit_only` in your config file." +
-    "\nAudit mode is disabled by default."
+  def audit_mode_settings_explanation
+    "\n* To enable audit mode after converge, use command line option `--audit-mode enabled` or set `audit_mode :enabled` in your config file." +
+      "\n* To disable audit mode, use command line option `--audit-mode disabled` or set `audit_mode :disabled` in your config file." +
+      "\n* To only run audit mode, use command line option `--audit-mode audit-only` or set `audit_mode :audit_only` in your config file." +
+      "\nAudit mode is disabled by default."
   end
 
   def unrecognized_audit_mode(mode)
-    "Unrecognized setting #{mode} for audit mode." + audit_mode_settings_explaination
-  end
-
-  def audit_mode_experimental_message
-    msg = if Chef::Config[:audit_mode] == :audit_only
-      "Chef-client has been configured to skip converge and only audit."
-    else
-      "Chef-client has been configured to audit after it converges."
-    end
-    msg += " Audit mode is an experimental feature currently under development. API changes may occur. Use at your own risk."
-    msg += audit_mode_settings_explaination
-    return msg
+    "Unrecognized setting #{mode} for audit mode." + audit_mode_settings_explanation
   end
 
   def fetch_recipe_tarball(url, path)
     Chef::Log.debug("Download recipes tarball from #{url} to #{path}")
-    File.open(path, 'wb') do |f|
+    File.open(path, "wb") do |f|
       open(url) do |r|
         f.write(r.read)
       end
diff --git a/lib/chef/application/knife.rb b/lib/chef/application/knife.rb
index af5216a..849a011 100644
--- a/lib/chef/application/knife.rb
+++ b/lib/chef/application/knife.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/knife'
-require 'chef/application'
-require 'mixlib/log'
-require 'ohai/config'
-require 'chef/monkey_patches/net_http.rb'
+require "chef/knife"
+require "chef/application"
+require "mixlib/log"
+require "ohai/config"
+require "chef/monkey_patches/net_http.rb"
 
 class Chef::Application::Knife < Chef::Application
 
@@ -35,17 +35,17 @@ class Chef::Application::Knife < Chef::Application
 
   verbosity_level = 0
   option :verbosity,
-    :short => '-V',
-    :long  => '--verbose',
+    :short => "-V",
+    :long  => "--verbose",
     :description => "More verbose output. Use twice for max verbosity",
-    :proc  => Proc.new { verbosity_level += 1},
+    :proc  => Proc.new { verbosity_level += 1 },
     :default => 0
 
   option :color,
-    :long         => '--[no-]color',
+    :long         => "--[no-]color",
     :boolean      => true,
-    :default      => !Chef::Platform.windows?,
-    :description  => "Use colored output, defaults to false on Windows, true otherwise"
+    :default      => true,
+    :description  => "Use colored output, defaults to enabled"
 
   option :environment,
     :short        => "-E ENVIRONMENT",
@@ -56,7 +56,7 @@ class Chef::Application::Knife < Chef::Application
     :short        => "-e EDITOR",
     :long         => "--editor EDITOR",
     :description  => "Set the editor to use for interactive commands",
-    :default      => ENV['EDITOR']
+    :default      => ENV["EDITOR"]
 
   option :disable_editing,
     :short        => "-d",
@@ -131,9 +131,15 @@ class Chef::Application::Knife < Chef::Application
     :long         => "--version",
     :description  => "Show chef version",
     :boolean      => true,
-    :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+    :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
     :exit         => 0
 
+  option :fips,
+    :long         => "--[no-]fips",
+    :description  => "Enable fips mode",
+    :boolean      => true,
+    :default      => nil
+
   # Run knife
   def run
     Mixlib::Log::Formatter.show_time = false
@@ -162,7 +168,7 @@ class Chef::Application::Knife < Chef::Application
       print_help_and_exit(1, NO_COMMAND_GIVEN)
     elsif no_subcommand_given?
       if (want_help? || want_version?)
-        print_help_and_exit
+        print_help_and_exit(0)
       else
         print_help_and_exit(2, NO_COMMAND_GIVEN)
       end
@@ -185,7 +191,7 @@ class Chef::Application::Knife < Chef::Application
     ARGV[0] =~ /^(--version|-v)$/
   end
 
-  def print_help_and_exit(exitcode=1, fatal_message=nil)
+  def print_help_and_exit(exitcode = 1, fatal_message = nil)
     Chef::Log.error(fatal_message) if fatal_message
 
     begin
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index dd09d65..3917a08 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -1,7 +1,7 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Mark Mzyk (mmzyk at opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Mark Mzyk (mmzyk at chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/daemon'
-require 'chef/log'
-require 'chef/rest'
-require 'chef/config_fetcher'
-require 'fileutils'
+require "chef"
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/daemon"
+require "chef/log"
+require "chef/rest"
+require "chef/config_fetcher"
+require "fileutils"
+require "chef/mixin/shell_out"
+require "pathname"
 
 class Chef::Application::Solo < Chef::Application
+  include Chef::Mixin::ShellOut
 
   option :config_file,
     :short => "-c CONFIG",
     :long  => "--config CONFIG",
-    :default => Chef::Config.platform_specific_path('/etc/chef/solo.rb'),
+    :default => Chef::Config.platform_specific_path("/etc/chef/solo.rb"),
     :description => "The configuration file to use"
 
   option :formatter,
@@ -52,8 +55,14 @@ class Chef::Application::Solo < Chef::Application
     :boolean      => true,
     :default      => false
 
+  option :profile_ruby,
+    :long         => "--[no-]profile-ruby",
+    :description  => "Dump complete Ruby call graph stack of entire Chef run (expert only)",
+    :boolean      => true,
+    :default      => false
+
   option :color,
-    :long         => '--[no-]color',
+    :long         => "--[no-]color",
     :boolean      => true,
     :default      => !Chef::Platform.windows?,
     :description  => "Use colored output, defaults to enabled"
@@ -129,26 +138,25 @@ class Chef::Application::Solo < Chef::Application
     :proc => lambda { |s| s.to_i }
 
   option :recipe_url,
-      :short => "-r RECIPE_URL",
-      :long => "--recipe-url RECIPE_URL",
-      :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache.",
-      :proc => nil
+    :short        => "-r RECIPE_URL",
+    :long         => "--recipe-url RECIPE_URL",
+    :description  => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache."
 
   option :version,
     :short        => "-v",
     :long         => "--version",
     :description  => "Show chef version",
     :boolean      => true,
-    :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+    :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
     :exit         => 0
 
   option :override_runlist,
     :short        => "-o RunlistItem,RunlistItem...",
     :long         => "--override-runlist RunlistItem,RunlistItem...",
     :description  => "Replace current run list with specified items",
-    :proc         => lambda{|items|
-      items = items.split(',')
-      items.compact.map{|item|
+    :proc         => lambda {|items|
+      items = items.split(",")
+      items.compact.map {|item|
         Chef::RunList::RunListItem.new(item)
       }
     }
@@ -160,20 +168,20 @@ class Chef::Application::Solo < Chef::Application
     :boolean      => true
 
   option :why_run,
-    :short        => '-W',
-    :long         => '--why-run',
-    :description  => 'Enable whyrun mode',
+    :short        => "-W",
+    :long         => "--why-run",
+    :description  => "Enable whyrun mode",
     :boolean      => true
 
   option :ez,
-    :long         => '--ez',
-    :description  => 'A memorial for Ezra Zygmuntowicz',
+    :long         => "--ez",
+    :description  => "A memorial for Ezra Zygmuntowicz",
     :boolean      => true
 
   option :environment,
-    :short        => '-E ENVIRONMENT',
-    :long         => '--environment ENVIRONMENT',
-    :description  => 'Set the Chef Environment on the node'
+    :short        => "-E ENVIRONMENT",
+    :long         => "--environment ENVIRONMENT",
+    :description  => "Set the Chef Environment on the node"
 
   option :run_lock_timeout,
     :long         => "--run-lock-timeout SECONDS",
@@ -185,6 +193,11 @@ class Chef::Application::Solo < Chef::Application
     :description    => "Only run the bare minimum ohai plugins chef needs to function",
     :boolean        => true
 
+  option :delete_entire_chef_repo,
+    :long           => "--delete-entire-chef-repo",
+    :description    => "DANGEROUS: does what it says, only useful with --recipe-url",
+    :boolean        => true
+
   attr_reader :chef_client_json
 
   def initialize
@@ -204,17 +217,22 @@ class Chef::Application::Solo < Chef::Application
 
     Chef::Application.fatal!(unforked_interval_error_message) if !Chef::Config[:client_fork] && Chef::Config[:interval]
 
+    Chef::Log.deprecation("-r MUST be changed to --recipe-url, the -r option will be changed in Chef 13.0") if ARGV.include?("-r")
+
     if Chef::Config[:recipe_url]
-      cookbooks_path = Array(Chef::Config[:cookbook_path]).detect{|e| e =~ /\/cookbooks\/*$/ }
-      recipes_path = File.expand_path(File.join(cookbooks_path, '..'))
+      cookbooks_path = Array(Chef::Config[:cookbook_path]).detect { |e| Pathname.new(e).cleanpath.to_s =~ /\/cookbooks\/*$/ }
+      recipes_path = File.expand_path(File.join(cookbooks_path, ".."))
 
-      Chef::Log.debug "Cleanup path #{recipes_path} before extract recipes into it"
-      FileUtils.rm_rf(recipes_path, :secure => true)
+      if Chef::Config[:delete_entire_chef_repo]
+        Chef::Log.debug "Cleanup path #{recipes_path} before extract recipes into it"
+        FileUtils.rm_rf(recipes_path, :secure => true)
+      end
       Chef::Log.debug "Creating path #{recipes_path} to extract recipes into"
       FileUtils.mkdir_p(recipes_path)
-      tarball_path = File.join(recipes_path, 'recipes.tgz')
+      tarball_path = File.join(recipes_path, "recipes.tgz")
       fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
-      Chef::Mixin::Command.run_command(:command => "tar zxvf #{tarball_path} -C #{recipes_path}")
+      result = shell_out!("tar zxvf #{tarball_path} -C #{recipes_path}")
+      Chef::Log.debug "#{result.stdout}"
     end
 
     # json_attribs shuld be fetched after recipe_url tarball is unpacked.
@@ -248,7 +266,6 @@ class Chef::Application::Solo < Chef::Application
     end
   end
 
-
   private
 
   def for_ezra
@@ -297,7 +314,7 @@ EOH
 
   def fetch_recipe_tarball(url, path)
     Chef::Log.debug("Download recipes tarball from #{url} to #{path}")
-    File.open(path, 'wb') do |f|
+    File.open(path, "wb") do |f|
       open(url) do |r|
         f.write(r.read)
       end
@@ -306,8 +323,8 @@ EOH
 
   def unforked_interval_error_message
     "Unforked chef-client interval runs are disabled in Chef 12." +
-    "\nConfiguration settings:" +
-    "#{"\n  interval  = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
-    "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
+      "\nConfiguration settings:" +
+      "#{"\n  interval  = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]}" +
+      "\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
   end
 end
diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb
index b42a01c..b955dd3 100644
--- a/lib/chef/application/windows_service.rb
+++ b/lib/chef/application/windows_service.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Christopher Maier (<maier at lambda.local>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/monologger'
-require 'chef/application'
-require 'chef/client'
-require 'chef/config'
-require 'chef/handler/error_report'
-require 'chef/log'
-require 'chef/rest'
-require 'mixlib/cli'
-require 'socket'
-require 'uri'
-require 'win32/daemon'
-require 'chef/mixin/shell_out'
+require "chef"
+require "chef/monologger"
+require "chef/application"
+require "chef/client"
+require "chef/config"
+require "chef/handler/error_report"
+require "chef/log"
+require "chef/http"
+require "mixlib/cli"
+require "socket"
+require "uri"
+require "win32/daemon"
+require "chef/mixin/shell_out"
 
 class Chef
   class Application
@@ -45,8 +45,7 @@ class Chef
       option :log_location,
         :short        => "-L LOGLOCATION",
         :long         => "--logfile LOGLOCATION",
-        :description  => "Set the log file location",
-        :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+        :description  => "Set the log file location"
 
       option :splay,
         :short        => "-s SECONDS",
@@ -60,6 +59,8 @@ class Chef
         :description  => "Set the number of seconds to wait between chef-client runs",
         :proc         => lambda { |s| s.to_i }
 
+      DEFAULT_LOG_LOCATION ||= "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+
       def service_init
         @service_action_mutex = Mutex.new
         @service_signal = ConditionVariable.new
@@ -186,16 +187,25 @@ class Chef
           Chef::Log.info "Starting chef-client in a new process"
           # Pass config params to the new process
           config_params = " --no-fork"
-          config_params += " -c #{Chef::Config[:config_file]}" unless  Chef::Config[:config_file].nil?
-          config_params += " -L #{Chef::Config[:log_location]}" unless Chef::Config[:log_location] == STDOUT
+          config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil?
+          # log_location might be an event logger and if so we cannot pass as a command argument
+          # but shed no tears! If the logger is an event logger, it must have been configured
+          # as such in the config file and chef-client will use that when no arg is passed here
+          config_params += " -L #{resolve_log_location}" if resolve_log_location.is_a?(String)
+
           # Starts a new process and waits till the process exits
-          result = shell_out("chef-client #{config_params}", :timeout => Chef::Config[:windows_service][:watchdog_timeout])
+
+          result = shell_out(
+            "chef-client.bat #{config_params}",
+            :timeout => Chef::Config[:windows_service][:watchdog_timeout],
+            :logger => Chef::Log,
+          )
           Chef::Log.debug "#{result.stdout}"
           Chef::Log.debug "#{result.stderr}"
         rescue Mixlib::ShellOut::CommandTimeout => e
           Chef::Log.error "chef-client timed out\n(#{e})"
-          Chef::Log.error(<<-EOF) 
-            Your chef-client run timed out. You can increase the time chef-client is given 
+          Chef::Log.error(<<-EOF)
+            Your chef-client run timed out. You can increase the time chef-client is given
             to complete by configuring windows_service.watchdog_timeout in your client.rb.
           EOF
         rescue Mixlib::ShellOut::ShellCommandFailed => e
@@ -215,12 +225,12 @@ class Chef
 
       # Lifted from Chef::Application, with addition of optional startup parameters
       # for playing nicely with Windows Services
-      def reconfigure(startup_parameters=[])
+      def reconfigure(startup_parameters = [])
         configure_chef startup_parameters
         configure_logging
 
         Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url
-        unless Chef::Config[:exception_handlers].any? {|h| Chef::Handler::ErrorReport === h}
+        unless Chef::Config[:exception_handlers].any? { |h| Chef::Handler::ErrorReport === h }
           Chef::Config[:exception_handlers] << Chef::Handler::ErrorReport.new
         end
 
@@ -231,7 +241,7 @@ class Chef
       # See application.rb for related comments.
 
       def configure_logging
-        Chef::Log.init(MonoLogger.new(Chef::Config[:log_location]))
+        Chef::Log.init(MonoLogger.new(resolve_log_location))
         if want_additional_logger?
           configure_stdout_logger
         end
@@ -241,7 +251,7 @@ class Chef
       def configure_stdout_logger
         stdout_logger = MonoLogger.new(STDOUT)
         stdout_logger.formatter = Chef::Log.logger.formatter
-        Chef::Log.loggers <<  stdout_logger
+        Chef::Log.loggers << stdout_logger
       end
 
       # Based on config and whether or not STDOUT is a tty, should we setup a
@@ -260,6 +270,11 @@ class Chef
         Chef::Config[:log_level] == :auto
       end
 
+      def resolve_log_location
+        # STDOUT is the default log location, but makes no sense for a windows service
+        Chef::Config[:log_location] == STDOUT ? DEFAULT_LOG_LOCATION : Chef::Config[:log_location]
+      end
+
       # if log_level is `:auto`, convert it to :warn (when using output formatter)
       # or :info (no output formatter). See also +using_output_formatter?+
       def resolve_log_level
@@ -293,7 +308,7 @@ class Chef
         begin
           case config[:config_file]
           when /^(http|https):\/\//
-            Chef::REST.new("", nil, nil).fetch(config[:config_file]) { |f| apply_config(f.path) }
+            Chef::HTTP.new("").streaming_request(config[:config_file]) { |f| apply_config(f.path) }
           else
             ::File::open(config[:config_file]) { |f| apply_config(f.path) }
           end
@@ -319,5 +334,5 @@ end
 # To run this file as a service, it must be called as a script from within
 # the Windows Service framework.  In that case, kick off the main loop!
 if __FILE__ == $0
-    Chef::Application::WindowsService.mainloop
+  Chef::Application::WindowsService.mainloop
 end
diff --git a/lib/chef/application/windows_service_manager.rb b/lib/chef/application/windows_service_manager.rb
index de8ed65..74ee395 100644
--- a/lib/chef/application/windows_service_manager.rb
+++ b/lib/chef/application/windows_service_manager.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 #
 
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'win32/service'
+  require "win32/service"
 end
-require 'chef/config'
-require 'mixlib/cli'
+require "chef/config"
+require "mixlib/cli"
 
 class Chef
   class Application
@@ -51,8 +51,7 @@ class Chef
       option :log_location,
         :short        => "-L LOGLOCATION",
         :long         => "--logfile LOGLOCATION",
-        :description  => "Set the log file location for chef-service",
-        :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log"
+        :description  => "Set the log file location for chef-service"
 
       option :help,
         :short        => "-h",
@@ -68,7 +67,7 @@ class Chef
         :long         => "--version",
         :description  => "Show chef version",
         :boolean      => true,
-        :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+        :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
         :exit         => 0
 
       def initialize(service_options)
@@ -78,7 +77,7 @@ class Chef
 
         raise ArgumentError, "Service definition is not provided" if service_options.nil?
 
-        required_options = [:service_name, :service_display_name, :service_name, :service_description, :service_file_path]
+        required_options = [:service_name, :service_display_name, :service_description, :service_file_path]
 
         required_options.each do |req_option|
           if !service_options.has_key?(req_option)
@@ -92,17 +91,19 @@ class Chef
         @service_file_path = service_options[:service_file_path]
         @service_start_name = service_options[:run_as_user]
         @password = service_options[:run_as_password]
+        @delayed_start = service_options[:delayed_start]
+        @dependencies = service_options[:dependencies]
       end
 
       def run(params = ARGV)
         parse_options(params)
 
         case config[:action]
-        when 'install'
+        when "install"
           if service_exists?
             puts "Service #{@service_name} already exists on the system."
           else
-            ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
+            ruby = File.join(RbConfig::CONFIG["bindir"], "ruby")
 
             opts = ""
             opts << " -c #{config[:config_file]}" if config[:config_file]
@@ -113,42 +114,47 @@ class Chef
             cmd = "\"#{ruby}\" \"#{@service_file_path}\" #{opts}".gsub(File::SEPARATOR, File::ALT_SEPARATOR)
 
             ::Win32::Service.new(
-                                 :service_name     => @service_name,
-                                 :display_name     => @service_display_name,
-                                 :description      => @service_description,
-                                 # Prior to 0.8.5, win32-service creates interactive services by default,
-                                 # and we don't want that, so we need to override the service type.
-                                 :service_type     => ::Win32::Service::SERVICE_WIN32_OWN_PROCESS,
-                                 :start_type       => ::Win32::Service::SERVICE_AUTO_START,
-                                 :binary_path_name => cmd,
-                                 :service_start_name => @service_start_name,
-                                 :password => @password,
-                                 )
+              :service_name       => @service_name,
+              :display_name       => @service_display_name,
+              :description        => @service_description,
+              # Prior to 0.8.5, win32-service creates interactive services by default,
+              # and we don't want that, so we need to override the service type.
+              :service_type       => ::Win32::Service::SERVICE_WIN32_OWN_PROCESS,
+              :start_type         => ::Win32::Service::SERVICE_AUTO_START,
+              :binary_path_name   => cmd,
+              :service_start_name => @service_start_name,
+              :password           => @password,
+              :dependencies       => @dependencies,
+            )
+            ::Win32::Service.configure(
+              :service_name     => @service_name,
+              :delayed_start    => @delayed_start,
+            ) unless @delayed_start.nil?
             puts "Service '#{@service_name}' has successfully been installed."
           end
-        when 'status'
+        when "status"
           if !service_exists?
             puts "Service #{@service_name} doesn't exist on the system."
           else
             puts "State of #{@service_name} service is: #{current_state}"
           end
-        when 'start'
+        when "start"
           # TODO: allow override of startup parameters here?
-          take_action('start', RUNNING)
-        when 'stop'
-          take_action('stop', STOPPED)
-        when 'uninstall', 'delete'
-          take_action('stop', STOPPED)
+          take_action("start", RUNNING)
+        when "stop"
+          take_action("stop", STOPPED)
+        when "uninstall", "delete"
+          take_action("stop", STOPPED)
           unless service_exists?
             puts "Service #{@service_name} doesn't exist on the system."
           else
             ::Win32::Service.delete(@service_name)
             puts "Service #{@service_name} deleted"
           end
-        when 'pause'
-          take_action('pause', PAUSED)
-        when 'resume'
-          take_action('resume', RUNNING)
+        when "pause"
+          take_action("pause", PAUSED)
+        when "resume"
+          take_action("resume", RUNNING)
         end
       end
 
@@ -163,7 +169,7 @@ class Chef
         return ::Win32::Service.exists?(@service_name)
       end
 
-      def take_action(action=nil, desired_state=nil)
+      def take_action(action = nil, desired_state = nil)
         if service_exists?
           if current_state != desired_state
             ::Win32::Service.send(action, @service_name)
diff --git a/lib/chef/applications.rb b/lib/chef/applications.rb
index 6a1a2e8..97c896e 100644
--- a/lib/chef/applications.rb
+++ b/lib/chef/applications.rb
@@ -1,4 +1,4 @@
-require 'chef/application/client'
-require 'chef/application/knife'
-require 'chef/application/solo'
-require 'chef/application/apply'
+require "chef/application/client"
+require "chef/application/knife"
+require "chef/application/solo"
+require "chef/application/apply"
diff --git a/lib/chef/audit/audit_event_proxy.rb b/lib/chef/audit/audit_event_proxy.rb
index b9ca39e..667e1db 100644
--- a/lib/chef/audit/audit_event_proxy.rb
+++ b/lib/chef/audit/audit_event_proxy.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -60,7 +60,7 @@ class Chef
       def build_control_from(example)
         described_class = example.metadata[:described_class]
         if described_class
-          resource_type = described_class.class.name.split(':')[-1]
+          resource_type = described_class.class.name.split(":")[-1]
           resource_name = described_class.name
         end
 
@@ -84,7 +84,7 @@ class Chef
             :resource_type => resource_type,
             :resource_name => resource_name,
             :context => describe_groups,
-            :line_number => example.metadata[:line_number]
+            :line_number => example.metadata[:line_number],
         }
       end
 
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb
index a4f84ed..a40cae9 100644
--- a/lib/chef/audit/audit_reporter.rb
+++ b/lib/chef/audit/audit_reporter.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'chef/event_dispatch/base'
-require 'chef/audit/control_group_data'
-require 'time'
+require "chef/event_dispatch/base"
+require "chef/audit/control_group_data"
+require "time"
 
 class Chef
   class Audit
@@ -28,12 +28,13 @@ class Chef
       attr_reader :rest_client, :audit_data, :ordered_control_groups, :run_status
       private :rest_client, :audit_data, :ordered_control_groups, :run_status
 
-      PROTOCOL_VERSION = '0.1.1'
+      PROTOCOL_VERSION = "0.1.1"
 
       def initialize(rest_client)
         @rest_client = rest_client
         # Ruby 1.9.3 and above "enumerate their values in the order that the corresponding keys were inserted."
         @ordered_control_groups = Hash.new
+        @audit_phase_error = nil
       end
 
       def run_context
@@ -46,7 +47,7 @@ class Chef
         @run_status = run_status
       end
 
-      def audit_phase_complete
+      def audit_phase_complete(audit_output)
         Chef::Log.debug("Audit Reporter completed successfully without errors.")
         ordered_control_groups.each do |name, control_group|
           audit_data.add_control_group(control_group)
@@ -57,8 +58,9 @@ class Chef
       # that runs tests - normal errors are interpreted as EXAMPLE failures and captured.
       # We still want to send available audit information to the server so we process the
       # known control groups.
-      def audit_phase_failed(error)
+      def audit_phase_failed(error, audit_output)
         # The stacktrace information has already been logged elsewhere
+        @audit_phase_error = error
         Chef::Log.debug("Audit Reporter failed.")
         ordered_control_groups.each do |name, control_group|
           audit_data.add_control_group(control_group)
@@ -70,7 +72,9 @@ class Chef
       end
 
       def run_failed(error)
-        post_auditing_data(error)
+        # Audit phase errors are captured when audit_phase_failed gets called.
+        # The error passed here isn't relevant to auditing, so we ignore it.
+        post_auditing_data
       end
 
       def control_group_started(name)
@@ -98,7 +102,7 @@ class Chef
 
       private
 
-      def post_auditing_data(error = nil)
+      def post_auditing_data
         unless auditing_enabled?
           Chef::Log.debug("Audit Reports are disabled. Skipping sending reports.")
           return
@@ -116,15 +120,15 @@ class Chef
         Chef::Log.debug("Sending audit report (run-id: #{audit_data.run_id})")
         run_data = audit_data.to_hash
 
-        if error
-          run_data[:error] = "#{error.class.to_s}: #{error.message}\n#{error.backtrace.join("\n")}"
+        if @audit_phase_error
+          error_info = "#{@audit_phase_error.class}: #{@audit_phase_error.message}"
+          error_info << "\n#{@audit_phase_error.backtrace.join("\n")}" if @audit_phase_error.backtrace
+          run_data[:error] = error_info
         end
 
         Chef::Log.debug "Audit Report:\n#{Chef::JSONCompat.to_json_pretty(run_data)}"
-        # Since we're posting compressed data we can not directly call post_rest which expects JSON
         begin
-          audit_url = rest_client.create_url(audit_history_url)
-          rest_client.post(audit_url, run_data, headers)
+          rest_client.post(audit_history_url, run_data, headers)
         rescue StandardError => e
           if e.respond_to? :response
             # 404 error code is OK. This means the version of server we're running against doesn't support
@@ -150,20 +154,19 @@ class Chef
       end
 
       def headers(additional_headers = {})
-        options = {'X-Ops-Audit-Report-Protocol-Version' => PROTOCOL_VERSION}
+        options = { "X-Ops-Audit-Report-Protocol-Version" => PROTOCOL_VERSION }
         options.merge(additional_headers)
       end
 
       def encode_gzip(data)
         "".tap do |out|
-          Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data }
+          Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
         end
       end
 
       def iso8601ify(time)
         time.utc.iso8601.to_s
       end
-
     end
   end
 end
diff --git a/lib/chef/audit/control_group_data.rb b/lib/chef/audit/control_group_data.rb
index 204d7f8..4dffbdf 100644
--- a/lib/chef/audit/control_group_data.rb
+++ b/lib/chef/audit/control_group_data.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'securerandom'
+require "securerandom"
 
 class Chef
   class Audit
@@ -41,7 +41,7 @@ class Chef
             :run_id => run_id,
             :start_time => start_time,
             :end_time => end_time,
-            :control_groups => control_groups.collect { |c| c.to_hash }
+            :control_groups => control_groups.collect { |c| c.to_hash },
         }
       end
     end
@@ -49,7 +49,7 @@ class Chef
     class ControlGroupData
       attr_reader :name, :status, :number_succeeded, :number_failed, :controls, :metadata
 
-      def initialize(name, metadata={})
+      def initialize(name, metadata = {})
         @status = "success"
         @controls = []
         @number_succeeded = 0
@@ -58,7 +58,6 @@ class Chef
         @metadata = metadata
       end
 
-
       def example_success(control_data)
         @number_succeeded += 1
         control = create_control(control_data)
@@ -80,13 +79,13 @@ class Chef
       def to_hash
         # We sort it so the examples appear in the output in the same order
         # they appeared in the recipe
-        controls.sort! {|x,y| x.line_number <=> y.line_number}
+        controls.sort! { |x, y| x.line_number <=> y.line_number }
         h = {
               :name => name,
               :status => status,
               :number_succeeded => number_succeeded,
               :number_failed => number_failed,
-              :controls => controls.collect { |c| c.to_hash }
+              :controls => controls.collect { |c| c.to_hash },
         }
         # If there is a duplicate key, metadata will overwrite it
         add_display_only_data(h).merge(metadata)
@@ -105,7 +104,7 @@ class Chef
         group[:id] = SecureRandom.uuid
         group[:controls].collect!.with_index do |c, i|
           # i is zero-indexed, and we want the display one-indexed
-          c[:sequence_number] = i+1
+          c[:sequence_number] = i + 1
           c
         end
         group
@@ -117,7 +116,7 @@ class Chef
       attr_reader :name, :resource_type, :resource_name, :context, :line_number
       attr_accessor :status, :details
 
-      def initialize(control_data={})
+      def initialize(control_data = {})
         control_data.each do |k, v|
           self.instance_variable_set("@#{k}", v)
         end
@@ -129,7 +128,7 @@ class Chef
             :status => status,
             :details => details,
             :resource_type => resource_type,
-            :resource_name => resource_name
+            :resource_name => resource_name,
         }
         h[:context] = context || []
         h
diff --git a/lib/chef/audit/logger.rb b/lib/chef/audit/logger.rb
new file mode 100644
index 0000000..759683c
--- /dev/null
+++ b/lib/chef/audit/logger.rb
@@ -0,0 +1,36 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "stringio"
+
+class Chef
+  class Audit
+    class Logger
+      def self.puts(message = "")
+        @buffer ||= StringIO.new
+        @buffer.puts(message)
+
+        Chef::Log.info(message)
+      end
+
+      def self.read_buffer
+        return "" if @buffer.nil?
+        @buffer.string
+      end
+    end
+  end
+end
diff --git a/lib/chef/audit/rspec_formatter.rb b/lib/chef/audit/rspec_formatter.rb
index 074a11b..234202b 100644
--- a/lib/chef/audit/rspec_formatter.rb
+++ b/lib/chef/audit/rspec_formatter.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Serdar Sutay (<serdar at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'rspec/core'
+require "rspec/core"
 
 class Chef
   class Audit
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
index 801bf5e..100a72d 100644
--- a/lib/chef/audit/runner.rb
+++ b/lib/chef/audit/runner.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Claire McQuin (<claire at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Claire McQuin (<claire at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
 # limitations under the License.
 #
 
+require "chef/audit/logger"
+
 class Chef
   class Audit
     class Runner
@@ -50,6 +52,7 @@ class Chef
       end
 
       private
+
       # Prepare to run audits:
       #  - Require files
       #  - Configure RSpec
@@ -76,16 +79,16 @@ class Chef
       # prevents Specinfra and Serverspec from modifying the RSpec configuration
       # used by our spec tests.
       def require_deps
-        require 'rspec'
-        require 'rspec/its'
-        require 'specinfra'
-        require 'specinfra/helper'
-        require 'specinfra/helper/set'
-        require 'serverspec/helper'
-        require 'serverspec/matcher'
-        require 'serverspec/subject'
-        require 'chef/audit/audit_event_proxy'
-        require 'chef/audit/rspec_formatter'
+        require "rspec"
+        require "rspec/its"
+        require "specinfra"
+        require "specinfra/helper"
+        require "specinfra/helper/set"
+        require "serverspec/helper"
+        require "serverspec/matcher"
+        require "serverspec/subject"
+        require "chef/audit/audit_event_proxy"
+        require "chef/audit/rspec_formatter"
 
         Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
       end
@@ -104,6 +107,7 @@ class Chef
         RSpec.configure do |c|
           c.color = Chef::Config[:color]
           c.expose_dsl_globally = false
+          c.project_source_dirs = Array(Chef::Config[:cookbook_path])
           c.backtrace_exclusion_patterns << exclusion_pattern
         end
       end
@@ -115,8 +119,8 @@ class Chef
       # the output stream to be changed for a formatter once the formatter has
       # been added.
       def set_streams
-        RSpec.configuration.output_stream = Chef::Config[:log_location]
-        RSpec.configuration.error_stream = Chef::Config[:log_location]
+        RSpec.configuration.output_stream = Chef::Audit::Logger
+        RSpec.configuration.error_stream = Chef::Audit::Logger
       end
 
       # Add formatters which we use to
@@ -144,7 +148,7 @@ class Chef
       def configure_specinfra
         if Chef::Platform.windows?
           Specinfra.configuration.backend = :cmd
-          Specinfra.configuration.os = { :family => 'windows' }
+          Specinfra.configuration.os = { :family => "windows" }
         else
           Specinfra.configuration.backend = :exec
         end
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index d3f7ee5..f019448 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,6 +26,11 @@
 # injected" into this class by other objects and do not reference the class symbols in those files
 # directly and we do not need to require those files here.
 
+require "chef/platform/provider_priority_map"
+require "chef/platform/resource_priority_map"
+require "chef/platform/provider_handler_map"
+require "chef/platform/resource_handler_map"
+
 class Chef
   class << self
 
@@ -33,50 +38,81 @@ class Chef
     # Public API
     #
 
+    #
     # Get the node object
     #
     # @return [Chef::Node] node object of the chef-client run
+    #
     attr_reader :node
 
+    #
     # Get the run context
     #
     # @return [Chef::RunContext] run_context of the chef-client run
+    #
     attr_reader :run_context
 
+    # Register an event handler with user specified block
+    #
+    # @return[Chef::EventDispatch::Base] handler object
+    def event_handler(&block)
+      dsl = Chef::EventDispatch::DSL.new("Chef client DSL")
+      dsl.instance_eval(&block)
+    end
+
     # Get the array of providers associated with a resource_name for the current node
     #
     # @param resource_name [Symbol] name of the resource as a symbol
+    #
     # @return [Array<Class>] Priority Array of Provider Classes to use for the resource_name on the node
+    #
     def get_provider_priority_array(resource_name)
-      @provider_priority_map.get_priority_array(node, resource_name).dup
+      result = provider_priority_map.get_priority_array(node, resource_name.to_sym)
+      result = result.dup if result
+      result
     end
 
+    #
     # Get the array of resources associated with a resource_name for the current node
     #
     # @param resource_name [Symbol] name of the resource as a symbol
+    #
     # @return [Array<Class>] Priority Array of Resource Classes to use for the resource_name on the node
+    #
     def get_resource_priority_array(resource_name)
-      @resource_priority_map.get_priority_array(node, resource_name).dup
+      result = resource_priority_map.get_priority_array(node, resource_name.to_sym)
+      result = result.dup if result
+      result
     end
 
+    #
     # Set the array of providers associated with a resource_name for the current node
     #
     # @param resource_name [Symbol] name of the resource as a symbol
-    # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+    # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node
     # @param filter [Hash] Chef::Nodearray-style filter
+    #
     # @return [Array<Class>] Modified Priority Array of Provider Classes to use for the resource_name on the node
-    def set_provider_priority_array(resource_name, priority_array, *filter)
-      @provider_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+    #
+    def set_provider_priority_array(resource_name, priority_array, *filter, &block)
+      result = provider_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block)
+      result = result.dup if result
+      result
     end
 
+    #
     # Get the array of resources associated with a resource_name for the current node
     #
     # @param resource_name [Symbol] name of the resource as a symbol
-    # @param priority_array [Array<Class>] Array of Classes to set as the priority for resource_name on the node
+    # @param priority_array [Class, Array<Class>] Class or Array of Classes to set as the priority for resource_name on the node
     # @param filter [Hash] Chef::Nodearray-style filter
+    #
     # @return [Array<Class>] Modified Priority Array of Resource Classes to use for the resource_name on the node
-    def set_resource_priority_array(resource_name, priority_array, *filter)
-      @resource_priority_map.set_priority_array(resource_name, priority_array, *filter).dup
+    #
+    def set_resource_priority_array(resource_name, priority_array, *filter, &block)
+      result = resource_priority_map.set_priority_array(resource_name.to_sym, priority_array, *filter, &block)
+      result = result.dup if result
+      result
     end
 
     #
@@ -85,22 +121,27 @@ class Chef
     #   *NOT* for public consumption ]
     #
 
+    #
     # Sets the resource_priority_map
     #
-    # @api private
     # @param resource_priority_map [Chef::Platform::ResourcePriorityMap]
+    #
+    # @api private
     def set_resource_priority_map(resource_priority_map)
       @resource_priority_map = resource_priority_map
     end
 
+    #
     # Sets the provider_priority_map
     #
-    # @api private
     # @param provider_priority_map [Chef::Platform::providerPriorityMap]
+    #
+    # @api private
     def set_provider_priority_map(provider_priority_map)
       @provider_priority_map = provider_priority_map
     end
 
+    #
     # Sets the node object
     #
     # @api private
@@ -109,14 +150,17 @@ class Chef
       @node = node
     end
 
+    #
     # Sets the run_context object
     #
-    # @api private
     # @param run_context [Chef::RunContext]
+    #
+    # @api private
     def set_run_context(run_context)
       @run_context = run_context
     end
 
+    #
     # Resets the internal state
     #
     # @api private
@@ -125,6 +169,60 @@ class Chef
       @node = nil
       @provider_priority_map = nil
       @resource_priority_map = nil
+      @provider_handler_map = nil
+      @resource_handler_map = nil
+    end
+
+    # @api private
+    def provider_priority_map
+      # these slurp in the resource+provider world, so be exceedingly lazy about requiring them
+      @provider_priority_map ||= Chef::Platform::ProviderPriorityMap.instance
+    end
+
+    # @api private
+    def resource_priority_map
+      @resource_priority_map ||= Chef::Platform::ResourcePriorityMap.instance
+    end
+
+    # @api private
+    def provider_handler_map
+      @provider_handler_map ||= Chef::Platform::ProviderHandlerMap.instance
+    end
+
+    # @api private
+    def resource_handler_map
+      @resource_handler_map ||= Chef::Platform::ResourceHandlerMap.instance
+    end
+
+    #
+    # Emit a deprecation message.
+    #
+    # @param message The message to send.
+    # @param location The location. Defaults to the caller who called you (since
+    #   generally the person who triggered the check is the one that needs to be
+    #   fixed).
+    #
+    # @example
+    #     Chef.deprecation("Deprecated!")
+    #
+    # @api private this will likely be removed in favor of an as-yet unwritten
+    #      `Chef.log`
+    def log_deprecation(message, location = nil)
+      location ||= Chef::Log.caller_location
+      # `run_context.events` is the primary deprecation target if we're in a
+      # run. If we are not yet in a run, print to `Chef::Log`.
+      if run_context && run_context.events
+        run_context.events.deprecation(message, location)
+      else
+        Chef::Log.deprecation(message, location)
+      end
     end
   end
+
+  # @api private Only for test dependency injection; not evenly implemented as yet.
+  def self.path_to(path)
+    path
+  end
+
+  reset!
 end
diff --git a/lib/chef/chef_fs.rb b/lib/chef/chef_fs.rb
index bc445e5..43a9efd 100644
--- a/lib/chef/chef_fs.rb
+++ b/lib/chef/chef_fs.rb
@@ -1,4 +1,54 @@
-require 'chef/platform'
+require "chef/platform"
+
+#
+# ChefFS was designed to be a near-1:1 translation between Chef server endpoints
+# and local data, so that it could be used for:
+#
+# 1. User editing, diffing and viewing of server content locally
+# 2. knife download, upload and diff (supporting the above scenario)
+# 3. chef-client -z (serving user repository directly)
+#
+# This is the translation between chef-zero data stores (which correspond
+# closely to server endpoints) and the ChefFS repository format.
+#
+# |-----------------------------------|-----------------------------------|
+# | chef-zero DataStore               | ChefFS (repository)               |
+# |-----------------------------------|-----------------------------------|
+# | <root>                            | org.json                          |
+# | association_requests/NAME         | invitations.json                  |
+# | clients/NAME                      | clients/NAME.json                 |
+# | cookbooks/NAME/VERSION            | cookbooks/NAME/metadata.rb        |
+# | containers/NAME                   | containers/NAME.json              |
+# | data/BAG/ITEM                     | data_bags/BAG/ITEM.json           |
+# | environments/NAME                 | environments/NAME.json            |
+# | groups/NAME                       | groups/NAME.json                  |
+# | nodes/NAME                        | nodes/NAME.json                   |
+# | policies/NAME/REVISION            | policies/NAME-REVISION.json       |
+# | policy_groups/NAME/policies/PNAME | policy_groups/NAME.json           |
+# | roles/NAME                        | roles/NAME.json                   |
+# | sandboxes/ID                      | <not stored on disk, just memory> |
+# | users/NAME                        | members.json                      |
+# | file_store/COOKBOOK/VERSION/PATH  | cookbooks/COOKBOOK/PATH           |
+# | **/_acl                           | acls/**.json                      |
+# |-----------------------------------|-----------------------------------|
+#
+#
+# ## The Code
+#
+# There are two main entry points to ChefFS:
+#
+# - ChefServerRootDir represents the chef server (under an org) and surfaces a
+#   filesystem-like interface (FSBaseObject / FSBaseDir) that maps the REST API
+#   to the same format as you would have on disk.
+# - ChefRepositoryFileSystemRootDir represents the local repository where you
+#   put your cookbooks, roles, policies, etc.
+#
+# Because these two map to a common directory structure, diff, upload, download,
+# and other filesystem operations, can easily be done in a generic manner.
+#
+# These are instantiated by Chef::ChefFS::Config's `chef_fs` and `local_fs`
+# methods.
+#
 
 class Chef
   module ChefFS
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index 4084fb8..7cf7d5f 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/cookbook_manifest'
-require 'chef_zero/data_store/memory_store'
-require 'chef_zero/data_store/data_already_exists_error'
-require 'chef_zero/data_store/data_not_found_error'
-require 'chef/chef_fs/file_pattern'
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/memory_root'
-require 'fileutils'
+require "chef/cookbook_manifest"
+require "chef_zero/data_store/memory_store"
+require "chef_zero/data_store/data_already_exists_error"
+require "chef_zero/data_store/data_not_found_error"
+require "chef/chef_fs/file_pattern"
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/memory/memory_root"
+require "fileutils"
 
 class Chef
   module ChefFS
@@ -66,13 +66,84 @@ class Chef
     #   - ChefFSDataStore lets cookbooks be uploaded into a temporary memory
     #     storage, and when the cookbook is committed, copies the files onto the
     #     disk in the correct place (/cookbooks/apache2/recipes/default.rb).
+    #
     # 3. Data bags:
     #   - The Chef server expects data bags in /data/BAG/ITEM
     #   - The repository stores data bags in /data_bags/BAG/ITEM
     #
     # 4. JSON filenames are generally NAME.json in the repository (e.g. /nodes/foo.json).
     #
+    # 5. Org membership:
+    #    chef-zero stores user membership in an org as a series of empty files.
+    #    If an org has jkeiser and cdoherty as members, chef-zero expects these
+    #    files to exist:
+    #
+    #    - `users/jkeiser` (content: '{}')
+    #    - `users/cdoherty` (content: '{}')
+    #
+    #    ChefFS, on the other hand, stores user membership in an org as a single
+    #    file, `members.json`, with content:
+    #
+    #        ```json
+    #        [
+    #          { "user": { "username": "jkeiser" } },
+    #          { "user": { "username": "cdoherty" } }
+    #        ]
+    #        ```
+    #
+    #    To translate between the two, we need to intercept requests to `users`
+    #    like so:
+    #
+    #    - `list(users)` -> `get(/members.json)`
+    #    - `get(users/NAME)` -> `get(/members.json)`, see if it's in there
+    #    - `create(users/NAME)` -> `get(/members.json)`, add name, `set(/members.json)`
+    #    - `delete(users/NAME)` -> `get(/members.json)`, remove name, `set(/members.json)`
+    #
+    # 6. Org invitations:
+    #    chef-zero stores org membership invitations as a series of empty files.
+    #    If an org has invited jkeiser and cdoherty (and they have not yet accepted
+    #    the invite), chef-zero expects these files to exist:
+    #
+    #    - `association_requests/jkeiser` (content: '{}')
+    #    - `association_requests/cdoherty` (content: '{}')
+    #
+    #    ChefFS, on the other hand, stores invitations as a single file,
+    #    `invitations.json`, with content:
+    #
+    #        ```json
+    #        [
+    #          { "id" => "jkeiser-chef", 'username' => 'jkeiser' },
+    #          { "id" => "cdoherty-chef", 'username' => 'cdoherty' }
+    #        ]
+    #        ```
+    #
+    #    To translate between the two, we need to intercept requests to `users`
+    #    like so:
+    #
+    #    - `list(association_requests)` -> `get(/invitations.json)`
+    #    - `get(association_requests/NAME)` -> `get(/invitations.json)`, see if it's in there
+    #    - `create(association_requests/NAME)` -> `get(/invitations.json)`, add name, `set(/invitations.json)`
+    #    - `delete(association_requests/NAME)` -> `get(/invitations.json)`, remove name, `set(/invitations.json)`
+    #
     class ChefFSDataStore
+
+      # The base directories in a Chef Repo; even when these don't exist, a
+      # matching GET for these objects will return an empty list instead of a
+      # 404.
+      BASE_DIRNAMES = %w{
+        clients
+        cookbooks
+        data
+        environments
+        nodes
+        roles
+        users
+        containers
+        groups
+        policy_groups
+        policies
+      }.freeze
+
       #
       # Create a new ChefFSDataStore
       #
@@ -83,9 +154,10 @@ class Chef
       #   Generally will be a +ChefFS::FileSystem::ChefRepositoryFileSystemRoot+
       #   object, created from +ChefFS::Config.local_fs+.
       #
-      def initialize(chef_fs)
+      def initialize(chef_fs, chef_config = Chef::Config)
         @chef_fs = chef_fs
         @memory_store = ChefZero::DataStore::MemoryStore.new
+        @repo_mode = chef_config[:repo_mode]
       end
 
       def publish_description
@@ -93,14 +165,15 @@ class Chef
       end
 
       attr_reader :chef_fs
+      attr_reader :repo_mode
 
       def create_dir(path, name, *options)
         if use_memory_store?(path)
           @memory_store.create_dir(path, name, *options)
         else
-          with_dir(path) do |parent|
+          with_parent_dir(path + [name], *options) do |parent, name|
             begin
-              parent.create_child(chef_fs_filename(path + [name]), nil)
+              parent.create_child(name, nil)
             rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
               raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
             end
@@ -108,21 +181,78 @@ class Chef
         end
       end
 
+      #
+      # If you want to get the contents of /data/x/y from the server,
+      # you say chef_fs.child('data').child('x').child('y').read.
+      # It will make exactly one network request: GET /data/x/y
+      # And that will return 404 if it doesn't exist.
+      #
+      # ChefFS objects do not go to the network until you ask them for data.
+      # This means you can construct a /data/x/y ChefFS entry early.
+      #
+      # Alternative:
+      # chef_fs.child('data') could have done a GET /data preemptively,
+      # allowing it to know whether child('x') was valid (GET /data gives you
+      # a list of data bags). Then child('x') could have done a GET /data/x,
+      # allowing it to know whether child('y') (the item) existed. Finally,
+      # we would do the GET /data/x/y to read the contents. Three network
+      # requests instead of 1.
+      #
+
       def create(path, name, data, *options)
         if use_memory_store?(path)
           @memory_store.create(path, name, data, *options)
 
-        elsif path[0] == 'cookbooks' && path.length == 2
+        elsif path[0] == "cookbooks" && path.length == 2
           # Do nothing.  The entry gets created when the cookbook is created.
 
+        # /policy_groups/GROUP/policies/NAME
+        elsif path[0] == "policy_groups" && path[2] == "policies"
+          # Just set or create the proper entry in the hash
+          update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+            if policies.has_key?(path[3])
+              raise ChefZero::DataStore::DataAlreadyExistsError.new(path, group)
+            end
+
+            group["policies"] ||= {}
+            group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+            group
+          end
+
+        # create [/organizations/ORG]/users/NAME (with content '{}')
+        # Manipulate the `members.json` file that contains a list of all users
+        elsif is_org? && path == [ "users" ]
+          update_json("members.json", [], *options) do |members|
+            # Format of each entry: { "user": { "username": "jkeiser" } }
+            if members.any? { |member| member["user"]["username"] == name }
+              raise ChefZero::DataStore::DataAlreadyExistsError.new(path, entry)
+            end
+
+            # Actually add the user
+            members << { "user" => { "username" => name } }
+          end
+
+        # create [/organizations/ORG]/association_requests/NAME (with content '{}')
+        # Manipulate the `invitations.json` file that contains a list of all users
+        elsif is_org? && path == [ "association_requests" ]
+          update_json("invitations.json", [], *options) do |invitations|
+            # Format of each entry: { "id" => "jkeiser-chef", 'username' => 'jkeiser' }
+            if invitations.any? { |member| member["username"] == name }
+              raise ChefZero::DataStore::DataAlreadyExistsError.new(path)
+            end
+
+            # Actually add the user (TODO insert org name??)
+            invitations << { "username" => name }
+          end
+
         else
           if !data.is_a?(String)
             raise "set only works with strings"
           end
 
-          with_dir(path) do |parent|
+          with_parent_dir(path + [name], *options) do |parent, name|
             begin
-              parent.create_child(chef_fs_filename(path + [name]), data)
+              parent.create_child(name, data)
             rescue Chef::ChefFS::FileSystem::AlreadyExistsError => e
               raise ChefZero::DataStore::DataAlreadyExistsError.new(to_zero_path(e.entry), e)
             end
@@ -130,54 +260,99 @@ class Chef
         end
       end
 
-      def get(path, request=nil)
+      def get(path, request = nil)
         if use_memory_store?(path)
           @memory_store.get(path)
 
-        elsif path[0] == 'file_store' && path[1] == 'repo'
-          entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join('/'))
+        elsif path[0] == "file_store" && path[1] == "repo"
+          entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join("/"))
           begin
             entry.read
           rescue Chef::ChefFS::FileSystem::NotFoundError => e
             raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
           end
 
-        else
+        # /policy_groups/NAME/policies/POLICYNAME: return the revision of the given policy
+        elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+          # Just set or create the proper entry in the hash
+          policy_group = get_json(to_chef_fs_path(path[0..1]), {})
+          if !policy_group["policies"] || !policy_group["policies"][path[3]]
+            raise ChefZero::DataStore::DataNotFoundError.new(path, entry)
+          end
+          # The policy group looks like:
+          # {
+          #   "policies": {
+          #     "x": { "revision_id": "10" }
+          #   }
+          # }
+          Chef::JSONCompat.to_json_pretty(policy_group["policies"][path[3]]["revision_id"])
+
+        # GET [/organizations/ORG]/users/NAME -> /users/NAME
+        # Manipulates members.json
+        elsif is_org? && path[0] == "users" && path.length == 2
+          if get_json("members.json", []).any? { |member| member["user"]["username"] == path[1] }
+            "{}"
+          else
+            raise ChefZero::DataStore::DataNotFoundError.new(path)
+          end
+
+        # GET [/organizations/ORG]/association_requests/NAME -> /users/NAME
+        # Manipulates invites.json
+        elsif is_org? && path[0] == "association_requests" && path.length == 2
+          if get_json("invites.json", []).any? { |member| member["user"]["username"] == path[1] }
+            "{}"
+          else
+            raise ChefZero::DataStore::DataNotFoundError.new(path)
+          end
+
+        # GET /cookbooks/NAME/VERSION or /cookbook_artifacts/NAME/IDENTIFIER
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3
           with_entry(path) do |entry|
-            if path[0] == 'cookbooks' && path.length == 3
-              # get /cookbooks/NAME/version
-              result = nil
-              begin
-                result = Chef::CookbookManifest.new(entry.chef_object).to_hash
-              rescue Chef::ChefFS::FileSystem::NotFoundError => e
-                raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
-              end
+            cookbook_type = path[0]
+            result = nil
+            begin
+              result = Chef::CookbookManifest.new(entry.chef_object, policy_mode: cookbook_type == "cookbook_artifacts").to_hash
+            rescue Chef::ChefFS::FileSystem::NotFoundError => e
+              raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+            end
 
-              result.each_pair do |key, value|
-                if value.is_a?(Array)
-                  value.each do |file|
-                    if file.is_a?(Hash) && file.has_key?('checksum')
-                      relative = ['file_store', 'repo', 'cookbooks']
-                      if chef_fs.versioned_cookbooks
-                        relative << "#{path[1]}-#{path[2]}"
-                      else
-                        relative << path[1]
-                      end
-                      relative = relative + file[:path].split('/')
-                      file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative)
+            result.each_pair do |key, value|
+              if value.is_a?(Array)
+                value.each do |file|
+                  if file.is_a?(Hash) && file.has_key?("checksum")
+                    relative = ["file_store", "repo", cookbook_type]
+                    if chef_fs.versioned_cookbooks || cookbook_type == "cookbook_artifacts"
+                      relative << "#{path[1]}-#{path[2]}"
+                    else
+                      relative << path[1]
                     end
+                    relative = relative + file[:path].split("/")
+                    file["url"] = ChefZero::RestBase::build_uri(request.base_uri, relative)
                   end
                 end
               end
-              Chef::JSONCompat.to_json_pretty(result)
+            end
 
-            else
-              begin
-                entry.read
-              rescue Chef::ChefFS::FileSystem::NotFoundError => e
-                raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+            if cookbook_type == "cookbook_artifacts"
+              result["metadata"] = result["metadata"].to_hash
+              result["metadata"].delete_if do |key, value|
+                value == [] ||
+                  (value == {} && !%w{dependencies attributes recipes}.include?(key)) ||
+                  (value == "" && %w{source_url issues_url}.include?(key)) ||
+                  (value == false && key == "privacy")
               end
             end
+
+            Chef::JSONCompat.to_json_pretty(result)
+          end
+
+        else
+          with_entry(path) do |entry|
+            begin
+              entry.read
+            rescue Chef::ChefFS::FileSystem::NotFoundError => e
+              raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+            end
           end
         end
       end
@@ -191,15 +366,25 @@ class Chef
           end
 
           # Write out the files!
-          if path[0] == 'cookbooks' && path.length == 3
+          if %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3
             write_cookbook(path, data, *options)
+
+          # Handle /policy_groups/some_policy_group/policies/some_policy_name
+          elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+            # Just set or create the proper entry in the hash
+            update_json(to_chef_fs_path(path[0..1]), {}, *options) do |group|
+              group["policies"] ||= {}
+              group["policies"][path[3]] = { "revision_id" => Chef::JSONCompat.parse(data) }
+              group
+            end
+
           else
-            with_dir(path[0..-2]) do |parent|
-              child = parent.child(chef_fs_filename(path))
+            with_parent_dir(path, *options) do |parent, name|
+              child = parent.child(name)
               if child.exists?
                 child.write(data)
               else
-                parent.create_child(chef_fs_filename(path), data)
+                parent.create_child(name, data)
               end
             end
           end
@@ -209,10 +394,43 @@ class Chef
       def delete(path)
         if use_memory_store?(path)
           @memory_store.delete(path)
+
+        # DELETE /policy_groups/GROUP/policies/POLICY
+        elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+          update_json(to_chef_fs_path(path[0..1]), {}) do |group|
+            unless group["policies"] && group["policies"].has_key?(path[3])
+              raise ChefZero::DataStore::DataNotFoundError.new(path)
+            end
+            group["policies"].delete(path[3])
+            group
+          end
+
+        # DELETE [/organizations/ORG]/users/NAME
+        # Manipulates members.json
+        elsif is_org? && path[0] == "users" && path.length == 2
+          update_json("members.json", []) do |members|
+            result = members.reject { |member| member["user"]["username"] == path[1] }
+            if result.size == members.size
+              raise ChefZero::DataStore::DataNotFoundError.new(path)
+            end
+            result
+          end
+
+        # DELETE [/organizations/ORG]/users/NAME
+        # Manipulates members.json
+        elsif is_org? && path[0] == "association_requests" && path.length == 2
+          update_json("invitations.json", []) do |invitations|
+            result = invitations.reject { |invitation| invitation["username"] == path[1] }
+            if result.size == invitations.size
+              raise ChefZero::DataStore::DataNotFoundError.new(path)
+            end
+            result
+          end
+
         else
           with_entry(path) do |entry|
             begin
-              if path[0] == 'cookbooks' && path.length >= 3
+              if %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length >= 3
                 entry.delete(true)
               else
                 entry.delete(false)
@@ -227,6 +445,24 @@ class Chef
       def delete_dir(path, *options)
         if use_memory_store?(path)
           @memory_store.delete_dir(path, *options)
+
+        # DELETE /policies/POLICY
+        elsif path[0] == "policies" && path.length == 2
+          with_entry(path[0..0]) do |policies|
+            # /policies:
+            #   - a-1.0.0.json
+            #   - a-1.0.1.json
+            #   - b-2.0.0.json
+            found_policy = false
+            policies.children.each do |policy|
+              # We want to delete just the ones that == POLICY
+              next unless policy.name.rpartition("-")[0] == path[1]
+              policy.delete(false)
+              found_policy = true
+            end
+            raise ChefZero::DataStore::DataNotFoundError.new(path) if !found_policy
+          end
+
         else
           with_entry(path) do |entry|
             begin
@@ -242,10 +478,49 @@ class Chef
         if use_memory_store?(path)
           @memory_store.list(path)
 
-        elsif path[0] == 'cookbooks' && path.length == 1
+        # LIST /policies
+        elsif path == [ "policies" ]
+          with_entry([ path[0] ]) do |policies|
+            begin
+              policies.children.map { |policy| policy.name[0..-6].rpartition("-")[0] }.uniq
+            rescue Chef::ChefFS::FileSystem::NotFoundError
+              []
+            end
+          end
+
+        # LIST /policies/POLICY/revisions
+        elsif path[0] == "policies" && path[2] == "revisions" && path.length == 3
+          with_entry([ path[0] ]) do |policies|
+            # /policies:
+            #   - a-1.0.0.json
+            #   - a-1.0.1.json
+            #   - b-2.0.0.json
+            revisions = []
+            policies.children.each do |policy|
+              name, dash, revision = policy.name[0..-6].rpartition("-")
+              revisions << revision if name == path[1]
+            end
+            raise ChefZero::DataStore::DataNotFoundError.new(path) if revisions.empty?
+            revisions
+          end
+
+        elsif path[0] == "policy_groups" && path.length == 2
+          with_entry(path) do |entry|
+            [ "policies" ]
+          end
+
+        elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
+          with_entry(path[0..1]) do |entry|
+            policies = Chef::JSONCompat.parse(entry.read)["policies"] || {}
+            policies.keys
+          end
+
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 1
           with_entry(path) do |entry|
             begin
-              if chef_fs.versioned_cookbooks
+              if path[0] == "cookbook_artifacts"
+                entry.children.map { |child| child.name.rpartition("-")[0] }.uniq
+              elsif chef_fs.versioned_cookbooks
                 # /cookbooks/name-version -> /cookbooks/name
                 entry.children.map { |child| split_name_version(child.name)[0] }.uniq
               else
@@ -257,13 +532,13 @@ class Chef
             end
           end
 
-        elsif path[0] == 'cookbooks' && path.length == 2
-          if chef_fs.versioned_cookbooks
-            result = with_entry([ 'cookbooks' ]) do |entry|
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2
+          if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
+            result = with_entry([ path[0] ]) do |entry|
               # list /cookbooks/name = filter /cookbooks/name-version down to name
               entry.children.map { |child| split_name_version(child.name) }.
-                             select { |name, version| name == path[1] }.
-                             map { |name, version| version }
+              select { |name, version| name == path[1] }.
+              map { |name, version| version }
             end
             if result.empty?
               raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -276,7 +551,7 @@ class Chef
           end
 
         else
-          with_entry(path) do |entry|
+          result = with_entry(path) do |entry|
             begin
               entry.children.map { |c| zero_filename(c) }.sort
             rescue Chef::ChefFS::FileSystem::NotFoundError => e
@@ -288,12 +563,25 @@ class Chef
               end
             end
           end
+
+          # Older versions of chef-zero do not understand policies and cookbook_artifacts,
+          # don't give that stuff to them
+          if path == [] && ChefZero::VERSION.to_f < 4.4
+            result.reject! { |child| %w{policies policy_data cookbook_artifacts}.include?(child) }
+          end
+          result
         end
       end
 
       def exists?(path)
         if use_memory_store?(path)
           @memory_store.exists?(path)
+
+        # /policy_groups/NAME/policies/POLICYNAME
+        elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 4
+          group = get_json(to_chef_fs_path(path[0..1]), {})
+          group["policies"] && group["policies"].has_key?(path[3])
+
         else
           path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
         end
@@ -302,8 +590,18 @@ class Chef
       def exists_dir?(path)
         if use_memory_store?(path)
           @memory_store.exists_dir?(path)
-        elsif path[0] == 'cookbooks' && path.length == 2
+
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2
+          list([ path[0] ]).include?(path[1])
+
+        # /policies/NAME
+        elsif path[0] == "policies" && path.length == 2
           list([ path[0] ]).include?(path[1])
+
+        # /policy_groups/NAME/policies
+        elsif path[0] == "policy_groups" && path[2] == "policies" && path.length == 3
+          exists_dir?(path[0..1])
+
         else
           Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists?
         end
@@ -312,34 +610,35 @@ class Chef
       private
 
       def use_memory_store?(path)
-        return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ]
+        return path[0] == "sandboxes" || path[0] == "file_store" && path[1] == "checksums" || path == [ "environments", "_default" ]
       end
 
       def write_cookbook(path, data, *options)
+        cookbook_type = path[0]
         if chef_fs.versioned_cookbooks
-          cookbook_path = File.join('cookbooks', "#{path[1]}-#{path[2]}")
+          cookbook_path = File.join(cookbook_type, "#{path[1]}-#{path[2]}")
         else
-          cookbook_path = File.join('cookbooks', path[1])
+          cookbook_path = File.join(cookbook_type, path[1])
         end
 
         # Create a little Chef::ChefFS memory filesystem with the data
-        cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading')
+        cookbook_fs = Chef::ChefFS::FileSystem::Memory::MemoryRoot.new("uploading")
         cookbook = Chef::JSONCompat.parse(data)
         cookbook.each_pair do |key, value|
           if value.is_a?(Array)
             value.each do |file|
-              if file.is_a?(Hash) && file.has_key?('checksum')
-                file_data = @memory_store.get(['file_store', 'checksums', file['checksum']])
-                cookbook_fs.add_file(File.join(cookbook_path, file['path']), file_data)
+              if file.is_a?(Hash) && file.has_key?("checksum")
+                file_data = @memory_store.get(["file_store", "checksums", file["checksum"]])
+                cookbook_fs.add_file(File.join(cookbook_path, file["path"]), file_data)
               end
             end
           end
         end
 
         # Create the .uploaded-cookbook-version.json
-        cookbooks = chef_fs.child('cookbooks')
+        cookbooks = chef_fs.child(cookbook_type)
         if !cookbooks.exists?
-          cookbooks = chef_fs.create_child('cookbooks')
+          cookbooks = chef_fs.create_child(cookbook_type)
         end
         # We are calling a cookbooks-specific API, so get multiplexed_dirs out of the way if it is there
         if cookbooks.respond_to?(:multiplexed_dirs)
@@ -349,14 +648,14 @@ class Chef
       end
 
       def split_name_version(entry_name)
-        name_version = entry_name.split('-')
-        name = name_version[0..-2].join('-')
+        name_version = entry_name.split("-")
+        name = name_version[0..-2].join("-")
         version = name_version[-1]
-        [name,version]
+        [name, version]
       end
 
       def to_chef_fs_path(path)
-        _to_chef_fs_path(path).join('/')
+        _to_chef_fs_path(path).join("/")
       end
 
       def chef_fs_filename(path)
@@ -364,27 +663,28 @@ class Chef
       end
 
       def _to_chef_fs_path(path)
-        if path[0] == 'data'
-          path = path.dup
-          path[0] = 'data_bags'
-          if path.length >= 3
-            path[2] = "#{path[2]}.json"
-          end
-        elsif path[0] == 'policies'
+        # /data -> /data_bags
+        # /data/BAG -> /data_bags/BAG
+        # /data/BAG/ITEM -> /data_bags/BAG/ITEM.json
+        if path[0] == "data"
           path = path.dup
+          path[0] = "data_bags"
           if path.length >= 3
             path[2] = "#{path[2]}.json"
           end
-        elsif path[0] == 'cookbooks'
+
+        # /policies/POLICY/revisions/REVISION -> /policies/POLICY-REVISION.json
+        elsif path[0] == "policies" && path[2] == "revisions" && path.length >= 4
+          path = [ "policies", "#{path[1]}-#{path[3]}.json" ]
+
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0])
           if path.length == 2
             raise ChefZero::DataStore::DataNotFoundError.new(path)
-          elsif chef_fs.versioned_cookbooks
-            if path.length >= 3
+          elsif path.length >= 3
+            if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
               # cookbooks/name/version -> cookbooks/name-version
               path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1]
-            end
-          else
-            if path.length >= 3
+            else
               # cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so
               version = get_single_cookbook_version(path)
               if path[2] == version
@@ -394,24 +694,43 @@ class Chef
               end
             end
           end
+
+        elsif path[0] == "acls"
+          # /acls/data -> /acls/data_bags
+          if path[1] == "data"
+            path = path.dup
+            path[1] = "data_bags"
+          end
+
+          # /acls/containers|nodes|.../x.json
+          # /acls/organization.json
+          if path.length == 3 || path == [ "acls", "organization" ]
+            path = path.dup
+            path[-1] = "#{path[-1]}.json"
+          end
+
+          # /acls/containers|nodes|... do NOT drop into the next elsif, and do
+          # not get .json appended
+
+        # /nodes|clients|.../x.json
         elsif path.length == 2
           path = path.dup
-          path[1] = "#{path[1]}.json"
+          path[-1] = "#{path[-1]}.json"
         end
         path
       end
 
       def to_zero_path(entry)
-        path = entry.path.split('/')[1..-1]
-        if path[0] == 'data_bags'
+        path = entry.path.split("/")[1..-1]
+        if path[0] == "data_bags"
           path = path.dup
-          path[0] = 'data'
+          path[0] = "data"
           if path.length >= 3
             path[2] = path[2][0..-6]
           end
 
-        elsif path[0] == 'cookbooks'
-          if chef_fs.versioned_cookbooks
+        elsif %w{cookbooks cookbook_artifacts}.include?(path[0])
+          if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
             # cookbooks/name-version/... -> cookbooks/name/version/...
             if path.length >= 2
               name, version = split_name_version(path[1])
@@ -425,7 +744,14 @@ class Chef
             end
           end
 
-        elsif path.length == 2 && path[0] != 'cookbooks'
+        # /policies/NAME-REVISION.json -> /policies/NAME/revisions/REVISION
+        elsif path[0] == "policies"
+          if path.length >= 2
+            name, dash, revision = path[1][0..-6].rpartition("-")
+            path = [ "policies", name, "revisions", revision ]
+          end
+
+        elsif path.length == 2 && path[0] != "cookbooks"
           path = path.dup
           path[1] = path[1][0..-6]
         end
@@ -437,7 +763,7 @@ class Chef
       end
 
       def path_always_exists?(path)
-        return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0])
+        return path.length == 1 && BASE_DIRNAMES.include?(path[0])
       end
 
       def with_entry(path)
@@ -448,9 +774,20 @@ class Chef
         end
       end
 
+      def with_parent_dir(path, *options)
+        path = _to_chef_fs_path(path)
+        begin
+          yield get_dir(path[0..-2], options.include?(:create_dir)), path[-1]
+        rescue Chef::ChefFS::FileSystem::NotFoundError => e
+          err = ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
+          err.set_backtrace(e.backtrace)
+          raise err
+        end
+      end
+
       def with_dir(path)
         # Do not automatically create data bags
-        create = !(path[0] == 'data' && path.size >= 2)
+        create = !(path[0] == "data" && path.size >= 2)
 
         begin
           yield get_dir(_to_chef_fs_path(path), create)
@@ -461,11 +798,11 @@ class Chef
         end
       end
 
-      def get_dir(path, create=false)
-        result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join('/'))
+      def get_dir(path, create = false)
+        result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join("/"))
         if result.exists?
           result
-        elsif create
+        elsif create || path.size == 1
           get_dir(path[0..-2], create).create_child(result.name, nil)
         else
           raise ChefZero::DataStore::DataNotFoundError.new(path)
@@ -473,9 +810,46 @@ class Chef
       end
 
       def get_single_cookbook_version(path)
-        dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join('/'))
+        dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join("/"))
         metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, [])
-        metadata[:version] || '0.0.0'
+        metadata[:version] || "0.0.0"
+      end
+
+      def update_json(path, default_value, *options)
+        entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
+        begin
+          input = Chef::JSONCompat.parse(entry.read)
+          output = yield input
+          entry.write(Chef::JSONCompat.to_json_pretty(output)) if output != Chef::JSONCompat.parse(entry.read)
+        rescue Chef::ChefFS::FileSystem::NotFoundError
+          # Send the default value to the caller, and create the entry if the caller updates it
+          output = yield default_value
+          parent = entry.parent
+          parent = ensure_dir(parent) if options.include?(:create_dir)
+          parent.create_child(entry.name, Chef::JSONCompat.to_json_pretty(output)) if output != []
+        end
+      end
+
+      def ensure_dir(entry)
+        return entry if entry.exists?
+        parent = entry.parent
+        if parent
+          ensure_dir(parent)
+          parent.create_child(entry.name)
+        end
+      end
+
+      def get_json(path, default_value)
+        entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
+        begin
+          Chef::JSONCompat.parse(entry.read)
+        rescue Chef::ChefFS::FileSystem::NotFoundError
+          default_value
+        end
+      end
+
+      def is_org?
+        repo_mode == "hosted_everything"
       end
     end
   end
diff --git a/lib/chef/chef_fs/command_line.rb b/lib/chef/chef_fs/command_line.rb
index 8a205ee..f3e6328 100644
--- a/lib/chef/chef_fs/command_line.rb
+++ b/lib/chef/chef_fs/command_line.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/util/diff'
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/operation_failed_error"
+require "chef/chef_fs/file_system/operation_not_allowed_error"
+require "chef/util/diff"
 
 class Chef
   module ChefFS
@@ -72,7 +72,7 @@ class Chef
             elsif old_value
               result = "diff --knife #{old_path} #{new_path}\n"
               result << "deleted file\n"
-              result << diff_text(old_path, '/dev/null', old_value, '')
+              result << diff_text(old_path, "/dev/null", old_value, "")
               yield result
             else
               yield "Only in #{format_path.call(old_entry.parent)}: #{old_entry.name}\n"
@@ -87,7 +87,7 @@ class Chef
             elsif new_value
               result = "diff --knife #{old_path} #{new_path}\n"
               result << "new file\n"
-              result << diff_text('/dev/null', new_path, '', new_value)
+              result << diff_text("/dev/null", new_path, "", new_value)
               yield result
             else
               yield "Only in #{format_path.call(new_entry.parent)}: #{new_entry.name}\n"
diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb
index 6666a3d..5eae050 100644
--- a/lib/chef/chef_fs/config.rb
+++ b/lib/chef/chef_fs/config.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/chef_fs/path_utils'
+require "chef/log"
+require "chef/chef_fs/path_utils"
 
 class Chef
   module ChefFS
@@ -33,6 +33,7 @@ class Chef
         "acls" => "acl",
         "clients" => "client",
         "cookbooks" => "cookbook",
+        "cookbook_artifacts" => "cookbook_artifact",
         "containers" => "container",
         "data_bags" => "data_bag",
         "environments" => "environment",
@@ -40,11 +41,39 @@ class Chef
         "nodes" => "node",
         "roles" => "role",
         "users" => "user",
-        "policies" => "policy"
+        "policies" => "policy",
+        "policy_groups" => "policy_group",
       }
-      INFLECTIONS.each { |k,v| k.freeze; v.freeze }
+      INFLECTIONS.each { |k, v| k.freeze; v.freeze }
       INFLECTIONS.freeze
 
+      # ChefFS supports three modes of operation: "static", "everything", and
+      # "hosted_everything". These names are antiquated since Chef 12 moved
+      # multi-tenant and RBAC to the open source product. In practice, they
+      # mean:
+      #
+      # * static: just static objects that are included in a traditional
+      #   chef-repo, with no support for anything introduced in Chef 12 or
+      #   later.
+      # * everything: all of the objects supported by the open source Chef
+      #   Server 11.x
+      # * hosted_everything: (the name comes from Hosted Chef) supports
+      #   everything in Chef Server 12 and later, including RBAC objects and
+      #   Policyfile objects.
+      #
+      # The "static" and "everything" modes are used for backup and
+      # upgrade/migration of older Chef Servers, so they should be considered
+      # frozen in time.
+
+      CHEF_11_OSS_STATIC_OBJECTS = %w{cookbooks cookbook_artifacts data_bags environments roles}.freeze
+      CHEF_11_OSS_DYNAMIC_OBJECTS = %w{clients nodes users}.freeze
+      RBAC_OBJECT_NAMES = %w{acls containers groups }.freeze
+      CHEF_12_OBJECTS = %w{ cookbook_artifacts policies policy_groups }.freeze
+
+      STATIC_MODE_OBJECT_NAMES = CHEF_11_OSS_STATIC_OBJECTS
+      EVERYTHING_MODE_OBJECT_NAMES = (CHEF_11_OSS_STATIC_OBJECTS + CHEF_11_OSS_DYNAMIC_OBJECTS).freeze
+      HOSTED_EVERYTHING_MODE_OBJECT_NAMES = (EVERYTHING_MODE_OBJECT_NAMES + RBAC_OBJECT_NAMES + CHEF_12_OBJECTS).freeze
+
       #
       # Create a new Config object which can produce a chef_fs and local_fs.
       #
@@ -111,10 +140,10 @@ class Chef
       #
       def initialize(chef_config = Chef::Config, cwd = Dir.pwd, options = {}, ui = nil)
         @chef_config = chef_config
-        @cwd = cwd
+        @cwd = File.expand_path(cwd)
         @cookbook_version = options[:cookbook_version]
 
-        if @chef_config[:repo_mode] == 'everything' && is_hosted? && !ui.nil?
+        if @chef_config[:repo_mode] == "everything" && is_hosted? && !ui.nil?
           ui.warn %Q{You have repo_mode set to 'everything', but your chef_server_url
               looks like it might be a hosted setup.  If this is the case please use
               hosted_everything or allow repo_mode to default}
@@ -122,9 +151,9 @@ class Chef
         # Default to getting *everything* from the server.
         if !@chef_config[:repo_mode]
           if is_hosted?
-            @chef_config[:repo_mode] = 'hosted_everything'
+            @chef_config[:repo_mode] = "hosted_everything"
           else
-            @chef_config[:repo_mode] = 'everything'
+            @chef_config[:repo_mode] = "everything"
           end
         end
       end
@@ -142,8 +171,8 @@ class Chef
       end
 
       def create_chef_fs
-        require 'chef/chef_fs/file_system/chef_server_root_dir'
-        Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version)
+        require "chef/chef_fs/file_system/chef_server/chef_server_root_dir"
+        Chef::ChefFS::FileSystem::ChefServer::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version)
       end
 
       def local_fs
@@ -151,8 +180,8 @@ class Chef
       end
 
       def create_local_fs
-        require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir'
-        Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths, Array(chef_config[:chef_repo_path]).flatten, @chef_config)
+        require "chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir"
+        Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemRootDir.new(object_paths, Array(chef_config[:chef_repo_path]).flatten, @chef_config)
       end
 
       # Returns the given real path's location relative to the server root.
@@ -166,61 +195,59 @@ class Chef
       # server_path('/home/jkeiser/chef_repo/cookbooks/blah') == '/cookbooks/blah'
       # server_path('/home/*/chef_repo/cookbooks/blah') == nil
       #
-      # If there are multiple paths (cookbooks, roles, data bags, etc. can all
-      # have separate paths), and cwd+the path reaches into one of them, we will
-      # return a path relative to that.  Otherwise we will return a path to
-      # chef_repo.
+      # If there are multiple different, manually specified paths to object locations
+      # (cookbooks, roles, data bags, etc. can all have separate paths), and cwd+the
+      # path reaches into one of them, we will return a path relative to the first
+      # one to match it.  Otherwise we expect the path provided to be to the chef
+      # repo path itself.  Paths that are not available on the server are not supported.
       #
       # Globs are allowed as well, but globs outside server paths are NOT
       # (presently) supported.  See above examples.  TODO support that.
       #
       # If the path does not reach into ANY specified directory, nil is returned.
       def server_path(file_path)
-        pwd = File.expand_path(Dir.pwd)
-        absolute_pwd = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd))
+        target_path = Chef::ChefFS::PathUtils.realest_path(file_path, @cwd)
 
         # Check all object paths (cookbooks_dir, data_bags_dir, etc.)
+        # These are either manually specified by the user or autogenerated relative
+        # to chef_repo_path.
         object_paths.each_pair do |name, paths|
           paths.each do |path|
-            realest_path = Chef::ChefFS::PathUtils.realest_path(path)
-            if PathUtils.descendant_of?(absolute_pwd, realest_path)
-              relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_pwd, realest_path)
-              return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}"
+            object_abs_path = Chef::ChefFS::PathUtils.realest_path(path, @cwd)
+            if relative_path = PathUtils.descendant_path(target_path, object_abs_path)
+              return Chef::ChefFS::PathUtils.join("/#{name}", relative_path)
             end
           end
         end
 
         # Check chef_repo_path
         Array(@chef_config[:chef_repo_path]).flatten.each do |chef_repo_path|
-          realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path)
-          if absolute_pwd == realest_chef_repo_path
-            return '/'
+          # We're using realest_path here but we really don't need to - we can just expand the
+          # path and use realpath because a repo_path if provided *must* exist.
+          realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path, @cwd)
+          if Chef::ChefFS::PathUtils.os_path_eq?(target_path, realest_chef_repo_path)
+            return "/"
           end
         end
 
         nil
       end
 
-      # The current directory, relative to server root
+      # The current directory, relative to server root.  This is a case-sensitive server path.
+      # It only exists if the current directory is a child of one of the recognized object_paths below.
       def base_path
-        @base_path ||= begin
-          if @chef_config[:chef_repo_path]
-            server_path(File.expand_path(@cwd))
-          else
-            nil
-          end
-        end
+        @base_path ||= server_path(@cwd)
       end
 
       # Print the given server path, relative to the current directory
       def format_path(entry)
         server_path = entry.path
-        if base_path && server_path[0,base_path.length] == base_path
+        if base_path && server_path[0, base_path.length] == base_path
           if server_path == base_path
             return "."
-          elsif server_path[base_path.length,1] == "/"
+          elsif server_path[base_path.length, 1] == "/"
             return server_path[base_path.length + 1, server_path.length - base_path.length - 1]
-          elsif base_path == "/" && server_path[0,1] == "/"
+          elsif base_path == "/" && server_path[0, 1] == "/"
             return server_path[1, server_path.length - 1]
           end
         end
@@ -233,12 +260,12 @@ class Chef
         @object_paths ||= begin
           result = {}
           case @chef_config[:repo_mode]
-          when 'static'
-            object_names = %w(cookbooks data_bags environments roles policies)
-          when 'hosted_everything'
-            object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles policies)
+          when "static"
+            object_names = STATIC_MODE_OBJECT_NAMES
+          when "hosted_everything"
+            object_names = HOSTED_EVERYTHING_MODE_OBJECT_NAMES
           else
-            object_names = %w(clients cookbooks data_bags environments nodes roles users policies)
+            object_names = EVERYTHING_MODE_OBJECT_NAMES
           end
           object_names.each do |object_name|
             # cookbooks -> cookbook_path
diff --git a/lib/chef/chef_fs/data_handler/acl_data_handler.rb b/lib/chef/chef_fs/data_handler/acl_data_handler.rb
index 8def8a5..91e4810 100644
--- a/lib/chef/chef_fs/data_handler/acl_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/acl_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
@@ -7,16 +7,16 @@ class Chef
         def normalize(acl, entry)
           # Normalize the order of the keys for easier reading
           result = normalize_hash(acl, {
-            'create' => {},
-            'read' => {},
-            'update' => {},
-            'delete' => {},
-            'grant' => {}
-            })
+            "create" => {},
+            "read" => {},
+            "update" => {},
+            "delete" => {},
+            "grant" => {},
+            },)
           result.keys.each do |key|
-            result[key] = normalize_hash(result[key], { 'actors' => [], 'groups' => [] })
-            result[key]['actors'] = result[key]['actors'].sort
-            result[key]['groups'] = result[key]['groups'].sort
+            result[key] = normalize_hash(result[key], { "actors" => [], "groups" => [] })
+            result[key]["actors"] = result[key]["actors"].sort
+            result[key]["groups"] = result[key]["groups"].sort
           end
           result
         end
diff --git a/lib/chef/chef_fs/data_handler/client_data_handler.rb b/lib/chef/chef_fs/data_handler/client_data_handler.rb
index d81f35e..5e12003 100644
--- a/lib/chef/chef_fs/data_handler/client_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/client_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/api_client'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/api_client"
 
 class Chef
   module ChefFS
@@ -7,23 +7,25 @@ class Chef
       class ClientDataHandler < DataHandlerBase
         def normalize(client, entry)
           defaults = {
-            'name' => remove_dot_json(entry.name),
-            'clientname' => remove_dot_json(entry.name),
-            'admin' => false,
-            'validator' => false,
-            'chef_type' => 'client'
+            "name" => remove_dot_json(entry.name),
+            "clientname" => remove_dot_json(entry.name),
+            "admin" => false,
+            "validator" => false,
+            "chef_type" => "client",
           }
+          # Handle the fact that admin/validator have changed type from string -> boolean
+          client["admin"] = (client["admin"] == "true") if client["admin"].is_a?(String)
+          client["validator"] = (client["validator"] == "true") if client["validator"].is_a?(String)
           if entry.respond_to?(:org) && entry.org
-            defaults['orgname'] = entry.org
+            defaults["orgname"] = entry.org
           end
           result = normalize_hash(client, defaults)
-          # You can NOT send json_class, or it will fail
-          result.delete('json_class')
+          result.delete("json_class")
           result
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def chef_class
diff --git a/lib/chef/chef_fs/data_handler/container_data_handler.rb b/lib/chef/chef_fs/data_handler/container_data_handler.rb
index 980453c..d1e8d2f 100644
--- a/lib/chef/chef_fs/data_handler/container_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/container_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
@@ -6,18 +6,18 @@ class Chef
       class ContainerDataHandler < DataHandlerBase
         def normalize(container, entry)
           normalize_hash(container, {
-            'containername' => remove_dot_json(entry.name),
-            'containerpath' => remove_dot_json(entry.name)
-          })
+            "containername" => remove_dot_json(entry.name),
+            "containerpath" => remove_dot_json(entry.name),
+          },)
         end
 
         def preserve_key?(key)
-          return key == 'containername'
+          return key == "containername"
         end
 
         def verify_integrity(object, entry, &on_error)
           base_name = remove_dot_json(entry.name)
-          if object['containername'] != base_name
+          if object["containername"] != base_name
             on_error.call("Name in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['name']}')")
           end
         end
diff --git a/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb b/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
index 56b7e0b..f75f96f 100644
--- a/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/cookbook/metadata'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/cookbook/metadata"
 
 class Chef
   module ChefFS
@@ -9,22 +9,22 @@ class Chef
           version = entry.name
           name = entry.parent.name
           result = normalize_hash(cookbook, {
-            'name' => "#{name}-#{version}",
-            'version' => version,
-            'cookbook_name' => name,
-            'json_class' => 'Chef::CookbookVersion',
-            'chef_type' => 'cookbook_version',
-            'frozen?' => false,
-            'metadata' => {}
-          })
-          result['metadata'] = normalize_hash(result['metadata'], {
-            'version' => version,
-            'name' => name
-          })
+            "name" => "#{name}-#{version}",
+            "version" => version,
+            "cookbook_name" => name,
+            "json_class" => "Chef::CookbookVersion",
+            "chef_type" => "cookbook_version",
+            "frozen?" => false,
+            "metadata" => {},
+          },)
+          result["metadata"] = normalize_hash(result["metadata"], {
+            "version" => version,
+            "name" => name,
+          },)
         end
 
         def preserve_key?(key)
-          return key == 'cookbook_name' || key == 'version'
+          return key == "cookbook_name" || key == "version"
         end
 
         def chef_class
diff --git a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
index 1306922..d56f662 100644
--- a/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/data_bag_item'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/data_bag_item"
 
 class Chef
   module ChefFS
@@ -7,26 +7,26 @@ class Chef
       class DataBagItemDataHandler < DataHandlerBase
         def normalize(data_bag_item, entry)
           # If it's wrapped with raw_data, unwrap it.
-          if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
-            data_bag_item = data_bag_item['raw_data']
+          if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"]
+            data_bag_item = data_bag_item["raw_data"]
           end
           # chef_type and data_bag come back in PUT and POST results, but we don't
           # use those in knife-essentials.
           normalize_hash(data_bag_item, {
-            'id' => remove_dot_json(entry.name)
-          })
+            "id" => remove_dot_json(entry.name)
+          },)
         end
 
         def normalize_for_post(data_bag_item, entry)
-          if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data']
-            data_bag_item = data_bag_item['raw_data']
+          if data_bag_item["json_class"] == "Chef::DataBagItem" && data_bag_item["raw_data"]
+            data_bag_item = data_bag_item["raw_data"]
           end
           {
             "name" => "data_bag_item_#{entry.parent.name}_#{remove_dot_json(entry.name)}",
             "json_class" => "Chef::DataBagItem",
             "chef_type" => "data_bag_item",
             "data_bag" => entry.parent.name,
-            "raw_data" => normalize(data_bag_item, entry)
+            "raw_data" => normalize(data_bag_item, entry),
           }
         end
 
@@ -35,7 +35,7 @@ class Chef
         end
 
         def preserve_key?(key)
-          return key == 'id'
+          return key == "id"
         end
 
         def chef_class
@@ -44,7 +44,7 @@ class Chef
 
         def verify_integrity(object, entry, &on_error)
           base_name = remove_dot_json(entry.name)
-          if object['raw_data']['id'] != base_name
+          if object["raw_data"]["id"] != base_name
             on_error.call("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')")
           end
         end
diff --git a/lib/chef/chef_fs/data_handler/data_handler_base.rb b/lib/chef/chef_fs/data_handler/data_handler_base.rb
index a3dc924..83f56ed 100644
--- a/lib/chef/chef_fs/data_handler/data_handler_base.rb
+++ b/lib/chef/chef_fs/data_handler/data_handler_base.rb
@@ -28,10 +28,10 @@ class Chef
         # Takes a name like blah.json and removes the .json from it.
         #
         def remove_dot_json(name)
-          if name.length < 5 || name[-5,5] != ".json"
+          if name.length < 5 || name[-5, 5] != ".json"
             raise "Invalid name #{path}: must end in .json"
           end
-          name[0,name.length-5]
+          name[0, name.length - 5]
         end
 
         #
@@ -94,7 +94,7 @@ class Chef
         # name to recipe[name].  Then calls uniq on the result.
         #
         def normalize_run_list(run_list)
-          run_list.map{|item|
+          run_list.map {|item|
             case item.to_s
             when /^recipe\[.*\]$/
               item # explicit recipe
@@ -117,7 +117,7 @@ class Chef
         # Turn a JSON hash into a bona fide Chef object (like Chef::Node).
         #
         def chef_object(object)
-          chef_class.json_create(object)
+          chef_class.from_hash(object)
         end
 
         #
@@ -147,18 +147,18 @@ class Chef
         #   environment "desert"'
         #
         def to_ruby_keys(object, keys)
-          result = ''
+          result = ""
           keys.each do |key|
             if object[key]
               if object[key].is_a?(Hash)
                 if object[key].size > 0
                   result << key
                   first = true
-                  object[key].each_pair do |k,v|
+                  object[key].each_pair do |k, v|
                     if first
                       first = false
                     else
-                      result << ' '*key.length
+                      result << " " * key.length
                     end
                     result << " #{k.inspect} => #{v.inspect}\n"
                   end
@@ -191,7 +191,7 @@ class Chef
         #
         def verify_integrity(object, entry, &on_error)
           base_name = remove_dot_json(entry.name)
-          if object['name'] != base_name
+          if object["name"] != base_name
             on_error.call("Name must be '#{base_name}' (is '#{object['name']}')")
           end
         end
diff --git a/lib/chef/chef_fs/data_handler/environment_data_handler.rb b/lib/chef/chef_fs/data_handler/environment_data_handler.rb
index 5105f2a..3b9d5b4 100644
--- a/lib/chef/chef_fs/data_handler/environment_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/environment_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/environment'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/environment"
 
 class Chef
   module ChefFS
@@ -7,18 +7,18 @@ class Chef
       class EnvironmentDataHandler < DataHandlerBase
         def normalize(environment, entry)
           normalize_hash(environment, {
-            'name' => remove_dot_json(entry.name),
-            'description' => '',
-            'cookbook_versions' => {},
-            'default_attributes' => {},
-            'override_attributes' => {},
-            'json_class' => 'Chef::Environment',
-            'chef_type' => 'environment'
-          })
+            "name" => remove_dot_json(entry.name),
+            "description" => "",
+            "cookbook_versions" => {},
+            "default_attributes" => {},
+            "override_attributes" => {},
+            "json_class" => "Chef::Environment",
+            "chef_type" => "environment",
+          },)
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def chef_class
@@ -26,9 +26,9 @@ class Chef
         end
 
         def to_ruby(object)
-          result = to_ruby_keys(object, %w(name description default_attributes override_attributes))
-          if object['cookbook_versions']
-            object['cookbook_versions'].each_pair do |name, version|
+          result = to_ruby_keys(object, %w{name description default_attributes override_attributes})
+          if object["cookbook_versions"]
+            object["cookbook_versions"].each_pair do |name, version|
               result << "cookbook #{name.inspect}, #{version.inspect}"
             end
           end
diff --git a/lib/chef/chef_fs/data_handler/group_data_handler.rb b/lib/chef/chef_fs/data_handler/group_data_handler.rb
index 1a36c66..7f38784 100644
--- a/lib/chef/chef_fs/data_handler/group_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/group_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/api_client'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/api_client"
 
 class Chef
   module ChefFS
@@ -7,32 +7,32 @@ class Chef
       class GroupDataHandler < DataHandlerBase
         def normalize(group, entry)
           defaults = {
-            'name' => remove_dot_json(entry.name),
-            'groupname' => remove_dot_json(entry.name),
-            'users' => [],
-            'clients' => [],
-            'groups' => [],
+            "name" => remove_dot_json(entry.name),
+            "groupname" => remove_dot_json(entry.name),
+            "users" => [],
+            "clients" => [],
+            "groups" => [],
           }
           if entry.org
-            defaults['orgname'] = entry.org
+            defaults["orgname"] = entry.org
           end
           result = normalize_hash(group, defaults)
-          if result['actors'] && result['actors'].sort.uniq == (result['users'] + result['clients']).sort.uniq
-            result.delete('actors')
+          if result["actors"] && result["actors"].sort.uniq == (result["users"] + result["clients"]).sort.uniq
+            result.delete("actors")
           end
           result
         end
 
         def normalize_for_put(group, entry)
           result = super(group, entry)
-          result['actors'] = {
-            'users' => result['users'],
-            'clients' => result['clients'],
-            'groups' => result['groups']
+          result["actors"] = {
+            "users" => result["users"],
+            "clients" => result["clients"],
+            "groups" => result["groups"],
           }
-          result.delete('users')
-          result.delete('clients')
-          result.delete('groups')
+          result.delete("users")
+          result.delete("clients")
+          result.delete("groups")
           result
         end
 
@@ -41,7 +41,7 @@ class Chef
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def chef_class
diff --git a/lib/chef/chef_fs/data_handler/node_data_handler.rb b/lib/chef/chef_fs/data_handler/node_data_handler.rb
index 04faa52..fcec74d 100644
--- a/lib/chef/chef_fs/data_handler/node_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/node_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/node'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/node"
 
 class Chef
   module ChefFS
@@ -7,22 +7,22 @@ class Chef
       class NodeDataHandler < DataHandlerBase
         def normalize(node, entry)
           result = normalize_hash(node, {
-            'name' => remove_dot_json(entry.name),
-            'json_class' => 'Chef::Node',
-            'chef_type' => 'node',
-            'chef_environment' => '_default',
-            'override' => {},
-            'normal' => {},
-            'default' => {},
-            'automatic' => {},
-            'run_list' => []
-          })
-          result['run_list'] = normalize_run_list(result['run_list'])
+            "name" => remove_dot_json(entry.name),
+            "json_class" => "Chef::Node",
+            "chef_type" => "node",
+            "chef_environment" => "_default",
+            "override" => {},
+            "normal" => {},
+            "default" => {},
+            "automatic" => {},
+            "run_list" => [],
+          },)
+          result["run_list"] = normalize_run_list(result["run_list"])
           result
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def chef_class
diff --git a/lib/chef/chef_fs/data_handler/organization_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_data_handler.rb
index da911c0..d9f97b2 100644
--- a/lib/chef/chef_fs/data_handler/organization_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
@@ -6,21 +6,21 @@ class Chef
       class OrganizationDataHandler < DataHandlerBase
         def normalize(organization, entry)
           result = normalize_hash(organization, {
-            'name' => entry.org,
-            'full_name' => entry.org,
-            'org_type' => 'Business',
-            'clientname' => "#{entry.org}-validator",
-            'billing_plan' => 'platform-free',
-          })
+            "name" => entry.org,
+            "full_name" => entry.org,
+            "org_type" => "Business",
+            "clientname" => "#{entry.org}-validator",
+            "billing_plan" => "platform-free",
+          },)
           result
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def verify_integrity(object, entry, &on_error)
-          if entry.org != object['name']
+          if entry.org != object["name"]
             on_error.call("Name must be '#{entry.org}' (is '#{object['name']}')")
           end
         end
diff --git a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
index db56ecc..c5a5f87 100644
--- a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
@@ -1,11 +1,11 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
     module DataHandler
       class OrganizationInvitesDataHandler < DataHandlerBase
         def normalize(invites, entry)
-          invites.map { |invite| invite.is_a?(Hash) ? invite['username'] : invite }.sort.uniq
+          invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.sort.uniq
         end
 
         def minimize(invites, entry)
diff --git a/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
index afa3317..8e452a4 100644
--- a/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
@@ -1,11 +1,11 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
     module DataHandler
       class OrganizationMembersDataHandler < DataHandlerBase
         def normalize(members, entry)
-          members.map { |member| member.is_a?(Hash) ? member['user']['username'] : member }.sort.uniq
+          members.map { |member| member.is_a?(Hash) ? member["user"]["username"] : member }.sort.uniq
         end
 
         def minimize(members, entry)
diff --git a/lib/chef/chef_fs/data_handler/policy_data_handler.rb b/lib/chef/chef_fs/data_handler/policy_data_handler.rb
index 769c13c..477d2bf 100644
--- a/lib/chef/chef_fs/data_handler/policy_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/policy_data_handler.rb
@@ -1,15 +1,42 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
     module DataHandler
       class PolicyDataHandler < DataHandlerBase
+        def name_and_revision(name)
+          # foo-1.0.0 = foo, 1.0.0
+          name = remove_dot_json(name)
+          if name =~ /^(.*)-([^-]*)$/
+            name, revision_id = $1, $2
+          end
+          revision_id ||= "0.0.0"
+          [ name, revision_id ]
+        end
 
         def normalize(policy, entry)
-          policy
+          # foo-1.0.0 = foo, 1.0.0
+          name, revision_id = name_and_revision(entry.name)
+          defaults = {
+            "name" => name,
+            "revision_id" => revision_id,
+            "run_list" => [],
+            "cookbook_locks" => {},
+          }
+          normalize_hash(policy, defaults)
+        end
+
+        def verify_integrity(object_data, entry, &on_error)
+          name, revision = name_and_revision(entry.name)
+          if object_data["name"] != name
+            on_error.call("Object name '#{object_data['name']}' doesn't match entry '#{entry.name}'.")
+          end
+
+          if object_data["revision_id"] != revision
+            on_error.call("Object revision ID '#{object_data['revision']}' doesn't match entry '#{entry.name}'.")
+          end
         end
       end
     end
   end
 end
-
diff --git a/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb b/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb
new file mode 100644
index 0000000..e5c430a
--- /dev/null
+++ b/lib/chef/chef_fs/data_handler/policy_group_data_handler.rb
@@ -0,0 +1,27 @@
+require "chef/chef_fs/data_handler/data_handler_base"
+
+class Chef
+  module ChefFS
+    module DataHandler
+      class PolicyGroupDataHandler < DataHandlerBase
+
+        def normalize(policy_group, entry)
+          defaults = {
+            "name" => remove_dot_json(entry.name),
+            "policies" => {},
+          }
+          result = normalize_hash(policy_group, defaults)
+          result.delete("uri") # not useful data
+          result
+        end
+
+        def verify_integrity(object_data, entry, &on_error)
+          if object_data["policies"].empty?
+            on_error.call("Policy group #{object_data["name"]} does not have any policies in it.")
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/data_handler/role_data_handler.rb b/lib/chef/chef_fs/data_handler/role_data_handler.rb
index 21c3013..eb10f7b 100644
--- a/lib/chef/chef_fs/data_handler/role_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/role_data_handler.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
-require 'chef/role'
+require "chef/chef_fs/data_handler/data_handler_base"
+require "chef/role"
 
 class Chef
   module ChefFS
@@ -7,24 +7,24 @@ class Chef
       class RoleDataHandler < DataHandlerBase
         def normalize(role, entry)
           result = normalize_hash(role, {
-            'name' => remove_dot_json(entry.name),
-            'description' => '',
-            'json_class' => 'Chef::Role',
-            'chef_type' => 'role',
-            'default_attributes' => {},
-            'override_attributes' => {},
-            'run_list' => [],
-            'env_run_lists' => {}
-          })
-          result['run_list'] = normalize_run_list(result['run_list'])
-          result['env_run_lists'].each_pair do |env, run_list|
-            result['env_run_lists'][env] = normalize_run_list(run_list)
+            "name" => remove_dot_json(entry.name),
+            "description" => "",
+            "json_class" => "Chef::Role",
+            "chef_type" => "role",
+            "default_attributes" => {},
+            "override_attributes" => {},
+            "run_list" => [],
+            "env_run_lists" => {},
+          },)
+          result["run_list"] = normalize_run_list(result["run_list"])
+          result["env_run_lists"].each_pair do |env, run_list|
+            result["env_run_lists"][env] = normalize_run_list(run_list)
           end
           result
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         def chef_class
@@ -32,7 +32,7 @@ class Chef
         end
 
         def to_ruby(object)
-          to_ruby_keys(object, %w(name description default_attributes override_attributes run_list env_run_lists))
+          to_ruby_keys(object, %w{name description default_attributes override_attributes run_list env_run_lists})
         end
       end
     end
diff --git a/lib/chef/chef_fs/data_handler/user_data_handler.rb b/lib/chef/chef_fs/data_handler/user_data_handler.rb
index f6859fa..392e67f 100644
--- a/lib/chef/chef_fs/data_handler/user_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/user_data_handler.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/data_handler/data_handler_base'
+require "chef/chef_fs/data_handler/data_handler_base"
 
 class Chef
   module ChefFS
@@ -6,20 +6,20 @@ class Chef
       class UserDataHandler < DataHandlerBase
         def normalize(user, entry)
           normalize_hash(user, {
-            'name' => remove_dot_json(entry.name),
-            'username' => remove_dot_json(entry.name),
-            'display_name' => remove_dot_json(entry.name),
-            'admin' => false,
-            'json_class' => 'Chef::WebUIUser',
-            'chef_type' => 'webui_user',
-            'salt' => nil,
-            'password' => nil,
-            'openid' => nil
-          })
+            "name" => remove_dot_json(entry.name),
+            "username" => remove_dot_json(entry.name),
+            "display_name" => remove_dot_json(entry.name),
+            "admin" => false,
+            "json_class" => "Chef::WebUIUser",
+            "chef_type" => "webui_user",
+            "salt" => nil,
+            "password" => nil,
+            "openid" => nil,
+          },)
         end
 
         def preserve_key?(key)
-          return key == 'name'
+          return key == "name"
         end
 
         # There is no chef_class for users, nor does to_ruby work.
diff --git a/lib/chef/chef_fs/file_pattern.rb b/lib/chef/chef_fs/file_pattern.rb
index 134d22c..5beec6d 100644
--- a/lib/chef/chef_fs/file_pattern.rb
+++ b/lib/chef/chef_fs/file_pattern.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs'
-require 'chef/chef_fs/path_utils'
+require "chef/chef_fs"
+require "chef/chef_fs/path_utils"
 
 class Chef
   module ChefFS
@@ -70,17 +70,17 @@ class Chef
       #   abc/def.could_match_children?('x') == false
       #   a**z.could_match_children?('ab/cd') == true
       def could_match_children?(path)
-        return false if path == '' # Empty string is not a path
+        return false if path == "" # Empty string is not a path
 
-        argument_is_absolute = !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/)
+        argument_is_absolute = Chef::ChefFS::PathUtils::is_absolute?(path)
         return false if is_absolute != argument_is_absolute
-        path = path[1,path.length-1] if argument_is_absolute
+        path = path[1, path.length - 1] if argument_is_absolute
 
         path_parts = Chef::ChefFS::PathUtils::split(path)
         # If the pattern is shorter than the path (or same size), children will be larger than the pattern, and will not match.
         return false if regexp_parts.length <= path_parts.length && !has_double_star
         # If the path doesn't match up to this point, children won't match either.
-        return false if path_parts.zip(regexp_parts).any? { |part,regexp| !regexp.nil? && !regexp.match(part) }
+        return false if path_parts.zip(regexp_parts).any? { |part, regexp| !regexp.nil? && !regexp.match(part) }
         # Otherwise, it's possible we could match: the path matches to this point, and the pattern is longer than the path.
         # TODO There is one edge case where the double star comes after some characters like abc**def--we could check whether the next
         # bit of path starts with abc in that case.
@@ -111,7 +111,7 @@ class Chef
       #
       # This method assumes +could_match_children?(path)+ is +true+.
       def exact_child_name_under(path)
-        path = path[1,path.length-1] if !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/)
+        path = path[1, path.length - 1] if Chef::ChefFS::PathUtils::is_absolute?(path)
         dirs_in_path = Chef::ChefFS::PathUtils::split(path).length
         return nil if exact_parts.length <= dirs_in_path
         return exact_parts[dirs_in_path]
@@ -125,7 +125,7 @@ class Chef
       def exact_path
         return nil if has_double_star || exact_parts.any? { |part| part.nil? }
         result = Chef::ChefFS::PathUtils::join(*exact_parts)
-        is_absolute ? Chef::ChefFS::PathUtils::join('', result) : result
+        is_absolute ? Chef::ChefFS::PathUtils::join("", result) : result
       end
 
       # Returns the normalized version of the pattern, with / as the directory
@@ -149,9 +149,9 @@ class Chef
       #   abc/*/def.match?('abc/foo/def') == true
       #   abc/*/def.match?('abc/foo') == false
       def match?(path)
-        argument_is_absolute = !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/)
+        argument_is_absolute = Chef::ChefFS::PathUtils::is_absolute?(path)
         return false if is_absolute != argument_is_absolute
-        path = path[1,path.length-1] if argument_is_absolute
+        path = path[1, path.length - 1] if argument_is_absolute
         !!regexp.match(path)
       end
 
@@ -160,17 +160,6 @@ class Chef
         pattern
       end
 
-      # Given a relative file pattern and a directory, makes a new file pattern
-      # starting with the directory.
-      #
-      #   FilePattern.relative_to('/usr/local', 'bin/*grok') == FilePattern.new('/usr/local/bin/*grok')
-      #
-      # BUG: this does not support patterns starting with <tt>..</tt>
-      def self.relative_to(dir, pattern)
-        return FilePattern.new(pattern) if pattern =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/
-        FilePattern.new(Chef::ChefFS::PathUtils::join(dir, pattern))
-      end
-
     private
 
       def regexp
@@ -195,7 +184,7 @@ class Chef
 
       def calculate
         if !@regexp
-          @is_absolute = !!(@pattern =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/)
+          @is_absolute = Chef::ChefFS::PathUtils::is_absolute?(@pattern)
 
           full_regexp_parts = []
           normalized_parts = []
@@ -210,12 +199,12 @@ class Chef
             end
 
             # Skip // and /./ (pretend it's not there)
-            if exact == '' || exact == '.'
+            if exact == "" || exact == "."
               next
             end
 
             # Back up when you see .. (unless the prior part has ** in it, in which case .. must be preserved)
-            if exact == '..'
+            if exact == ".."
               if @is_absolute && normalized_parts.length == 0
                 # If we are at the root, just pretend the .. isn't there
                 next
@@ -245,7 +234,7 @@ class Chef
 
           @regexp = Regexp.new("^#{full_regexp_parts.join(Chef::ChefFS::PathUtils::regexp_path_separator)}$")
           @normalized_pattern = Chef::ChefFS::PathUtils.join(*normalized_parts)
-          @normalized_pattern = Chef::ChefFS::PathUtils.join('', @normalized_pattern) if @is_absolute
+          @normalized_pattern = Chef::ChefFS::PathUtils.join("", @normalized_pattern) if @is_absolute
         end
       end
 
@@ -260,7 +249,7 @@ class Chef
       end
 
       def self.regexp_escape_characters
-        [ '[', '\\', '^', '$', '.', '|', '?', '*', '+', '(', ')', '{', '}' ]
+        [ "[", '\\', "^", "$", ".", "|", "?", "*", "+", "(", ")", "{", "}" ]
       end
 
       def self.pattern_to_regexp(pattern)
@@ -269,32 +258,32 @@ class Chef
         has_double_star = false
         pattern.split(pattern_special_characters).each_with_index do |part, index|
           # Odd indexes from the split are symbols.  Even are normal bits.
-          if index % 2 == 0
+          if index.even?
             exact << part if !exact.nil?
             regexp << part
           else
             case part
             # **, * and ? happen on both platforms.
-            when '**'
+            when "**"
               exact = nil
               has_double_star = true
-              regexp << '.*'
-            when '*'
+              regexp << ".*"
+            when "*"
               exact = nil
               regexp << '[^\/]*'
-            when '?'
+            when "?"
               exact = nil
-              regexp << '.'
+              regexp << "."
             else
-              if part[0,1] == '\\' && part.length == 2
+              if part[0, 1] == '\\' && part.length == 2
                 # backslash escapes are only supported on Unix, and are handled here by leaving the escape on (it means the same thing in a regex)
-                exact << part[1,1] if !exact.nil?
-                if regexp_escape_characters.include?(part[1,1])
+                exact << part[1, 1] if !exact.nil?
+                if regexp_escape_characters.include?(part[1, 1])
                   regexp << part
                 else
-                  regexp << part[1,1]
+                  regexp << part[1, 1]
                 end
-              elsif part[0,1] == '[' && part.length > 1
+              elsif part[0, 1] == "[" && part.length > 1
                 # [...] happens only on Unix, and is handled here by *not* backslashing (it means the same thing in and out of regex)
                 exact = nil
                 regexp << part
diff --git a/lib/chef/chef_fs/file_system.rb b/lib/chef/chef_fs/file_system.rb
index 3ab5904..5865dd4 100644
--- a/lib/chef/chef_fs/file_system.rb
+++ b/lib/chef/chef_fs/file_system.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/path_utils'
-require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/chef_fs/parallelizer'
+require "chef/chef_fs/path_utils"
+require "chef/chef_fs/file_system/default_environment_cannot_be_modified_error"
+require "chef/chef_fs/file_system/operation_failed_error"
+require "chef/chef_fs/file_system/operation_not_allowed_error"
+require "chef/chef_fs/parallelizer"
 
 class Chef
   module ChefFS
@@ -95,9 +95,9 @@ class Chef
       #
       def self.resolve_path(entry, path)
         return entry if path.length == 0
-        return resolve_path(entry.root, path) if path[0,1] == "/" && entry.root != entry
-        if path[0,1] == "/"
-          path = path[1,path.length-1]
+        return resolve_path(entry.root, path) if path[0, 1] == "/" && entry.root != entry
+        if path[0, 1] == "/"
+          path = path[1, path.length - 1]
         end
 
         result = entry
diff --git a/lib/chef/chef_fs/file_system/acl_dir.rb b/lib/chef/chef_fs/file_system/acl_dir.rb
deleted file mode 100644
index c2354d4..0000000
--- a/lib/chef/chef_fs/file_system/acl_dir.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class AclDir < BaseFSDir
-        def api_path
-          parent.parent.child(name).api_path
-        end
-
-        def child(name)
-          result = @children.select { |child| child.name == name }.first if @children
-          result ||= can_have_child?(name, false) ?
-                     AclEntry.new(name, self) : NonexistentFSObject.new(name, self)
-        end
-
-        def can_have_child?(name, is_dir)
-          name =~ /\.json$/ && !is_dir
-        end
-
-        def children
-          if @children.nil?
-            # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names
-            names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name }
-            @children = names.map { |name| AclEntry.new(name, self, true) }
-          end
-          @children
-        end
-
-        def create_child(name, file_contents)
-          raise OperationNotAllowedError.new(:create_child, self), "ACLs can only be updated, and can only be created when the corresponding object is created."
-        end
-
-        def data_handler
-          parent.data_handler
-        end
-
-        def rest
-          parent.rest
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/acl_entry.rb b/lib/chef/chef_fs/file_system/acl_entry.rb
deleted file mode 100644
index b2545af..0000000
--- a/lib/chef/chef_fs/file_system/acl_entry.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class AclEntry < RestListEntry
-        PERMISSIONS = %w(create read update delete grant)
-
-        def api_path
-          "#{super}/_acl"
-        end
-
-        def delete(recurse)
-          raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self), "ACLs cannot be deleted."
-        end
-
-        def write(file_contents)
-          # ACL writes are fun.
-          acls = data_handler.normalize(Chef::JSONCompat.parse(file_contents), self)
-          PERMISSIONS.each do |permission|
-            begin
-              rest.put("#{api_path}/#{permission}", { permission => acls[permission] })
-            rescue Timeout::Error => e
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
-            rescue Net::HTTPServerException => e
-              if e.response.code == "404"
-                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-              else
-                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/acls_dir.rb b/lib/chef/chef_fs/file_system/acls_dir.rb
deleted file mode 100644
index 938bf73..0000000
--- a/lib/chef/chef_fs/file_system/acls_dir.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/acl_dir'
-require 'chef/chef_fs/file_system/cookbooks_acl_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-require 'chef/chef_fs/data_handler/acl_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class AclsDir < BaseFSDir
-        ENTITY_TYPES = %w(clients containers cookbooks data_bags environments groups nodes roles) # we don't read sandboxes, so we don't read their acls
-
-        def initialize(parent)
-          super('acls', parent)
-        end
-
-        def data_handler
-          @data_handler ||= Chef::ChefFS::DataHandler::AclDataHandler.new
-        end
-
-        def api_path
-          parent.api_path
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir ? ENTITY_TYPES.include(name) : name == 'organization.json'
-        end
-
-        def children
-          if @children.nil?
-            @children = ENTITY_TYPES.map do |entity_type|
-              case entity_type
-              when 'cookbooks'
-                CookbooksAclDir.new(entity_type, self)
-              else
-                AclDir.new(entity_type, self)
-              end
-            end
-            @children << AclEntry.new('organization.json', self, true) # the org acl is retrieved as GET /organizations/ORGNAME/ANYTHINGATALL/_acl
-          end
-          @children
-        end
-
-        def rest
-          parent.rest
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/already_exists_error.rb b/lib/chef/chef_fs/file_system/already_exists_error.rb
index bf8994f..92ec915 100644
--- a/lib/chef/chef_fs/file_system/already_exists_error.rb
+++ b/lib/chef/chef_fs/file_system/already_exists_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/operation_failed_error'
+require "chef/chef_fs/file_system/operation_failed_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class AlreadyExistsError < OperationFailedError
-        def initialize(operation, entry, cause = nil)
-          super(operation, entry, cause)
-        end
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/base_fs_dir.rb b/lib/chef/chef_fs/file_system/base_fs_dir.rb
index 8cc277f..2827e5b 100644
--- a/lib/chef/chef_fs/file_system/base_fs_dir.rb
+++ b/lib/chef/chef_fs/file_system/base_fs_dir.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
 
 class Chef
   module ChefFS
@@ -31,11 +31,6 @@ class Chef
           true
         end
 
-        # Override child(name) to provide a child object by name without the network read
-        def child(name)
-          children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self)
-        end
-
         def can_have_child?(name, is_dir)
           true
         end
diff --git a/lib/chef/chef_fs/file_system/base_fs_object.rb b/lib/chef/chef_fs/file_system/base_fs_object.rb
index 43e6a51..19f98f2 100644
--- a/lib/chef/chef_fs/file_system/base_fs_object.rb
+++ b/lib/chef/chef_fs/file_system/base_fs_object.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/path_utils'
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
+require "chef/chef_fs/path_utils"
+require "chef/chef_fs/file_system/operation_not_allowed_error"
 
 class Chef
   module ChefFS
@@ -29,10 +29,10 @@ class Chef
           if parent
             @path = Chef::ChefFS::PathUtils::join(parent.path, name)
           else
-            if name != ''
+            if name != ""
               raise ArgumentError, "Name of root object must be empty string: was '#{name}' instead"
             end
-            @path = '/'
+            @path = "/"
           end
         end
 
@@ -95,7 +95,10 @@ class Chef
         # directly perform a network request to retrieve the y.json data bag.  No
         # network request was necessary to retrieve
         def child(name)
-          NonexistentFSObject.new(name, self)
+          if can_have_child?(name, true) || can_have_child?(name, false)
+            result = make_child_entry(name)
+          end
+          result || NonexistentFSObject.new(name, self)
         end
 
         # Override children to report your *actual* list of children as an array.
@@ -143,7 +146,7 @@ class Chef
         def path_for_printing
           if parent
             parent_path = parent.path_for_printing
-            if parent_path == '.'
+            if parent_path == "."
               name
             else
               Chef::ChefFS::PathUtils::join(parent.path_for_printing, name)
@@ -171,10 +174,10 @@ class Chef
 
         # Important directory attributes: name, parent, path, root
         # Overridable attributes: dir?, child(name), path_for_printing
-        # Abstract: read, write, delete, children, can_have_child?, create_child, compare_to
+        # Abstract: read, write, delete, children, can_have_child?, create_child, compare_to, make_child_entry
       end # class BaseFsObject
     end
   end
 end
 
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/nonexistent_fs_object"
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
deleted file mode 100644
index 7d2a930..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/acls_dir'
-require 'chef/chef_fs/data_handler/acl_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry
-        def initialize(name, parent, path = nil)
-          super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new)
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir ? Chef::ChefFS::FileSystem::AclsDir::ENTITY_TYPES.include?(name) : name == 'organization.json'
-        end
-      end
-    end
-  end
-end
\ No newline at end of file
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
deleted file mode 100644
index a7f1d73..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry'
-require 'chef/chef_fs/file_system/cookbook_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/cookbook_version_loader'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class ChefRepositoryFileSystemCookbookDir < ChefRepositoryFileSystemCookbookEntry
-        def initialize(name, parent, file_path = nil)
-          super(name, parent, file_path)
-        end
-
-        def chef_object
-          begin
-            loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
-            # We need the canonical cookbook name if we are using versioned cookbooks, but we don't
-            # want to spend a lot of time adding code to the main Chef libraries
-            if root.versioned_cookbooks
-              canonical_name = canonical_cookbook_name(File.basename(file_path))
-              fail "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z"  unless canonical_name
-
-              # KLUDGE: We shouldn't have to use instance_variable_set
-              loader.instance_variable_set(:@cookbook_name, canonical_name)
-            end
-
-            loader.load_cookbooks
-            cb = loader.cookbook_version
-            if !cb
-              Chef::Log.error("Cookbook #{file_path} empty.")
-              raise "Cookbook #{file_path} empty."
-            end
-            cb
-          rescue => e
-            Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{e}")
-            Chef::Log.error(e.backtrace.join("\n"))
-            raise
-          end
-        end
-
-        def children
-          begin
-            Dir.entries(file_path).sort.
-                select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
-                map { |child_name| make_child(child_name) }.
-                select { |entry| !(entry.dir? && entry.children.size == 0) }
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          if is_dir
-            # Only the given directories will be uploaded.
-            return CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != 'root_files'
-          elsif name == Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE
-            return false
-          end
-          super(name, is_dir)
-        end
-
-        # Exposed as a class method so that it can be used elsewhere
-        def self.canonical_cookbook_name(entry_name)
-          name_match = Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME.match(entry_name)
-          return nil if name_match.nil?
-          return name_match[1]
-        end
-
-        def canonical_cookbook_name(entry_name)
-          self.class.canonical_cookbook_name(entry_name)
-        end
-
-        def uploaded_cookbook_version_path
-          File.join(file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
-        end
-
-        def can_upload?
-          File.exists?(uploaded_cookbook_version_path) || children.size > 0
-        end
-
-        protected
-
-        def make_child(child_name)
-          segment_info = CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
-          ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
deleted file mode 100644
index 66709cc..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class ChefRepositoryFileSystemCookbookEntry < ChefRepositoryFileSystemEntry
-        def initialize(name, parent, file_path = nil, ruby_only = false, recursive = false)
-          super(name, parent, file_path)
-          @ruby_only = ruby_only
-          @recursive = recursive
-        end
-
-        attr_reader :ruby_only
-        attr_reader :recursive
-
-        def children
-          begin
-            Dir.entries(file_path).sort.
-                select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
-                map { |child_name| make_child(child_name) }.
-                select { |entry| !(entry.dir? && entry.children.size == 0) }
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          if is_dir
-            return recursive && name != '.' && name != '..'
-          elsif ruby_only
-            return false if name[-3..-1] != '.rb'
-          end
-
-          # Check chefignore
-          ignorer = parent
-          loop do
-            if ignorer.is_a?(ChefRepositoryFileSystemCookbooksDir)
-              # Grab the path from entry to child
-              path_to_child = name
-              child = self
-              while child.parent != ignorer
-                path_to_child = PathUtils.join(child.name, path_to_child)
-                child = child.parent
-              end
-              # Check whether that relative path is ignored
-              return !ignorer.chefignore || !ignorer.chefignore.ignored?(path_to_child)
-            end
-            ignorer = ignorer.parent
-            break unless ignorer
-          end
-
-          true
-        end
-
-        def write_pretty_json
-          false
-        end
-
-        protected
-
-        def make_child(child_name)
-          ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
deleted file mode 100644
index 7c60b51..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir'
-require 'chef/cookbook/chefignore'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class ChefRepositoryFileSystemCookbooksDir < ChefRepositoryFileSystemEntry
-        def initialize(name, parent, file_path)
-          super(name, parent, file_path)
-          begin
-            @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
-          rescue Errno::EISDIR
-          rescue Errno::EACCES
-            # Work around a bug in Chefignore when chefignore is a directory
-          end
-        end
-
-        attr_reader :chefignore
-
-        def children
-          begin
-            Dir.entries(file_path).sort.
-                select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
-                map { |child_name| make_child(child_name) }.
-                select do |entry|
-                  # empty cookbooks and cookbook directories are ignored
-                  if !entry.can_upload?
-                    Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}")
-                    false
-                  else
-                    true
-                  end
-                end
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir && !name.start_with?('.')
-        end
-
-        def write_cookbook(cookbook_path, cookbook_version_json, from_fs)
-          cookbook_name = File.basename(cookbook_path)
-          child = make_child(cookbook_name)
-
-          # Use the copy/diff algorithm to copy it down so we don't destroy
-          # chefignored data.  This is terribly un-thread-safe.
-          Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), from_fs, child, nil, {:purge => true})
-
-          # Write out .uploaded-cookbook-version.json
-          cookbook_file_path = File.join(file_path, cookbook_name)
-          if !File.exists?(cookbook_file_path)
-            FileUtils.mkdir_p(cookbook_file_path)
-          end
-          uploaded_cookbook_version_path = File.join(cookbook_file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
-          File.open(uploaded_cookbook_version_path, 'w') do |file|
-            file.write(cookbook_version_json)
-          end
-        end
-
-        protected
-
-        def make_child(child_name)
-          ChefRepositoryFileSystemCookbookDir.new(child_name, self)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb
deleted file mode 100644
index 73556b2..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/data_handler/data_bag_item_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class ChefRepositoryFileSystemDataBagsDir < ChefRepositoryFileSystemEntry
-        def initialize(name, parent, path = nil)
-          super(name, parent, path, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir && !name.start_with?('.')
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
deleted file mode 100644
index 0b14750..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/file_system_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      # ChefRepositoryFileSystemEntry works just like FileSystemEntry,
-      # except can inflate Chef objects
-      class ChefRepositoryFileSystemEntry < FileSystemEntry
-        def initialize(name, parent, file_path = nil, data_handler = nil)
-          super(name, parent, file_path)
-          @data_handler = data_handler
-        end
-
-        def write_pretty_json=(value)
-          @write_pretty_json = value
-        end
-
-        def write_pretty_json
-          @write_pretty_json.nil? ? root.write_pretty_json : @write_pretty_json
-        end
-
-        def data_handler
-          @data_handler || parent.data_handler
-        end
-
-        def chef_object
-          begin
-            return data_handler.chef_object(Chef::JSONCompat.parse(read))
-          rescue
-            Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}")
-          end
-          nil
-        end
-
-        def can_have_child?(name, is_dir)
-          !is_dir && name[-5..-1] == '.json'
-        end
-
-        def write(file_contents)
-          if file_contents && write_pretty_json && name[-5..-1] == '.json'
-            file_contents = minimize(file_contents, self)
-          end
-          super(file_contents)
-        end
-
-        def minimize(file_contents, entry)
-          object = Chef::JSONCompat.parse(file_contents)
-          object = data_handler.normalize(object, entry)
-          object = data_handler.minimize(object, entry)
-          Chef::JSONCompat.to_json_pretty(object)
-        end
-
-        def children
-          # Except cookbooks and data bag dirs, all things must be json files
-          begin
-            Dir.entries(file_path).sort.
-                select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
-                map { |child_name| make_child(child_name) }
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        protected
-
-        def make_child(child_name)
-          ChefRepositoryFileSystemEntry.new(child_name, self)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb
deleted file mode 100644
index 42768f1..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/data_handler/policy_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-
-      class ChefRepositoryFileSystemPoliciesDir < ChefRepositoryFileSystemEntry
-        def initialize(name, parent, path = nil)
-          super(name, parent, path, Chef::ChefFS::DataHandler::PolicyDataHandler.new)
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir && !name.start_with?('.')
-        end
-      end
-    end
-  end
-end
-
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
deleted file mode 100644
index d03baf9..0000000
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
-require 'chef/chef_fs/file_system/chef_repository_file_system_acls_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir'
-require 'chef/chef_fs/file_system/chef_repository_file_system_policies_dir'
-require 'chef/chef_fs/file_system/multiplexed_dir'
-require 'chef/chef_fs/data_handler/client_data_handler'
-require 'chef/chef_fs/data_handler/environment_data_handler'
-require 'chef/chef_fs/data_handler/node_data_handler'
-require 'chef/chef_fs/data_handler/role_data_handler'
-require 'chef/chef_fs/data_handler/user_data_handler'
-require 'chef/chef_fs/data_handler/group_data_handler'
-require 'chef/chef_fs/data_handler/container_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-
-      #
-      # Represents the root of a local Chef repository, with directories for
-      # nodes, cookbooks, roles, etc. under it.
-      #
-      class ChefRepositoryFileSystemRootDir < BaseFSDir
-        #
-        # Create a new Chef Repository File System root.
-        #
-        # == Parameters
-        # [child_paths]
-        #   A hash of child paths, e.g.:
-        #     "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
-        #     "roles" => [ '/var/roles' ],
-        #     ...
-        # [root_paths]
-        #   An array of paths representing the top level, where
-        #   +org.json+, +members.json+, and +invites.json+ will be stored.
-        # [chef_config] - a hash of options that looks suspiciously like the ones
-        #   stored in Chef::Config, containing at least these keys:
-        #   :versioned_cookbooks:: whether to include versions in cookbook names
-        def initialize(child_paths, root_paths=[], chef_config=Chef::Config)
-          super("", nil)
-          @child_paths = child_paths
-          @root_paths = root_paths
-          @versioned_cookbooks = chef_config[:versioned_cookbooks]
-        end
-
-        attr_accessor :write_pretty_json
-
-        attr_reader :root_paths
-        attr_reader :child_paths
-        attr_reader :versioned_cookbooks
-
-        CHILDREN = %w(invitations.json members.json org.json)
-
-        def children
-          @children ||= begin
-            result = child_paths.keys.sort.map { |name| make_child_entry(name) }.select { |child| !child.nil? }
-            result += root_dir.children.select { |c| CHILDREN.include?(c.name) } if root_dir
-            result.sort_by { |c| c.name }
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          if is_dir
-            child_paths.has_key?(name)
-          elsif root_dir
-            CHILDREN.include?(name)
-          else
-            false
-          end
-        end
-
-        def create_child(name, file_contents = nil)
-          if file_contents
-            child = root_dir.create_child(name, file_contents)
-          else
-            child_paths[name].each do |path|
-              begin
-                Dir.mkdir(path)
-              rescue Errno::EEXIST
-              end
-            end
-            child = make_child_entry(name)
-          end
-          @children = nil
-          child
-        end
-
-        def json_class
-          nil
-        end
-
-        # Used to print out a human-readable file system description
-        def fs_description
-          repo_paths = root_paths || [ File.dirname(child_paths['cookbooks'][0]) ]
-          result = "repository at #{repo_paths.join(', ')}\n"
-          if versioned_cookbooks
-            result << "  Multiple versions per cookbook\n"
-          else
-            result << "  One version per cookbook\n"
-          end
-          child_paths.each_pair do |name, paths|
-            if paths.any? { |path| !repo_paths.include?(File.dirname(path)) }
-              result << "  #{name} at #{paths.join(', ')}\n"
-            end
-          end
-          result
-        end
-
-        private
-
-        #
-        # A FileSystemEntry representing the root path where invites.json,
-        # members.json and org.json may be found.
-        #
-        def root_dir
-          existing_paths = root_paths.select { |path| File.exists?(path) }
-          if existing_paths.size > 0
-            MultiplexedDir.new(existing_paths.map do |path|
-              dir = ChefRepositoryFileSystemEntry.new(name, parent, path)
-              dir.write_pretty_json = !!write_pretty_json
-              dir
-            end)
-          end
-        end
-
-        #
-        # Create a child entry of the appropriate type:
-        # cookbooks, data_bags, acls, etc.  All will be multiplexed (i.e. if
-        # you have multiple paths for cookbooks, the multiplexed dir will grab
-        # cookbooks from all of them when you list or grab them).
-        #
-        def make_child_entry(name)
-          paths = child_paths[name].select do |path|
-            File.exists?(path)
-          end
-          if paths.size == 0
-            return nil
-          end
-          if name == 'cookbooks'
-            dirs = paths.map { |path| ChefRepositoryFileSystemCookbooksDir.new(name, self, path) }
-          elsif name == 'data_bags'
-            dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) }
-          elsif name == 'policies'
-            dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) }
-          elsif name == 'acls'
-            dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) }
-          else
-            data_handler = case name
-              when 'clients'
-                Chef::ChefFS::DataHandler::ClientDataHandler.new
-              when 'environments'
-                Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
-              when 'nodes'
-                Chef::ChefFS::DataHandler::NodeDataHandler.new
-              when 'roles'
-                Chef::ChefFS::DataHandler::RoleDataHandler.new
-              when 'users'
-                Chef::ChefFS::DataHandler::UserDataHandler.new
-              when 'groups'
-                Chef::ChefFS::DataHandler::GroupDataHandler.new
-              when 'containers'
-                Chef::ChefFS::DataHandler::ContainerDataHandler.new
-              else
-                raise "Unknown top level path #{name}"
-              end
-            dirs = paths.map { |path| ChefRepositoryFileSystemEntry.new(name, self, path, data_handler) }
-          end
-          MultiplexedDir.new(dirs)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb
new file mode 100644
index 0000000..9943aae
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acl_dir.rb
@@ -0,0 +1,65 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+require "chef/chef_fs/file_system/operation_not_allowed_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class AclDir < BaseFSDir
+          def api_path
+            parent.parent.child(name).api_path
+          end
+
+          def make_child_entry(name, exists = nil)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || AclEntry.new(name, self, exists)
+          end
+
+          def can_have_child?(name, is_dir)
+            name =~ /\.json$/ && !is_dir
+          end
+
+          def children
+            if @children.nil?
+              # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names
+              names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name }
+              @children = names.map { |name| make_child_entry(name, true) }
+            end
+            @children
+          end
+
+          def create_child(name, file_contents)
+            raise OperationNotAllowedError.new(:create_child, self, nil, "ACLs can only be updated, and can only be created when the corresponding object is created.")
+          end
+
+          def data_handler
+            parent.data_handler
+          end
+
+          def rest
+            parent.rest
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb b/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb
new file mode 100644
index 0000000..cf63425
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acl_entry.rb
@@ -0,0 +1,60 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/operation_not_allowed_error"
+require "chef/chef_fs/file_system/operation_failed_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class AclEntry < RestListEntry
+          PERMISSIONS = %w{create read update delete grant}
+
+          def api_path
+            "#{super}/_acl"
+          end
+
+          def delete(recurse)
+            raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self, nil, "ACLs cannot be deleted")
+          end
+
+          def write(file_contents)
+            # ACL writes are fun.
+            acls = data_handler.normalize(Chef::JSONCompat.parse(file_contents), self)
+            PERMISSIONS.each do |permission|
+              begin
+                rest.put("#{api_path}/#{permission}", { permission => acls[permission] })
+              rescue Timeout::Error => e
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+              rescue Net::HTTPServerException => e
+                if e.response.code == "404"
+                  raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+                else
+                  raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+                end
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb b/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb
new file mode 100644
index 0000000..d031640
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/acls_dir.rb
@@ -0,0 +1,75 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+require "chef/chef_fs/file_system/chef_server/cookbooks_acl_dir"
+require "chef/chef_fs/file_system/chef_server/policies_acl_dir"
+require "chef/chef_fs/file_system/chef_server/acl_entry"
+require "chef/chef_fs/data_handler/acl_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class AclsDir < BaseFSDir
+          ENTITY_TYPES = %w{clients containers cookbook_artifacts cookbooks data_bags environments groups nodes policies policy_groups roles} # we don't read sandboxes, so we don't read their acls
+
+          def data_handler
+            @data_handler ||= Chef::ChefFS::DataHandler::AclDataHandler.new
+          end
+
+          def api_path
+            parent.api_path
+          end
+
+          def make_child_entry(name)
+            children.select { |child| child.name == name }.first
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir ? ENTITY_TYPES.include?(name) : name == "organization.json"
+          end
+
+          def children
+            if @children.nil?
+              @children = ENTITY_TYPES.map do |entity_type|
+                # All three of these can be versioned (NAME-VERSION), but only have
+                # one ACL that covers them all (NAME.json).
+                case entity_type
+                when "cookbooks", "cookbook_artifacts"
+                  CookbooksAclDir.new(entity_type, self)
+                when "policies"
+                  PoliciesAclDir.new(entity_type, self)
+                else
+                  AclDir.new(entity_type, self)
+                end
+              end
+              @children << AclEntry.new("organization.json", self, true) # the org acl is retrieved as GET /organizations/ORGNAME/ANYTHINGATALL/_acl
+            end
+            @children
+          end
+
+          def rest
+            parent.rest
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
new file mode 100644
index 0000000..6c99d6d
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/chef_server_root_dir.rb
@@ -0,0 +1,196 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/server_api"
+require "chef/chef_fs/file_system/chef_server/acls_dir"
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/data_bags_dir"
+require "chef/chef_fs/file_system/chef_server/nodes_dir"
+require "chef/chef_fs/file_system/chef_server/org_entry"
+require "chef/chef_fs/file_system/chef_server/organization_invites_entry"
+require "chef/chef_fs/file_system/chef_server/organization_members_entry"
+require "chef/chef_fs/file_system/chef_server/policies_dir"
+require "chef/chef_fs/file_system/chef_server/policy_groups_dir"
+require "chef/chef_fs/file_system/chef_server/environments_dir"
+require "chef/chef_fs/data_handler/acl_data_handler"
+require "chef/chef_fs/data_handler/client_data_handler"
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/data_handler/node_data_handler"
+require "chef/chef_fs/data_handler/role_data_handler"
+require "chef/chef_fs/data_handler/user_data_handler"
+require "chef/chef_fs/data_handler/group_data_handler"
+require "chef/chef_fs/data_handler/container_data_handler"
+require "chef/chef_fs/data_handler/policy_group_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        #
+        # Represents the root of a Chef server (or organization), under which
+        # nodes, roles, cookbooks, etc. can be found.
+        #
+        class ChefServerRootDir < BaseFSDir
+          #
+          # Create a new Chef server root.
+          #
+          # == Parameters
+          #
+          # [root_name]
+          #   A friendly name for the root, for printing--like "remote" or "chef_central".
+          # [chef_config]
+          #   A hash with options that look suspiciously like Chef::Config, including the
+          #   following keys:
+          #   :chef_server_url:: The URL to the Chef server or top of the organization
+          #   :node_name:: The username to authenticate to the Chef server with
+          #   :client_key:: The private key for the user for authentication
+          #   :environment:: The environment in which you are presently working
+          #   :repo_mode::
+          #     The repository mode, :hosted_everything, :everything or :static.
+          #     This determines the set of subdirectories the Chef server will
+          #     offer up.
+          #   :versioned_cookbooks:: whether or not to include versions in cookbook names
+          # [options]
+          #   Other options:
+          #   :cookbook_version:: when cookbooks are retrieved, grab this version for them.
+          #   :freeze:: freeze cookbooks on upload
+          #
+          def initialize(root_name, chef_config, options = {})
+            super("", nil)
+            @chef_server_url = chef_config[:chef_server_url]
+            @chef_username = chef_config[:node_name]
+            @chef_private_key = chef_config[:client_key]
+            @environment = chef_config[:environment]
+            @repo_mode = chef_config[:repo_mode]
+            @versioned_cookbooks = chef_config[:versioned_cookbooks]
+            @root_name = root_name
+            @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version
+          end
+
+          attr_reader :chef_server_url
+          attr_reader :chef_username
+          attr_reader :chef_private_key
+          attr_reader :environment
+          attr_reader :repo_mode
+          attr_reader :cookbook_version
+          attr_reader :versioned_cookbooks
+
+          def fs_description
+            "Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}"
+          end
+
+          def rest
+            Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true, :api_version => "0")
+          end
+
+          def get_json(path)
+            Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :api_version => "0").get(path)
+          end
+
+          def chef_rest
+            Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key)
+          end
+
+          def api_path
+            ""
+          end
+
+          def path_for_printing
+            "#{@root_name}/"
+          end
+
+          def can_have_child?(name, is_dir)
+            result = children.select { |child| child.name == name }.first
+            result && !!result.dir? == !!is_dir
+          end
+
+          def org
+            @org ||= begin
+              path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
+              if File.dirname(path) == "/organizations"
+                File.basename(path)
+              else
+                # In Chef 12, everything is in an org.
+                "chef"
+              end
+            end
+          end
+
+          def make_child_entry(name)
+            children.select { |child| child.name == name }.first
+          end
+
+          def children
+            @children ||= begin
+              result = [
+                # /cookbooks
+                versioned_cookbooks ? VersionedCookbooksDir.new("cookbooks", self) : CookbooksDir.new("cookbooks", self),
+                # /data_bags
+                DataBagsDir.new("data_bags", self, "data"),
+                # /environments
+                EnvironmentsDir.new("environments", self, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new),
+                # /roles
+                RestListDir.new("roles", self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new),
+              ]
+              if repo_mode == "hosted_everything"
+                result += [
+                  # /acls
+                  AclsDir.new("acls", self),
+                  # /clients
+                  RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
+                  # /containers
+                  RestListDir.new("containers", self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new),
+                  # /cookbook_artifacts
+                  CookbookArtifactsDir.new("cookbook_artifacts", self),
+                  # /groups
+                  RestListDir.new("groups", self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new),
+                  # /nodes
+                  NodesDir.new("nodes", self, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new),
+                  # /org.json
+                  OrgEntry.new("org.json", self),
+                  # /members.json
+                  OrganizationMembersEntry.new("members.json", self),
+                  # /invitations.json
+                  OrganizationInvitesEntry.new("invitations.json", self),
+                  # /policies
+                  PoliciesDir.new("policies", self, nil, Chef::ChefFS::DataHandler::PolicyDataHandler.new),
+                  # /policy_groups
+                  PolicyGroupsDir.new("policy_groups", self, nil, Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new),
+                ]
+              elsif repo_mode != "static"
+                result += [
+                  # /clients
+                  RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
+                  # /nodes
+                  NodesDir.new("nodes", self, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new),
+                  # /users
+                  RestListDir.new("users", self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new),
+                ]
+              end
+              result.sort_by { |child| child.name }
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb
new file mode 100644
index 0000000..faea96e
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifact_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class CookbookArtifactDir < CookbookDir
+          def initialize(name, parent, options = {})
+            super(name, parent)
+            @cookbook_name, dash, @version = name.rpartition("-")
+          end
+
+          def copy_from(other, options = {})
+            raise OperationNotAllowedError.new(:write, self, nil, "cannot be updated: cookbook artifacts are immutable once uploaded")
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
new file mode 100644
index 0000000..020f851
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_artifacts_dir.rb
@@ -0,0 +1,102 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_artifact_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        #
+        # /cookbook_artifacts
+        #
+        # Example children of /cookbook_artifacts:
+        #
+        # - apache2-ab234098245908ddf324a
+        # - apache2-295387a9823745feff239
+        # - mysql-1a2b9e1298734dfe90444
+        #
+        class CookbookArtifactsDir < CookbooksDir
+
+          def make_child_entry(name)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || CookbookArtifactDir.new(name, self)
+          end
+
+          def children
+            @children ||= begin
+              result = []
+              root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
+                cookbooks["versions"].each do |cookbook_version|
+                  result << CookbookArtifactDir.new("#{cookbook_name}-#{cookbook_version['identifier']}", self)
+                end
+              end
+              result.sort_by(&:name)
+            end
+          end
+
+          # Knife currently does not understand versioned cookbooks
+          # Cookbook Version uploader also requires a lot of refactoring
+          # to make this work. So instead, we make a temporary cookbook
+          # symlinking back to real cookbook, and upload the proxy.
+          def upload_cookbook(other, options)
+            cookbook_name, dash, identifier = other.name.rpartition("-")
+
+            Dir.mktmpdir do |temp_cookbooks_path|
+              proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
+
+              # Make a symlink
+              file_class.symlink other.file_path, proxy_cookbook_path
+
+              # Instantiate a proxy loader using the temporary symlink
+              proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
+              proxy_loader.load_cookbooks
+
+              cookbook_to_upload = proxy_loader.cookbook_version
+              cookbook_to_upload.identifier = identifier
+              cookbook_to_upload.freeze_version if options[:freeze]
+
+              # Instantiate a new uploader based on the proxy loader
+              uploader = Chef::CookbookUploader.new(cookbook_to_upload, force: options[:force], rest: root.chef_rest, policy_mode: true)
+
+              with_actual_cookbooks_dir(temp_cookbooks_path) do
+                uploader.upload_cookbooks
+              end
+
+              #
+              # When the temporary directory is being deleted on
+              # windows, the contents of the symlink under that
+              # directory is also deleted. So explicitly remove
+              # the symlink without removing the original contents if we
+              # are running on windows
+              #
+              if Chef::Platform.windows?
+                Dir.rmdir proxy_cookbook_path
+              end
+            end
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir && name.include?("-")
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
new file mode 100644
index 0000000..a6a062a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_dir.rb
@@ -0,0 +1,222 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/command_line"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_subdir"
+require "chef/chef_fs/file_system/chef_server/cookbook_file"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/cookbook_version"
+require "chef/cookbook_uploader"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # Unversioned cookbook.
+        #
+        #   /cookbooks/NAME
+        #
+        # Children look like:
+        #
+        # - metadata.rb
+        # - attributes/
+        # - libraries/
+        # - recipes/
+        #
+        class CookbookDir < BaseFSDir
+          def initialize(name, parent, options = {})
+            super(name, parent)
+            @exists = options[:exists]
+            @cookbook_name = name
+            @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff
+          end
+
+          attr_reader :cookbook_name, :version
+
+          COOKBOOK_SEGMENT_INFO = {
+            :attributes => { :ruby_only => true },
+            :definitions => { :ruby_only => true },
+            :recipes => { :ruby_only => true },
+            :libraries => { :ruby_only => true },
+            :templates => { :recursive => true },
+            :files => { :recursive => true },
+            :resources => { :ruby_only => true, :recursive => true },
+            :providers => { :ruby_only => true, :recursive => true },
+            :root_files => {},
+          }
+
+          def add_child(child)
+            @children << child
+          end
+
+          def api_path
+            "#{parent.api_path}/#{cookbook_name}/#{version || "_latest"}"
+          end
+
+          def make_child_entry(name)
+            # Since we're ignoring the rules and doing a network request here,
+            # we need to make sure we don't rethrow the exception.  (child(name)
+            # is not supposed to fail.)
+            begin
+              children.select { |child| child.name == name }.first
+            rescue Chef::ChefFS::FileSystem::NotFoundError
+              nil
+            end
+          end
+
+          def can_have_child?(name, is_dir)
+            # A cookbook's root may not have directories unless they are segment directories
+            return name != "root_files" && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir
+            return true
+          end
+
+          def children
+            if @children.nil?
+              @children = []
+              manifest = chef_object.manifest
+              COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
+                next unless manifest.has_key?(segment)
+
+                # Go through each file in the manifest for the segment, and
+                # add cookbook subdirs and files for it.
+                manifest[segment].each do |segment_file|
+                  parts = segment_file[:path].split("/")
+                  # Get or create the path to the file
+                  container = self
+                  parts[0, parts.length - 1].each do |part|
+                    old_container = container
+                    container = old_container.children.select { |child| part == child.name }.first
+                    if !container
+                      container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
+                      old_container.add_child(container)
+                    end
+                  end
+                  # Create the file itself
+                  container.add_child(CookbookFile.new(parts[parts.length - 1], container, segment_file))
+                end
+              end
+              @children = @children.sort_by { |c| c.name }
+            end
+            @children
+          end
+
+          def dir?
+            exists?
+          end
+
+          def delete(recurse)
+            if recurse
+              begin
+                rest.delete(api_path)
+              rescue Timeout::Error => e
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+              rescue Net::HTTPServerException
+                if $!.response.code == "404"
+                  raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+                else
+                  raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "HTTP error deleting: #{e}")
+                end
+              end
+            else
+              raise NotFoundError.new(self) if !exists?
+              raise MustDeleteRecursivelyError.new(self, "#{path_for_printing} must be deleted recursively")
+            end
+          end
+
+          # In versioned cookbook mode, actually check if the version exists
+          # Probably want to cache this.
+          def exists?
+            if @exists.nil?
+              @exists = parent.children.any? { |child| child.name == name }
+            end
+            @exists
+          end
+
+          def compare_to(other)
+            if !other.dir?
+              return [ !exists?, nil, nil ]
+            end
+            are_same = true
+            Chef::ChefFS::CommandLine::diff_entries(self, other, nil, :name_only).each do |type, old_entry, new_entry|
+              if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type)
+                are_same = false
+              end
+            end
+            [ are_same, nil, nil ]
+          end
+
+          def copy_from(other, options = {})
+            parent.upload_cookbook_from(other, options)
+          end
+
+          def rest
+            parent.rest
+          end
+
+          def chef_object
+            # We cheat and cache here, because it seems like a good idea to keep
+            # the cookbook view consistent with the directory structure.
+            return @chef_object if @chef_object
+
+            # The negative (not found) response is cached
+            if @could_not_get_chef_object
+              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+            end
+
+            begin
+              # We want to fail fast, for now, because of the 500 issue :/
+              # This will make things worse for parallelism, a little, because
+              # Chef::Config is global and this could affect other requests while
+              # this request is going on.  (We're not parallel yet, but we will be.)
+              # Chef bug http://tickets.opscode.com/browse/CHEF-3066
+              old_retry_count = Chef::Config[:http_retry_count]
+              begin
+                Chef::Config[:http_retry_count] = 0
+                @chef_object ||= Chef::CookbookVersion.from_hash(root.get_json(api_path))
+              ensure
+                Chef::Config[:http_retry_count] = old_retry_count
+              end
+
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading: #{e}")
+
+            rescue Net::HTTPServerException => e
+              if e.response.code == "404"
+                @could_not_get_chef_object = e
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+              end
+
+            # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
+            # Remove this when that bug is fixed.
+            rescue Net::HTTPFatalError => e
+              if e.response.code == "500"
+                @could_not_get_chef_object = e
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb
new file mode 100644
index 0000000..426cc62
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_file.rb
@@ -0,0 +1,84 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/http/simple"
+require "openssl"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class CookbookFile < BaseFSObject
+          def initialize(name, parent, file)
+            super(name, parent)
+            @file = file
+          end
+
+          attr_reader :file
+
+          def checksum
+            file[:checksum]
+          end
+
+          def read
+            begin
+              tmpfile = rest.streaming_request(file[:url])
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading #{file[:url]}: #{e}")
+            rescue Net::HTTPServerException => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "#{e.message} retrieving #{file[:url]}")
+            end
+
+            begin
+              tmpfile.open
+              tmpfile.read
+            ensure
+              tmpfile.close!
+            end
+          end
+
+          def rest
+            parent.rest
+          end
+
+          def compare_to(other)
+            other_value = nil
+            if other.respond_to?(:checksum)
+              other_checksum = other.checksum
+            else
+              begin
+                other_value = other.read
+              rescue Chef::ChefFS::FileSystem::NotFoundError
+                return [ false, nil, :none ]
+              end
+              other_checksum = calc_checksum(other_value)
+            end
+            [ checksum == other_checksum, nil, other_value ]
+          end
+
+          private
+
+          def calc_checksum(value)
+            OpenSSL::Digest::MD5.hexdigest(value)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb
new file mode 100644
index 0000000..913cf1a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbook_subdir.rb
@@ -0,0 +1,61 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class CookbookSubdir < BaseFSDir
+          def initialize(name, parent, ruby_only, recursive)
+            super(name, parent)
+            @children = []
+            @ruby_only = ruby_only
+            @recursive = recursive
+          end
+
+          attr_reader :versions
+          attr_reader :children
+
+          def add_child(child)
+            @children << child
+          end
+
+          def can_have_child?(name, is_dir)
+            if is_dir
+              return false if !@recursive
+            else
+              return false if @ruby_only && name !~ /\.rb$/
+            end
+            true
+          end
+
+          def make_child_entry(name)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || NonexistentFSObject.new(name, self)
+          end
+
+          def rest
+            parent.rest
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb
new file mode 100644
index 0000000..e020d0f
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbooks_acl_dir.rb
@@ -0,0 +1,42 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class CookbooksAclDir < AclDir
+          # If versioned_cookbooks is on, the list of cookbooks will have versions
+          # in them.  But all versions of a cookbook have the same acl, so even if
+          # we have cookbooks/apache2-1.0.0 and cookbooks/apache2-1.1.2, we will
+          # only have one acl: acls/cookbooks/apache2.json.  Thus, the list of
+          # children of acls/cookbooks is a unique list of cookbook *names*.
+          def children
+            if @children.nil?
+              names = parent.parent.child(name).children.map { |child| "#{child.cookbook_name}.json" }
+              @children = names.uniq.map { |name| make_child_entry(name, true) }
+            end
+            @children
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
new file mode 100644
index 0000000..75d7150
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/cookbooks_dir.rb
@@ -0,0 +1,102 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+require "chef/chef_fs/file_system/operation_failed_error"
+require "chef/chef_fs/file_system/cookbook_frozen_error"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+require "chef/mixin/file_class"
+
+require "tmpdir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        #
+        # /cookbooks
+        #
+        # Example children:
+        #   apache2/
+        #   mysql/
+        #
+        class CookbooksDir < RestListDir
+
+          include Chef::Mixin::FileClass
+
+          def make_child_entry(name)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || CookbookDir.new(name, self)
+          end
+
+          def children
+            @children ||= begin
+              result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, exists: true) }
+              result.sort_by(&:name)
+            end
+          end
+
+          def create_child_from(other, options = {})
+            @children = nil
+            upload_cookbook_from(other, options)
+          end
+
+          def upload_cookbook_from(other, options = {})
+            upload_cookbook(other, options)
+          rescue Timeout::Error => e
+            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+          rescue Net::HTTPServerException => e
+            case e.response.code
+            when "409"
+              raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e, "Cookbook #{other.name} is frozen")
+            else
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+            end
+          rescue Chef::Exceptions::CookbookFrozen => e
+            raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e, "Cookbook #{other.name} is frozen")
+          end
+
+          def upload_cookbook(other, options)
+            cookbook_to_upload = other.chef_object
+            cookbook_to_upload.freeze_version if options[:freeze]
+            uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+
+            with_actual_cookbooks_dir(other.parent.file_path) do
+              uploader.upload_cookbooks
+            end
+          end
+
+          # Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)
+          def with_actual_cookbooks_dir(actual_cookbook_path)
+            old_cookbook_path = Chef::Config.cookbook_path
+            Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path
+
+            yield
+          ensure
+            Chef::Config.cookbook_path = old_cookbook_path
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb b/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb
new file mode 100644
index 0000000..6b06550
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb
@@ -0,0 +1,71 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/must_delete_recursively_error"
+require "chef/chef_fs/data_handler/data_bag_item_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class DataBagDir < RestListDir
+          def initialize(name, parent, exists = nil)
+            super(name, parent, nil, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
+            @exists = nil
+          end
+
+          def dir?
+            exists?
+          end
+
+          def read
+            # This will only be called if dir? is false, which means exists? is false.
+            raise Chef::ChefFS::FileSystem::NotFoundError.new(self)
+          end
+
+          def exists?
+            if @exists.nil?
+              @exists = parent.children.any? { |child| child.name == name }
+            end
+            @exists
+          end
+
+          def delete(recurse)
+            if !recurse
+              raise NotFoundError.new(self) if !exists?
+              raise MustDeleteRecursivelyError.new(self, "#{path_for_printing} must be deleted recursively")
+            end
+            begin
+              rest.delete(api_path)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+            rescue Net::HTTPServerException => e
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "HTTP error deleting: #{e}")
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb b/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb
new file mode 100644
index 0000000..9246d8e
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/data_bags_dir.rb
@@ -0,0 +1,69 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/data_bag_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class DataBagsDir < RestListDir
+          def make_child_entry(name, exists = false)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || DataBagDir.new(name, self, exists)
+          end
+
+          def children
+            begin
+              @children ||= root.get_json(api_path).keys.sort.map { |entry| make_child_entry(entry, true) }
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout getting children: #{e}")
+            rescue Net::HTTPServerException => e
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error getting children: #{e}")
+              end
+            end
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir
+          end
+
+          def create_child(name, file_contents)
+            begin
+              rest.post(api_path, { "name" => name })
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating child '#{name}': #{e}")
+            rescue Net::HTTPServerException => e
+              if e.response.code == "409"
+                raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Cannot create #{name} under #{path}: already exists")
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "HTTP error creating child '#{name}': #{e}")
+              end
+            end
+            @children = nil
+            DataBagDir.new(name, self, true)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb b/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb
new file mode 100644
index 0000000..4940369
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/environments_dir.rb
@@ -0,0 +1,57 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/default_environment_cannot_be_modified_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class EnvironmentsDir < RestListDir
+          def make_child_entry(name, exists = nil)
+            if name == "_default.json"
+              DefaultEnvironmentEntry.new(name, self, exists)
+            else
+              super
+            end
+          end
+
+          class DefaultEnvironmentEntry < RestListEntry
+            def initialize(name, parent, exists = nil)
+              super(name, parent)
+              @exists = exists
+            end
+
+            def delete(recurse)
+              raise NotFoundError.new(self) if !exists?
+              raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self)
+            end
+
+            def write(file_contents)
+              raise NotFoundError.new(self) if !exists?
+              raise DefaultEnvironmentCannotBeModifiedError.new(:write, self)
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb b/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb
new file mode 100644
index 0000000..6ecc7f4
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/nodes_dir.rb
@@ -0,0 +1,53 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/data_handler/node_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class NodesDir < RestListDir
+          # Identical to RestListDir.children, except supports environments
+          def children
+            begin
+              @children ||= root.get_json(env_api_path).keys.sort.map do |key|
+                make_child_entry("#{key}.json", true)
+              end
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
+            rescue Net::HTTPServerException => e
+              if $!.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+              end
+            end
+          end
+
+          def env_api_path
+            environment ? "environments/#{environment}/#{api_path}" : api_path
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/org_entry.rb b/lib/chef/chef_fs/file_system/chef_server/org_entry.rb
new file mode 100644
index 0000000..87be36b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/org_entry.rb
@@ -0,0 +1,31 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # /organizations/NAME/org.json
+        # Represents the actual data at /organizations/NAME (the full name, etc.)
+        class OrgEntry < RestListEntry
+          def data_handler
+            Chef::ChefFS::DataHandler::OrganizationDataHandler.new
+          end
+
+          # /organizations/foo/org.json -> GET /organizations/foo
+          def api_path
+            parent.api_path
+          end
+
+          def exists?
+            parent.exists?
+          end
+
+          def delete(recurse)
+            raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb b/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb
new file mode 100644
index 0000000..37b7af8
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/organization_invites_entry.rb
@@ -0,0 +1,61 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_invites_data_handler"
+require "chef/json_compat"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # /organizations/NAME/invitations.json
+        # read data from:
+        # - GET /organizations/NAME/association_requests
+        # write data to:
+        # - remove from list: DELETE /organizations/NAME/association_requests/id
+        # - add to list: POST /organizations/NAME/association_requests
+        class OrganizationInvitesEntry < RestListEntry
+          def initialize(name, parent, exists = nil)
+            super(name, parent)
+            @exists = exists
+          end
+
+          def data_handler
+            Chef::ChefFS::DataHandler::OrganizationInvitesDataHandler.new
+          end
+
+          # /organizations/foo/invites.json -> /organizations/foo/association_requests
+          def api_path
+            File.join(parent.api_path, "association_requests")
+          end
+
+          def exists?
+            parent.exists?
+          end
+
+          def delete(recurse)
+            raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+          end
+
+          def write(contents)
+            desired_invites = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
+            actual_invites = _read_json.inject({}) { |h, val| h[val["username"]] = val["id"]; h }
+            invites = actual_invites.keys
+            (desired_invites - invites).each do |invite|
+              begin
+                rest.post(api_path, { "user" => invite })
+              rescue Net::HTTPServerException => e
+                if e.response.code == "409"
+                  Chef::Log.warn("Could not invite #{invite} to organization #{org}: #{api_error_text(e.response)}")
+                else
+                  raise
+                end
+              end
+            end
+            (invites - desired_invites).each do |invite|
+              rest.delete(File.join(api_path, actual_invites[invite]))
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb b/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb
new file mode 100644
index 0000000..2e45b74
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/organization_members_entry.rb
@@ -0,0 +1,60 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/organization_members_data_handler"
+require "chef/json_compat"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # /organizations/NAME/members.json
+        # reads data from:
+        # - GET /organizations/NAME/users
+        # writes data to:
+        # - remove from list: DELETE /organizations/NAME/users/name
+        # - add to list: POST /organizations/NAME/users/name
+        class OrganizationMembersEntry < RestListEntry
+          def initialize(name, parent, exists = nil)
+            super(name, parent)
+            @exists = exists
+          end
+
+          def data_handler
+            Chef::ChefFS::DataHandler::OrganizationMembersDataHandler.new
+          end
+
+          # /organizations/foo/members.json -> /organizations/foo/users
+          def api_path
+            File.join(parent.api_path, "users")
+          end
+
+          def exists?
+            parent.exists?
+          end
+
+          def delete(recurse)
+            raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
+          end
+
+          def write(contents)
+            desired_members = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
+            members = minimize_value(_read_json)
+            (desired_members - members).each do |member|
+              begin
+                rest.post(api_path, "username" => member)
+              rescue Net::HTTPServerException => e
+                if %w{404 405}.include?(e.response.code)
+                  raise "Chef server at #{api_path} does not allow you to directly add members.  Please either upgrade your Chef server or move the users you want into invitations.json instead of members.json."
+                else
+                  raise
+                end
+              end
+            end
+            (members - desired_members).each do |member|
+              rest.delete(File.join(api_path, member))
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb b/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb
new file mode 100644
index 0000000..fa1d184
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policies_acl_dir.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/acl_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class PoliciesAclDir < AclDir
+          # Policies are presented like /NAME-VERSION.json. But there is only
+          # one ACL for a given NAME. So we find out the unique policy names,
+          # and make one acls/policies/NAME.json for each one.
+          def children
+            if @children.nil?
+              # /acls/policies -> List ../../policies
+              names = parent.parent.child(name).children.map { |child| "#{child.policy_name}.json" }
+              @children = names.uniq.map { |name| make_child_entry(name, true) }
+            end
+            @children
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb b/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb
new file mode 100644
index 0000000..ebb274a
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policies_dir.rb
@@ -0,0 +1,160 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/chef_server/policy_revision_entry"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        #
+        # Server API:
+        # /policies - list of policies by name
+        #   - /policies/NAME - represents a policy with all revisions
+        #     - /policies/NAME/revisions - list of revisions for that policy
+        #       - /policies/NAME/revisions/REVISION - actual policy-revision document
+        #
+        # Local Repository and ChefFS:
+        # /policies - PoliciesDir - maps to server API /policies
+        #   - /policies/NAME-REVISION.json - PolicyRevision - maps to /policies/NAME/revisions/REVISION
+        #
+        class PoliciesDir < RestListDir
+          # Children: NAME-REVISION.json for all revisions of all policies
+          #
+          # /nodes: {
+          #   "node1": "https://api.opscode.com/organizations/myorg/nodes/node1",
+          #   "node2": "https://api.opscode.com/organizations/myorg/nodes/node2",
+          # }
+          #
+          # /policies: {
+          #   "foo": {}
+          # }
+
+          def make_child_entry(name, exists = nil)
+            @children.select { |child| child.name == name }.first if @children
+            PolicyRevisionEntry.new(name, self, exists)
+          end
+
+          # Children come from /policies in this format:
+          # {
+          #   "foo": {
+          #     "uri": "https://api.opscode.com/organizations/essentials/policies/foo",
+          #     "revisions": {
+          #       "1.0.0": {
+          #
+          #       },
+          #       "1.0.1": {
+          #
+          #       }
+          #     }
+          #   }
+          # }
+          def children
+            begin
+              # Grab the names of the children, append json, and make child entries
+              @children ||= begin
+                result = []
+                data = root.get_json(api_path)
+                data.keys.sort.each do |policy_name|
+                  data[policy_name]["revisions"].keys.each do |policy_revision|
+                    filename = "#{policy_name}-#{policy_revision}.json"
+                    result << make_child_entry(filename, true)
+                  end
+                end
+                result
+              end
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
+            rescue Net::HTTPServerException => e
+              # 404 = NotFoundError
+              if $!.response.code == "404"
+                # GET /organizations/ORG/policies returned 404, but that just might be because
+                # we are talking to an older version of the server that doesn't support policies.
+                # Do GET /orgqanizations/ORG to find out if the org exists at all.
+                # TODO use server API version instead of a second network request.
+                begin
+                  root.get_json(parent.api_path)
+                  # Return empty list if the organization exists but /policies didn't work
+                  []
+                rescue Net::HTTPServerException => e
+                  if e.response.code == "404"
+                    raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+                  end
+                  raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+                end
+              # Anything else is unexpected (OperationFailedError)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+              end
+            end
+          end
+
+          #
+          # Does POST <api_path> with file_contents
+          #
+          def create_child(name, file_contents)
+            # Parse the contents to ensure they are valid JSON
+            begin
+              object = Chef::JSONCompat.parse(file_contents)
+            rescue Chef::Exceptions::JSON::ParseError => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+            end
+
+            # Create the child entry that will be returned
+            result = make_child_entry(name, true)
+
+            # Normalize the file_contents before post (add defaults, etc.)
+            if data_handler
+              object = data_handler.normalize_for_post(object, result)
+              data_handler.verify_integrity(object, result) do |error|
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+              end
+            end
+
+            # POST /api_path with the normalized file_contents
+            begin
+              policy_name, policy_revision = data_handler.name_and_revision(name)
+              rest.post("#{api_path}/#{policy_name}/revisions", object)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+            rescue Net::HTTPServerException => e
+              # 404 = NotFoundError
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              # 409 = AlreadyExistsError
+              elsif $!.response.code == "409"
+                raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+              # Anything else is unexpected (OperationFailedError)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+              end
+            end
+
+            # Clear the cache of children so that if someone asks for children
+            # again, we will get it again
+            @children = nil
+
+            result
+          end
+
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb b/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb
new file mode 100644
index 0000000..98a0463
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_group_entry.rb
@@ -0,0 +1,137 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/already_exists_error"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/operation_failed_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # Represents an entire policy group.
+        # Server path: /organizations/ORG/policy_groups/GROUP
+        # Repository path: policy_groups\GROUP.json
+        # Format:
+        # {
+        #   "policies": {
+        #     "a": { "revision_id": "1.0.0" }
+        #   }
+        # }
+        class PolicyGroupEntry < RestListEntry
+          # delete is handled normally:
+          # DELETE /organizations/ORG/policy_groups/GROUP
+
+          # read is handled normally:
+          # GET /organizations/ORG/policy_groups/GROUP
+
+          # write is different.
+          # For each policy:
+          # - PUT /organizations/ORG/policy_groups/GROUP/policies/POLICY
+          # For each policy on the server but not the client:
+          # - DELETE /organizations/ORG/policy_groups/GROUP/policies/POLICY
+          # If the server has associations for a, b and c,
+          # And the client wants associations for a, x and y,
+          # We must PUT a, x and y
+          # And DELETE b and c
+          def write(file_contents)
+            # Parse the contents to ensure they are valid JSON
+            begin
+              object = Chef::JSONCompat.parse(file_contents)
+            rescue Chef::Exceptions::JSON::ParseError => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+            end
+
+            if data_handler
+              object = data_handler.normalize_for_put(object, self)
+              data_handler.verify_integrity(object, self) do |error|
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+              end
+            end
+
+            begin
+
+              # this should all get carted to PolicyGroupEntry#write.
+
+              # the server demands the full policy data, but we want users' local policy_group documents to just
+              # have the data you'd get from GET /policy_groups/POLICY_GROUP. so we try to fetch that.
+
+              # ordinarily this would be POST to the normal URL, but we do PUT to
+              # /organizations/{organization}/policy_groups/{policy_group}/policies/{policy_name} with the full
+              # policy data, for each individual policy.
+              policy_datas = {}
+
+              object["policies"].each do |policy_name, policy_data|
+                policy_path = "/policies/#{policy_name}/revisions/#{policy_data["revision_id"]}"
+
+                get_data = begin
+                  rest.get(policy_path)
+                rescue Net::HTTPServerException => e
+                  raise "Could not find policy '#{policy_name}'' with revision '#{policy_data["revision_id"]}'' on the server"
+                end
+
+                # GET policy data
+                server_policy_data = Chef::JSONCompat.parse(get_data)
+
+                # if it comes back 404, raise an Exception with "Policy file X does not exist with revision Y on the server"
+
+                # otherwise, add it to the list of policyfile datas.
+                policy_datas[policy_name] = server_policy_data
+              end
+
+              begin
+                existing_group = Chef::JSONCompat.parse(self.read)
+              rescue NotFoundError
+                # It's OK if the group doesn't already exist, just means no existing policies
+              end
+
+              # now we have the fullpolicy data for each policies, which is what the PUT endpoint demands.
+              policy_datas.each do |policy_name, policy_data|
+                # PUT /organizations/ORG/policy_groups/GROUP/policies/NAME
+                rest.put("#{api_path}/policies/#{policy_name}", policy_data)
+              end
+
+              # Now we need to remove any policies that are *not* in our current group.
+              if existing_group && existing_group["policies"]
+                (existing_group["policies"].keys - policy_datas.keys).each do |policy_name|
+                  rest.delete("#{api_path}/policies/#{policy_name}")
+                end
+              end
+
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+            rescue Net::HTTPServerException => e
+              # 404 = NotFoundError
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              # 409 = AlreadyExistsError
+              elsif $!.response.code == "409"
+                raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+              # Anything else is unexpected (OperationFailedError)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+              end
+            end
+
+            self
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb b/lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb
new file mode 100644
index 0000000..7243996
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_groups_dir.rb
@@ -0,0 +1,43 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/chef_server/policy_group_entry"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class PolicyGroupsDir < RestListDir
+          def make_child_entry(name, exists = nil)
+            PolicyGroupEntry.new(name, self, exists)
+          end
+
+          def create_child(name, file_contents)
+            entry = make_child_entry(name, true)
+            entry.write(file_contents)
+            @children = nil
+            entry
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb b/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb
new file mode 100644
index 0000000..d083383
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/policy_revision_entry.rb
@@ -0,0 +1,34 @@
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/data_handler/policy_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        # /policies/NAME-REVISION.json
+        # Represents the actual data at /organizations/ORG/policies/NAME/revisions/REVISION
+        class PolicyRevisionEntry < RestListEntry
+
+          # /policies/foo-1.0.0.json -> /policies/foo/revisions/1.0.0
+          def api_path(options = {})
+            "#{parent.api_path}/#{policy_name}/revisions/#{revision_id}"
+          end
+
+          def write(file_contents)
+            raise OperationNotAllowedError.new(:write, self, nil, "cannot be updated: policy revisions are immutable once uploaded. If you want to change the policy, create a new revision with your changes")
+          end
+
+          def policy_name
+            policy_name, revision_id = data_handler.name_and_revision(name)
+            policy_name
+          end
+
+          def revision_id
+            policy_name, revision_id = data_handler.name_and_revision(name)
+            revision_id
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb b/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb
new file mode 100644
index 0000000..488e9c0
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/rest_list_dir.rb
@@ -0,0 +1,178 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_entry"
+require "chef/chef_fs/file_system/not_found_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class RestListDir < BaseFSDir
+          def initialize(name, parent, api_path = nil, data_handler = nil)
+            super(name, parent)
+            @api_path = api_path || (parent.api_path == "" ? name : "#{parent.api_path}/#{name}")
+            @data_handler = data_handler
+          end
+
+          attr_reader :api_path
+          attr_reader :data_handler
+
+          def can_have_child?(name, is_dir)
+            name =~ /\.json$/ && !is_dir
+          end
+
+          #
+          # When talking to a modern (12.0+) Chef server
+          # knife list /
+          # -> /nodes
+          # -> /policies
+          # -> /policy_groups
+          # -> /roles
+          #
+          # 12.0 or 12.1 will fail when you do this:
+          # knife list / --recursive
+          # Because it thinks /policies exists, and when it tries to list its children
+          # it gets a 404 (indicating it actually doesn't exist).
+          #
+          # With this change, knife list / --recursive will list /policies as a real, empty directory.
+          #
+          # Alternately, we could have done some sort of detection when we listed the top level
+          # and determined which endpoints the server would support, and returned only those.
+          # So you wouldn't see /policies in that case at all.
+          # The issue with that is there's no efficient way to do it because we can't find out
+          # the server version directly, and can't ask the server for a list of the endpoints it supports.
+          #
+
+          #
+          # Does GET /<api_path>, assumes the result is of the format:
+          #
+          # {
+          #   "foo": "<api_path>/foo",
+          #   "bar": "<api_path>/bar",
+          # }
+          #
+          # Children are foo.json and bar.json in this case.
+          #
+          def children
+            begin
+              # Grab the names of the children, append json, and make child entries
+              @children ||= root.get_json(api_path).keys.sort.map do |key|
+                make_child_entry("#{key}.json", true)
+              end
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "Timeout retrieving children: #{e}")
+            rescue Net::HTTPServerException => e
+              # 404 = NotFoundError
+              if $!.response.code == "404"
+
+                if parent.is_a?(ChefServerRootDir)
+                  # GET /organizations/ORG/<container> returned 404, but that just might be because
+                  # we are talking to an older version of the server that doesn't support policies.
+                  # Do GET /orgqanizations/ORG to find out if the org exists at all.
+                  # TODO use server API version instead of a second network request.
+                  begin
+                    root.get_json(parent.api_path)
+                    # Return empty list if the organization exists but /policies didn't work
+                    []
+                  rescue Net::HTTPServerException => e
+                    if e.response.code == "404"
+                      raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+                    end
+                    raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+                  end
+                else
+                  raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+                end
+
+              # Anything else is unexpected (OperationFailedError)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e, "HTTP error retrieving children: #{e}")
+              end
+            end
+          end
+
+          #
+          # Does POST <api_path> with file_contents
+          #
+          def create_child(name, file_contents)
+            # Parse the contents to ensure they are valid JSON
+            begin
+              object = Chef::JSONCompat.parse(file_contents)
+            rescue Chef::Exceptions::JSON::ParseError => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Parse error reading JSON creating child '#{name}': #{e}")
+            end
+
+            # Create the child entry that will be returned
+            result = make_child_entry(name, true)
+
+            # Normalize the file_contents before post (add defaults, etc.)
+            if data_handler
+              object = data_handler.normalize_for_post(object, result)
+              data_handler.verify_integrity(object, result) do |error|
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, nil, "Error creating '#{name}': #{error}")
+              end
+            end
+
+            # POST /api_path with the normalized file_contents
+            begin
+              rest.post(api_path, object)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Timeout creating '#{name}': #{e}")
+            rescue Net::HTTPServerException => e
+              # 404 = NotFoundError
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              # 409 = AlreadyExistsError
+              elsif $!.response.code == "409"
+                raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e, "Failure creating '#{name}': #{path}/#{name} already exists")
+              # Anything else is unexpected (OperationFailedError)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e, "Failure creating '#{name}': #{e.message}")
+              end
+            end
+
+            # Clear the cache of children so that if someone asks for children
+            # again, we will get it again
+            @children = nil
+
+            result
+          end
+
+          def org
+            parent.org
+          end
+
+          def environment
+            parent.environment
+          end
+
+          def rest
+            parent.rest
+          end
+
+          def make_child_entry(name, exists = nil)
+            @children.select { |child| child.name == name }.first if @children
+            RestListEntry.new(name, self, exists)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb b/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb
new file mode 100644
index 0000000..5b9252b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/rest_list_entry.rb
@@ -0,0 +1,187 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/file_system/operation_failed_error"
+require "chef/role"
+require "chef/node"
+require "chef/json_compat"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class RestListEntry < BaseFSObject
+          def initialize(name, parent, exists = nil)
+            super(name, parent)
+            @exists = exists
+          end
+
+          def data_handler
+            parent.data_handler
+          end
+
+          def api_child_name
+            if name.length < 5 || name[-5, 5] != ".json"
+              raise "Invalid name #{path}: must end in .json"
+            end
+            name[0, name.length - 5]
+          end
+
+          def api_path
+            "#{parent.api_path}/#{api_child_name}"
+          end
+
+          def org
+            parent.org
+          end
+
+          def environment
+            parent.environment
+          end
+
+          def exists?
+            if @exists.nil?
+              begin
+                @exists = parent.children.any? { |child| child.name == name }
+              rescue Chef::ChefFS::FileSystem::NotFoundError
+                @exists = false
+              end
+            end
+            @exists
+          end
+
+          def delete(recurse)
+            begin
+              rest.delete(api_path)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+            rescue Net::HTTPServerException => e
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e, "Timeout deleting: #{e}")
+              end
+            end
+          end
+
+          def read
+            Chef::JSONCompat.to_json_pretty(minimize_value(_read_json))
+          end
+
+          def _read_json
+            begin
+              # Minimize the value (get rid of defaults) so the results don't look terrible
+              root.get_json(api_path)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "Timeout reading: #{e}")
+            rescue Net::HTTPServerException => e
+              if $!.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e, "HTTP error reading: #{e}")
+              end
+            end
+          end
+
+          def chef_object
+            # REST will inflate the Chef object using json_class
+            data_handler.json_class.from_hash(read)
+          end
+
+          def minimize_value(value)
+            data_handler.minimize(data_handler.normalize(value, self), self)
+          end
+
+          def compare_to(other)
+            # TODO this pair of reads can be parallelized
+
+            # Grab the other value
+            begin
+              other_value_json = other.read
+            rescue Chef::ChefFS::FileSystem::NotFoundError
+              return [ nil, nil, :none ]
+            end
+
+            # Grab this value
+            begin
+              value = _read_json
+            rescue Chef::ChefFS::FileSystem::NotFoundError
+              return [ false, :none, other_value_json ]
+            end
+
+            # Minimize (and normalize) both values for easy and beautiful diffs
+            value = minimize_value(value)
+            value_json = Chef::JSONCompat.to_json_pretty(value)
+            begin
+              other_value = Chef::JSONCompat.parse(other_value_json)
+            rescue Chef::Exceptions::JSON::ParseError => e
+              Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}")
+              return [ nil, value_json, other_value_json ]
+            end
+            other_value = minimize_value(other_value)
+            other_value_json = Chef::JSONCompat.to_json_pretty(other_value)
+
+            [ value == other_value, value_json, other_value_json ]
+          end
+
+          def rest
+            parent.rest
+          end
+
+          def write(file_contents)
+            begin
+              object = Chef::JSONCompat.parse(file_contents)
+            rescue Chef::Exceptions::JSON::ParseError => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Parse error reading JSON: #{e}")
+            end
+
+            if data_handler
+              object = data_handler.normalize_for_put(object, self)
+              data_handler.verify_integrity(object, self) do |error|
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, nil, "#{error}")
+              end
+            end
+
+            begin
+              rest.put(api_path, object)
+            rescue Timeout::Error => e
+              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "Timeout writing: #{e}")
+            rescue Net::HTTPServerException => e
+              if e.response.code == "404"
+                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
+              else
+                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e, "HTTP error writing: #{e}")
+              end
+            end
+          end
+
+          def api_error_text(response)
+            begin
+              Chef::JSONCompat.parse(response.body)["error"].join("\n")
+            rescue
+              response.body
+            end
+          end
+        end
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
new file mode 100644
index 0000000..269e160
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbook_dir.rb
@@ -0,0 +1,45 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        class VersionedCookbookDir < CookbookDir
+          # See Erchef code
+          # https://github.com/opscode/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
+          VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/
+
+          def initialize(name, parent, options = {})
+            super(name, parent)
+            # If the name is apache2-1.0.0 and versioned_cookbooks is on, we know
+            # the actual cookbook_name and version.
+            if name =~ VALID_VERSIONED_COOKBOOK_NAME
+              @cookbook_name = $1
+              @version = $2
+            else
+              @exists = false
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
new file mode 100644
index 0000000..9abafed
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_server/versioned_cookbooks_dir.rb
@@ -0,0 +1,107 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/chef_server/cookbooks_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module ChefServer
+        #
+        # /cookbooks or /cookbook_artifacts
+        #
+        # Example children of /cookbooks:
+        #
+        # - apache2-1.0.0
+        # - apache2-1.0.1
+        # - mysql-2.0.5
+        #
+        # Example children of /cookbook_artifacts:
+        #
+        # - apache2-ab234098245908ddf324a
+        # - apache2-295387a9823745feff239
+        # - mysql-1a2b9e1298734dfe90444
+        #
+        class VersionedCookbooksDir < CookbooksDir
+
+          def make_child_entry(name)
+            result = @children.select { |child| child.name == name }.first if @children
+            result || VersionedCookbookDir.new(name, self)
+          end
+
+          def children
+            @children ||= begin
+              result = []
+              root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
+                cookbooks["versions"].each do |cookbook_version|
+                  result << VersionedCookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self)
+                end
+              end
+              result.sort_by(&:name)
+            end
+          end
+
+          # Knife currently does not understand versioned cookbooks
+          # Cookbook Version uploader also requires a lot of refactoring
+          # to make this work. So instead, we make a temporary cookbook
+          # symlinking back to real cookbook, and upload the proxy.
+          def upload_cookbook(other, options)
+            cookbook_name = Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name)
+
+            Dir.mktmpdir do |temp_cookbooks_path|
+              proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
+
+              # Make a symlink
+              file_class.symlink other.file_path, proxy_cookbook_path
+
+              # Instantiate a proxy loader using the temporary symlink
+              proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
+              proxy_loader.load_cookbooks
+
+              cookbook_to_upload = proxy_loader.cookbook_version
+              cookbook_to_upload.freeze_version if options[:freeze]
+
+              # Instantiate a new uploader based on the proxy loader
+              uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
+
+              with_actual_cookbooks_dir(temp_cookbooks_path) do
+                uploader.upload_cookbooks
+              end
+
+              #
+              # When the temporary directory is being deleted on
+              # windows, the contents of the symlink under that
+              # directory is also deleted. So explicitly remove
+              # the symlink without removing the original contents if we
+              # are running on windows
+              #
+              if Chef::Platform.windows?
+                Dir.rmdir proxy_cookbook_path
+              end
+            end
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir && name =~ Chef::ChefFS::FileSystem::ChefServer::VersionedCookbookDir::VALID_VERSIONED_COOKBOOK_NAME
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
deleted file mode 100644
index 370308e..0000000
--- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/server_api'
-require 'chef/chef_fs/file_system/acls_dir'
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbooks_dir'
-require 'chef/chef_fs/file_system/data_bags_dir'
-require 'chef/chef_fs/file_system/nodes_dir'
-require 'chef/chef_fs/file_system/org_entry'
-require 'chef/chef_fs/file_system/organization_invites_entry'
-require 'chef/chef_fs/file_system/organization_members_entry'
-require 'chef/chef_fs/file_system/environments_dir'
-require 'chef/chef_fs/data_handler/client_data_handler'
-require 'chef/chef_fs/data_handler/role_data_handler'
-require 'chef/chef_fs/data_handler/user_data_handler'
-require 'chef/chef_fs/data_handler/group_data_handler'
-require 'chef/chef_fs/data_handler/container_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      #
-      # Represents the root of a Chef server (or organization), under which
-      # nodes, roles, cookbooks, etc. can be found.
-      #
-      class ChefServerRootDir < BaseFSDir
-        #
-        # Create a new Chef server root.
-        #
-        # == Parameters
-        #
-        # [root_name]
-        #   A friendly name for the root, for printing--like "remote" or "chef_central".
-        # [chef_config]
-        #   A hash with options that look suspiciously like Chef::Config, including the
-        #   following keys:
-        #   :chef_server_url:: The URL to the Chef server or top of the organization
-        #   :node_name:: The username to authenticate to the Chef server with
-        #   :client_key:: The private key for the user for authentication
-        #   :environment:: The environment in which you are presently working
-        #   :repo_mode::
-        #     The repository mode, :hosted_everything, :everything or :static.
-        #     This determines the set of subdirectories the Chef server will
-        #     offer up.
-        #   :versioned_cookbooks:: whether or not to include versions in cookbook names
-        # [options]
-        #   Other options:
-        #   :cookbook_version:: when cookbooks are retrieved, grab this version for them.
-        #   :freeze:: freeze cookbooks on upload
-        #
-        def initialize(root_name, chef_config, options = {})
-          super("", nil)
-          @chef_server_url = chef_config[:chef_server_url]
-          @chef_username = chef_config[:node_name]
-          @chef_private_key = chef_config[:client_key]
-          @environment = chef_config[:environment]
-          @repo_mode = chef_config[:repo_mode]
-          @versioned_cookbooks = chef_config[:versioned_cookbooks]
-          @root_name = root_name
-          @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version
-        end
-
-        attr_reader :chef_server_url
-        attr_reader :chef_username
-        attr_reader :chef_private_key
-        attr_reader :environment
-        attr_reader :repo_mode
-        attr_reader :cookbook_version
-        attr_reader :versioned_cookbooks
-
-        def fs_description
-          "Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}"
-        end
-
-        def rest
-          Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true)
-        end
-
-        def get_json(path)
-          Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key).get(path)
-        end
-
-        def chef_rest
-          Chef::REST.new(chef_server_url, chef_username, chef_private_key)
-        end
-
-        def api_path
-          ""
-        end
-
-        def path_for_printing
-          "#{@root_name}/"
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir && children.any? { |child| child.name == name }
-        end
-
-        def org
-          @org ||= begin
-            path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
-            if File.dirname(path) == '/organizations'
-              File.basename(path)
-            else
-              nil
-            end
-          end
-        end
-
-        def children
-          @children ||= begin
-            result = [
-              CookbooksDir.new(self),
-              DataBagsDir.new(self),
-              EnvironmentsDir.new(self),
-              RestListDir.new("roles", self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new)
-            ]
-            if repo_mode == 'hosted_everything'
-              result += [
-                AclsDir.new(self),
-                RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
-                RestListDir.new("containers", self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new),
-                RestListDir.new("groups", self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new),
-                NodesDir.new(self),
-                OrgEntry.new("org.json", self),
-                OrganizationMembersEntry.new("members.json", self),
-                OrganizationInvitesEntry.new("invitations.json", self)
-              ]
-            elsif repo_mode != 'static'
-              result += [
-                RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new),
-                NodesDir.new(self),
-                RestListDir.new("users", self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new)
-              ]
-            end
-            result.sort_by { |child| child.name }
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_dir.rb b/lib/chef/chef_fs/file_system/cookbook_dir.rb
deleted file mode 100644
index 03652dc..0000000
--- a/lib/chef/chef_fs/file_system/cookbook_dir.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbook_subdir'
-require 'chef/chef_fs/file_system/cookbook_file'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/cookbook_version'
-require 'chef/cookbook_uploader'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class CookbookDir < BaseFSDir
-        def initialize(name, parent, options = {})
-          super(name, parent)
-          @exists = options[:exists]
-          # If the name is apache2-1.0.0 and versioned_cookbooks is on, we know
-          # the actual cookbook_name and version.
-          if root.versioned_cookbooks
-            if name =~ VALID_VERSIONED_COOKBOOK_NAME
-              @cookbook_name = $1
-              @version = $2
-            else
-              @exists = false
-            end
-          else
-            @cookbook_name = name
-            @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff
-          end
-        end
-
-        attr_reader :cookbook_name, :version
-
-        COOKBOOK_SEGMENT_INFO = {
-          :attributes => { :ruby_only => true },
-          :definitions => { :ruby_only => true },
-          :recipes => { :ruby_only => true },
-          :libraries => { :ruby_only => true },
-          :templates => { :recursive => true },
-          :files => { :recursive => true },
-          :resources => { :ruby_only => true, :recursive => true },
-          :providers => { :ruby_only => true, :recursive => true },
-          :root_files => { }
-        }
-
-        # See Erchef code
-        # https://github.com/opscode/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94
-        VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/
-
-        def add_child(child)
-          @children << child
-        end
-
-        def api_path
-          "#{parent.api_path}/#{cookbook_name}/#{version || "_latest"}"
-        end
-
-        def child(name)
-          # Since we're ignoring the rules and doing a network request here,
-          # we need to make sure we don't rethrow the exception.  (child(name)
-          # is not supposed to fail.)
-          begin
-            result = children.select { |child| child.name == name }.first
-            return result if result
-          rescue Chef::ChefFS::FileSystem::NotFoundError
-          end
-          return NonexistentFSObject.new(name, self)
-        end
-
-        def can_have_child?(name, is_dir)
-          # A cookbook's root may not have directories unless they are segment directories
-          return name != 'root_files' && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir
-          return true
-        end
-
-        def children
-          if @children.nil?
-            @children = []
-            manifest = chef_object.manifest
-            COOKBOOK_SEGMENT_INFO.each do |segment, segment_info|
-              next unless manifest.has_key?(segment)
-
-              # Go through each file in the manifest for the segment, and
-              # add cookbook subdirs and files for it.
-              manifest[segment].each do |segment_file|
-                parts = segment_file[:path].split('/')
-                # Get or create the path to the file
-                container = self
-                parts[0,parts.length-1].each do |part|
-                  old_container = container
-                  container = old_container.children.select { |child| part == child.name }.first
-                  if !container
-                    container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive])
-                    old_container.add_child(container)
-                  end
-                end
-                # Create the file itself
-                container.add_child(CookbookFile.new(parts[parts.length-1], container, segment_file))
-              end
-            end
-            @children = @children.sort_by { |c| c.name }
-          end
-          @children
-        end
-
-        def dir?
-          exists?
-        end
-
-        def delete(recurse)
-          if recurse
-            begin
-              rest.delete(api_path)
-            rescue Timeout::Error => e
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
-            rescue Net::HTTPServerException
-              if $!.response.code == "404"
-                raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-              else
-                raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
-              end
-            end
-          else
-            raise NotFoundError.new(self) if !exists?
-            raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
-          end
-        end
-
-        # In versioned cookbook mode, actually check if the version exists
-        # Probably want to cache this.
-        def exists?
-          if @exists.nil?
-            @exists = parent.children.any? { |child| child.name == name }
-          end
-          @exists
-        end
-
-        def compare_to(other)
-          if !other.dir?
-            return [ !exists?, nil, nil ]
-          end
-          are_same = true
-          Chef::ChefFS::CommandLine::diff_entries(self, other, nil, :name_only).each do |type, old_entry, new_entry|
-            if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type)
-              are_same = false
-            end
-          end
-          [ are_same, nil, nil ]
-        end
-
-        def copy_from(other, options = {})
-          parent.upload_cookbook_from(other, options)
-        end
-
-        def rest
-          parent.rest
-        end
-
-        def chef_object
-          # We cheat and cache here, because it seems like a good idea to keep
-          # the cookbook view consistent with the directory structure.
-          return @chef_object if @chef_object
-
-          # The negative (not found) response is cached
-          if @could_not_get_chef_object
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
-          end
-
-          begin
-            # We want to fail fast, for now, because of the 500 issue :/
-            # This will make things worse for parallelism, a little, because
-            # Chef::Config is global and this could affect other requests while
-            # this request is going on.  (We're not parallel yet, but we will be.)
-            # Chef bug http://tickets.opscode.com/browse/CHEF-3066
-            old_retry_count = Chef::Config[:http_retry_count]
-            begin
-              Chef::Config[:http_retry_count] = 0
-              @chef_object ||= Chef::CookbookVersion.json_create(root.get_json(api_path))
-            ensure
-              Chef::Config[:http_retry_count] = old_retry_count
-            end
-
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
-
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              @could_not_get_chef_object = e
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
-            end
-
-          # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now.
-          # Remove this when that bug is fixed.
-          rescue Net::HTTPFatalError => e
-            if e.response.code == "500"
-              @could_not_get_chef_object = e
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
-            end
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_file.rb b/lib/chef/chef_fs/file_system/cookbook_file.rb
deleted file mode 100644
index 16203b7..0000000
--- a/lib/chef/chef_fs/file_system/cookbook_file.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/http/simple'
-require 'openssl'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class CookbookFile < BaseFSObject
-        def initialize(name, parent, file)
-          super(name, parent)
-          @file = file
-        end
-
-        attr_reader :file
-
-        def checksum
-          file[:checksum]
-        end
-
-        def read
-          begin
-            tmpfile = rest.streaming_request(file[:url])
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}"
-          rescue Net::HTTPServerException => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}"
-          end
-
-          begin
-            tmpfile.open
-            tmpfile.read
-          ensure
-            tmpfile.close!
-          end
-        end
-
-        def rest
-          parent.rest
-        end
-
-        def compare_to(other)
-          other_value = nil
-          if other.respond_to?(:checksum)
-            other_checksum = other.checksum
-          else
-            begin
-              other_value = other.read
-            rescue Chef::ChefFS::FileSystem::NotFoundError
-              return [ false, nil, :none ]
-            end
-            other_checksum = calc_checksum(other_value)
-          end
-          [ checksum == other_checksum, nil, other_value ]
-        end
-
-        private
-
-        def calc_checksum(value)
-          OpenSSL::Digest::MD5.hexdigest(value)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb b/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb
index 7056733..20ac6f1 100644
--- a/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb
+++ b/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/already_exists_error'
+require "chef/chef_fs/file_system/already_exists_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class CookbookFrozenError < AlreadyExistsError
-        def initialize(operation, entry, cause = nil)
-          super(operation, entry, cause)
-        end
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/cookbook_subdir.rb b/lib/chef/chef_fs/file_system/cookbook_subdir.rb
deleted file mode 100644
index 73c709e..0000000
--- a/lib/chef/chef_fs/file_system/cookbook_subdir.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class CookbookSubdir < BaseFSDir
-        def initialize(name, parent, ruby_only, recursive)
-          super(name, parent)
-          @children = []
-          @ruby_only = ruby_only
-          @recursive = recursive
-        end
-
-        attr_reader :versions
-        attr_reader :children
-
-        def add_child(child)
-          @children << child
-        end
-
-        def can_have_child?(name, is_dir)
-          if is_dir
-            return false if !@recursive
-          else
-            return false if @ruby_only && name !~ /\.rb$/
-          end
-          true
-        end
-
-        def rest
-          parent.rest
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb
deleted file mode 100644
index d6246f1..0000000
--- a/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/acl_dir'
-require 'chef/chef_fs/file_system/acl_entry'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class CookbooksAclDir < AclDir
-        # If versioned_cookbooks is on, the list of cookbooks will have versions
-        # in them.  But all versions of a cookbook have the same acl, so even if
-        # we have cookbooks/apache2-1.0.0 and cookbooks/apache2-1.1.2, we will
-        # only have one acl: acls/cookbooks/apache2.json.  Thus, the list of
-        # children of acls/cookbooks is a unique list of cookbook *names*.
-        def children
-          if @children.nil?
-            names = parent.parent.child(name).children.map { |child| "#{child.cookbook_name}.json" }
-            @children = names.uniq.map { |name| AclEntry.new(name, self, true) }
-          end
-          @children
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
deleted file mode 100644
index 27bedd3..0000000
--- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/cookbook_dir'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/file_system/cookbook_frozen_error'
-require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir'
-require 'chef/mixin/file_class'
-
-require 'tmpdir'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class CookbooksDir < RestListDir
-
-        include Chef::Mixin::FileClass
-
-        def initialize(parent)
-          super("cookbooks", parent)
-        end
-
-        def child(name)
-          if @children
-            result = self.children.select { |child| child.name == name }.first
-            if result
-              result
-            else
-              NonexistentFSObject.new(name, self)
-            end
-          else
-            CookbookDir.new(name, self)
-          end
-        end
-
-        def children
-          @children ||= begin
-            if root.versioned_cookbooks
-              result = []
-              root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
-                cookbooks['versions'].each do |cookbook_version|
-                  result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true)
-                end
-              end
-            else
-              result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) }
-            end
-            result.sort_by(&:name)
-          end
-        end
-
-        def create_child_from(other, options = {})
-          @children = nil
-          upload_cookbook_from(other, options)
-        end
-
-        def upload_cookbook_from(other, options = {})
-          root.versioned_cookbooks ? upload_versioned_cookbook(other, options) : upload_unversioned_cookbook(other, options)
-        rescue Timeout::Error => e
-          raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
-        rescue Net::HTTPServerException => e
-          case e.response.code
-          when "409"
-            raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
-          else
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
-          end
-        rescue Chef::Exceptions::CookbookFrozen => e
-          raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen"
-        end
-
-        # Knife currently does not understand versioned cookbooks
-        # Cookbook Version uploader also requires a lot of refactoring
-        # to make this work. So instead, we make a temporary cookbook
-        # symlinking back to real cookbook, and upload the proxy.
-        def upload_versioned_cookbook(other, options)
-          cookbook_name = Chef::ChefFS::FileSystem::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name)
-
-          Dir.mktmpdir do |temp_cookbooks_path|
-            proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
-
-            # Make a symlink
-            file_class.symlink other.file_path, proxy_cookbook_path
-
-            # Instantiate a proxy loader using the temporary symlink
-            proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
-            proxy_loader.load_cookbooks
-
-            cookbook_to_upload = proxy_loader.cookbook_version
-            cookbook_to_upload.freeze_version if options[:freeze]
-
-            # Instantiate a new uploader based on the proxy loader
-            uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
-
-            with_actual_cookbooks_dir(temp_cookbooks_path) do
-              upload_cookbook!(uploader)
-            end
-
-            #
-            # When the temporary directory is being deleted on
-            # windows, the contents of the symlink under that
-            # directory is also deleted. So explicitly remove
-            # the symlink without removing the original contents if we
-            # are running on windows
-            #
-            if Chef::Platform.windows?
-              Dir.rmdir proxy_cookbook_path
-            end
-          end
-        end
-
-        def upload_unversioned_cookbook(other, options)
-          cookbook_to_upload = other.chef_object
-          cookbook_to_upload.freeze_version if options[:freeze]
-          uploader = Chef::CookbookUploader.new(cookbook_to_upload, :force => options[:force], :rest => root.chef_rest)
-
-          with_actual_cookbooks_dir(other.parent.file_path) do
-            upload_cookbook!(uploader)
-          end
-        end
-
-        # Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet)
-        def with_actual_cookbooks_dir(actual_cookbook_path)
-          old_cookbook_path = Chef::Config.cookbook_path
-          Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path
-
-          yield
-        ensure
-          Chef::Config.cookbook_path = old_cookbook_path
-        end
-
-        def upload_cookbook!(uploader, options = {})
-          if uploader.respond_to?(:upload_cookbook)
-            uploader.upload_cookbook
-          else
-            uploader.upload_cookbooks
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          return false if !is_dir
-          return false if root.versioned_cookbooks && name !~ Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME
-          return true
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/data_bag_dir.rb b/lib/chef/chef_fs/file_system/data_bag_dir.rb
deleted file mode 100644
index 212f76f..0000000
--- a/lib/chef/chef_fs/file_system/data_bag_dir.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/must_delete_recursively_error'
-require 'chef/chef_fs/data_handler/data_bag_item_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class DataBagDir < RestListDir
-        def initialize(name, parent, exists = nil)
-          super(name, parent, nil, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
-          @exists = nil
-        end
-
-        def dir?
-          exists?
-        end
-
-        def read
-          # This will only be called if dir? is false, which means exists? is false.
-          raise Chef::ChefFS::FileSystem::NotFoundError.new(self)
-        end
-
-        def exists?
-          if @exists.nil?
-            @exists = parent.children.any? { |child| child.name == name }
-          end
-          @exists
-        end
-
-        def delete(recurse)
-          if !recurse
-            raise NotFoundError.new(self) if !exists?
-            raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
-          end
-          begin
-            rest.delete(api_path)
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}"
-            end
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/data_bags_dir.rb b/lib/chef/chef_fs/file_system/data_bags_dir.rb
deleted file mode 100644
index 6d0685d..0000000
--- a/lib/chef/chef_fs/file_system/data_bags_dir.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/data_bag_dir'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class DataBagsDir < RestListDir
-        def initialize(parent)
-          super("data_bags", parent, "data")
-        end
-
-        def child(name)
-          result = @children.select { |child| child.name == name }.first if @children
-          result || DataBagDir.new(name, self)
-        end
-
-        def children
-          begin
-            @children ||= root.get_json(api_path).keys.sort.map do |entry|
-              DataBagDir.new(entry, self, true)
-            end
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout getting children: #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error getting children: #{e}"
-            end
-          end
-        end
-
-        def can_have_child?(name, is_dir)
-          is_dir
-        end
-
-        def create_child(name, file_contents)
-          begin
-            rest.post(api_path, { 'name' => name })
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "409"
-              raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Cannot create #{name} under #{path}: already exists"
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "HTTP error creating child '#{name}': #{e}"
-            end
-          end
-          @children = nil
-          DataBagDir.new(name, self, true)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb b/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
index 8ca3b91..e55f97d 100644
--- a/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
+++ b/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/operation_not_allowed_error'
+require "chef/chef_fs/file_system/operation_not_allowed_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class DefaultEnvironmentCannotBeModifiedError < OperationNotAllowedError
-        def initialize(operation, entry, cause = nil)
-          super(operation, entry, cause)
-        end
-
         def reason
           result = super
           result + " (default environment cannot be modified)"
diff --git a/lib/chef/chef_fs/file_system/environments_dir.rb b/lib/chef/chef_fs/file_system/environments_dir.rb
deleted file mode 100644
index 559dd6a..0000000
--- a/lib/chef/chef_fs/file_system/environments_dir.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error'
-require 'chef/chef_fs/data_handler/environment_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class EnvironmentsDir < RestListDir
-        def initialize(parent)
-          super("environments", parent, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new)
-        end
-
-        def _make_child_entry(name, exists = nil)
-          if name == '_default.json'
-            DefaultEnvironmentEntry.new(name, self, exists)
-          else
-            super
-          end
-        end
-
-        class DefaultEnvironmentEntry < RestListEntry
-          def initialize(name, parent, exists = nil)
-            super(name, parent)
-            @exists = exists
-          end
-
-          def delete(recurse)
-            raise NotFoundError.new(self) if !exists?
-            raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self), "#{path_for_printing} cannot be deleted."
-          end
-
-          def write(file_contents)
-            raise NotFoundError.new(self) if !exists?
-            raise DefaultEnvironmentCannotBeModifiedError.new(:write, self), "#{path_for_printing} cannot be updated."
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/file_system_entry.rb b/lib/chef/chef_fs/file_system/file_system_entry.rb
deleted file mode 100644
index 1af7e61..0000000
--- a/lib/chef/chef_fs/file_system/file_system_entry.rb
+++ /dev/null
@@ -1,108 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_dir'
-require 'chef/chef_fs/file_system/already_exists_error'
-require 'chef/chef_fs/file_system/must_delete_recursively_error'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/path_utils'
-require 'fileutils'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class FileSystemEntry < BaseFSDir
-        def initialize(name, parent, file_path = nil)
-          super(name, parent)
-          @file_path = file_path || "#{parent.file_path}/#{name}"
-        end
-
-        attr_reader :file_path
-
-        def path_for_printing
-          file_path
-        end
-
-        def children
-          begin
-            Dir.entries(file_path).sort.select { |entry| entry != '.' && entry != '..' }.map { |entry| make_child(entry) }
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        def create_child(child_name, file_contents=nil)
-          child = make_child(child_name)
-          if child.exists?
-            raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
-          end
-          if file_contents
-            child.write(file_contents)
-          else
-            begin
-              Dir.mkdir(child.file_path)
-            rescue Errno::EEXIST
-              raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
-            end
-          end
-          child
-        end
-
-        def dir?
-          File.directory?(file_path)
-        end
-
-        def delete(recurse)
-          if dir?
-            if !recurse
-              raise MustDeleteRecursivelyError.new(self, $!)
-            end
-            FileUtils.rm_rf(file_path)
-          else
-            File.delete(file_path)
-          end
-        end
-
-        def exists?
-          File.exists?(file_path)
-        end
-
-        def read
-          begin
-            File.open(file_path, "rb") {|f| f.read}
-          rescue Errno::ENOENT
-            raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-          end
-        end
-
-        def write(content)
-          File.open(file_path, 'wb') do |file|
-            file.write(content)
-          end
-        end
-
-        protected
-
-        def make_child(child_name)
-          FileSystemEntry.new(child_name, self)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/file_system_error.rb b/lib/chef/chef_fs/file_system/file_system_error.rb
index 80aff35..1a2a19d 100644
--- a/lib/chef/chef_fs/file_system/file_system_error.rb
+++ b/lib/chef/chef_fs/file_system/file_system_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,13 +20,24 @@ class Chef
   module ChefFS
     module FileSystem
       class FileSystemError < StandardError
-        def initialize(entry, cause = nil)
+        # @param entry The entry which had an issue.
+        # @param cause The wrapped exception (if any).
+        # @param reason A string describing why this exception happened.
+        def initialize(entry, cause = nil, reason = nil)
+          super(reason)
           @entry = entry
           @cause = cause
+          @reason = reason
         end
 
+        # The entry which had an issue.
         attr_reader :entry
+
+        # The wrapped exception (if any).
         attr_reader :cause
+
+        # A string describing why this exception happened.
+        attr_reader :reason
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/file_system_root_dir.rb b/lib/chef/chef_fs/file_system/file_system_root_dir.rb
deleted file mode 100644
index afbf7b1..0000000
--- a/lib/chef/chef_fs/file_system/file_system_root_dir.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/file_system_entry'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class FileSystemRootDir < FileSystemEntry
-        def initialize(file_path)
-          super("", nil, file_path)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_dir.rb b/lib/chef/chef_fs/file_system/memory/memory_dir.rb
new file mode 100644
index 0000000..beb6614
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_dir.rb
@@ -0,0 +1,53 @@
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/memory/memory_file"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Memory
+        class MemoryDir < Chef::ChefFS::FileSystem::BaseFSDir
+          def initialize(name, parent)
+            super(name, parent)
+            @children = []
+          end
+
+          attr_reader :children
+
+          def make_child_entry(name)
+            @children.select { |child| child.name == name }.first
+          end
+
+          def add_child(child)
+            @children.push(child)
+          end
+
+          def can_have_child?(name, is_dir)
+            root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
+          end
+
+          def add_file(path, value)
+            path_parts = path.split("/")
+            dir = add_dir(path_parts[0..-2].join("/"))
+            file = MemoryFile.new(path_parts[-1], dir, value)
+            dir.add_child(file)
+            file
+          end
+
+          def add_dir(path)
+            path_parts = path.split("/")
+            dir = self
+            path_parts.each do |path_part|
+              subdir = dir.child(path_part)
+              if !subdir.exists?
+                subdir = MemoryDir.new(path_part, dir)
+                dir.add_child(subdir)
+              end
+              dir = subdir
+            end
+            dir
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_file.rb b/lib/chef/chef_fs/file_system/memory/memory_file.rb
new file mode 100644
index 0000000..7eabc8f
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_file.rb
@@ -0,0 +1,20 @@
+require "chef/chef_fs/file_system/base_fs_object"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Memory
+        class MemoryFile < Chef::ChefFS::FileSystem::BaseFSObject
+          def initialize(name, parent, value)
+            super(name, parent)
+            @value = value
+          end
+
+          def read
+            return @value
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/memory/memory_root.rb b/lib/chef/chef_fs/file_system/memory/memory_root.rb
new file mode 100644
index 0000000..4881b3d
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/memory/memory_root.rb
@@ -0,0 +1,23 @@
+require "chef/chef_fs/file_system/memory/memory_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Memory
+        class MemoryRoot < MemoryDir
+          def initialize(pretty_name, cannot_be_in_regex = nil)
+            super("", nil)
+            @pretty_name = pretty_name
+            @cannot_be_in_regex = cannot_be_in_regex
+          end
+
+          attr_reader :cannot_be_in_regex
+
+          def path_for_printing
+            @pretty_name
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/memory_dir.rb b/lib/chef/chef_fs/file_system/memory_dir.rb
deleted file mode 100644
index a7eda3c..0000000
--- a/lib/chef/chef_fs/file_system/memory_dir.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
-require 'chef/chef_fs/file_system/memory_file'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class MemoryDir < Chef::ChefFS::FileSystem::BaseFSDir
-        def initialize(name, parent)
-          super(name, parent)
-          @children = []
-        end
-
-        attr_reader :children
-
-        def child(name)
-          @children.select { |child| child.name == name }.first || Chef::ChefFS::FileSystem::NonexistentFSObject.new(name, self)
-        end
-
-        def add_child(child)
-          @children.push(child)
-        end
-
-        def can_have_child?(name, is_dir)
-          root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true
-        end
-
-        def add_file(path, value)
-          path_parts = path.split('/')
-          dir = add_dir(path_parts[0..-2].join('/'))
-          file = MemoryFile.new(path_parts[-1], dir, value)
-          dir.add_child(file)
-          file
-        end
-
-        def add_dir(path)
-          path_parts = path.split('/')
-          dir = self
-          path_parts.each do |path_part|
-            subdir = dir.child(path_part)
-            if !subdir.exists?
-              subdir = MemoryDir.new(path_part, dir)
-              dir.add_child(subdir)
-            end
-            dir = subdir
-          end
-          dir
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/memory_file.rb b/lib/chef/chef_fs/file_system/memory_file.rb
deleted file mode 100644
index 0c44e70..0000000
--- a/lib/chef/chef_fs/file_system/memory_file.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'chef/chef_fs/file_system/base_fs_object'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class MemoryFile < Chef::ChefFS::FileSystem::BaseFSObject
-        def initialize(name, parent, value)
-          super(name, parent)
-          @value = value
-        end
-        def read
-          return @value
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/memory_root.rb b/lib/chef/chef_fs/file_system/memory_root.rb
deleted file mode 100644
index 4a83830..0000000
--- a/lib/chef/chef_fs/file_system/memory_root.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'chef/chef_fs/file_system/memory_dir'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class MemoryRoot < MemoryDir
-        def initialize(pretty_name, cannot_be_in_regex = nil)
-          super('', nil)
-          @pretty_name = pretty_name
-          @cannot_be_in_regex = cannot_be_in_regex
-        end
-
-        attr_reader :cannot_be_in_regex
-
-        def path_for_printing
-          @pretty_name
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/multiplexed_dir.rb b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
index 06d4af7..e143dde 100644
--- a/lib/chef/chef_fs/file_system/multiplexed_dir.rb
+++ b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
@@ -1,5 +1,5 @@
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/nonexistent_fs_object'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/nonexistent_fs_object"
 
 class Chef
   module ChefFS
@@ -35,6 +35,21 @@ class Chef
           end
         end
 
+        def make_child_entry(name)
+          result = nil
+          multiplexed_dirs.each do |dir|
+            child_entry = dir.child(name)
+            if child_entry.exists?
+              if result
+                Chef::Log.warn("Child with name '#{child_entry.name}' found in multiple directories: #{result.parent.path_for_printing} and #{child_entry.parent.path_for_printing}")
+              else
+                result = child_entry
+              end
+            end
+          end
+          result
+        end
+
         def can_have_child?(name, is_dir)
           write_dir.can_have_child?(name, is_dir)
         end
diff --git a/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb b/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb
index bfa8ba2..5f538d8 100644
--- a/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb
+++ b/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/file_system/file_system_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class MustDeleteRecursivelyError < FileSystemError
-        def initialize(entry, cause = nil)
-          super(entry, cause)
-        end
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/nodes_dir.rb b/lib/chef/chef_fs/file_system/nodes_dir.rb
deleted file mode 100644
index c3c4837..0000000
--- a/lib/chef/chef_fs/file_system/nodes_dir.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/data_handler/node_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class NodesDir < RestListDir
-        def initialize(parent)
-          super("nodes", parent, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new)
-        end
-
-        # Identical to RestListDir.children, except supports environments
-        def children
-          begin
-            @children ||= root.get_json(env_api_path).keys.sort.map do |key|
-              _make_child_entry("#{key}.json", true)
-            end
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
-          rescue Net::HTTPServerException => e
-            if $!.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}"
-            end
-          end
-        end
-
-        def env_api_path
-          environment ? "environments/#{environment}/#{api_path}" : api_path
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb b/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
index a587ab4..81c0154 100644
--- a/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
+++ b/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/not_found_error'
+require "chef/chef_fs/file_system/base_fs_object"
+require "chef/chef_fs/file_system/not_found_error"
 
 class Chef
   module ChefFS
diff --git a/lib/chef/chef_fs/file_system/not_found_error.rb b/lib/chef/chef_fs/file_system/not_found_error.rb
index 9eab3d6..a7f66d7 100644
--- a/lib/chef/chef_fs/file_system/not_found_error.rb
+++ b/lib/chef/chef_fs/file_system/not_found_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/file_system/file_system_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class NotFoundError < FileSystemError
-        def initialize(entry, cause = nil)
-          super(entry, cause)
-        end
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/operation_failed_error.rb b/lib/chef/chef_fs/file_system/operation_failed_error.rb
index 28d170d..faf19c7 100644
--- a/lib/chef/chef_fs/file_system/operation_failed_error.rb
+++ b/lib/chef/chef_fs/file_system/operation_failed_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/file_system/file_system_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class OperationFailedError < FileSystemError
-        def initialize(operation, entry, cause = nil)
-          super(entry, cause)
+        def initialize(operation, entry, cause = nil, reason = nil)
+          super(entry, cause, reason)
           @operation = operation
         end
 
diff --git a/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb b/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb
index 4b4f974..ab93bc9 100644
--- a/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb
+++ b/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,30 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system/file_system_error'
+require "chef/chef_fs/file_system/file_system_error"
 
 class Chef
   module ChefFS
     module FileSystem
       class OperationNotAllowedError < FileSystemError
-        def initialize(operation, entry, cause = nil)
-          super(entry, cause)
+        def initialize(operation, entry, cause = nil, reason = nil)
+          reason ||=
+            case operation
+            when :delete
+              "cannot be deleted"
+            when :write
+              "cannot be updated"
+            when :create_child
+              "cannot have a child created under it"
+            when :read
+              "cannot be read"
+            end
+          super(entry, cause, reason)
           @operation = operation
         end
 
         attr_reader :operation
         attr_reader :entry
-
-        def reason
-          case operation
-          when :delete
-            "cannot be deleted"
-          when :write
-            "cannot be updated"
-          when :create_child
-            "cannot have a child created under it"
-          when :read
-            "cannot be read"
-          end
-        end
       end
     end
   end
diff --git a/lib/chef/chef_fs/file_system/org_entry.rb b/lib/chef/chef_fs/file_system/org_entry.rb
deleted file mode 100644
index 852956e..0000000
--- a/lib/chef/chef_fs/file_system/org_entry.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_data_handler'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      # /organizations/NAME/org.json
-      # Represents the actual data at /organizations/NAME (the full name, etc.)
-      class OrgEntry < RestListEntry
-        def initialize(name, parent, exists = nil)
-          super(name, parent)
-          @exists = exists
-        end
-
-        def data_handler
-          Chef::ChefFS::DataHandler::OrganizationDataHandler.new
-        end
-
-        # /organizations/foo/org.json -> GET /organizations/foo
-        def api_path
-          parent.api_path
-        end
-
-        def exists?
-          parent.exists?
-        end
-
-        def delete(recurse)
-          raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/organization_invites_entry.rb b/lib/chef/chef_fs/file_system/organization_invites_entry.rb
deleted file mode 100644
index 5df3708..0000000
--- a/lib/chef/chef_fs/file_system/organization_invites_entry.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_invites_data_handler'
-require 'chef/json_compat'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      # /organizations/NAME/invitations.json
-      # read data from:
-      # - GET /organizations/NAME/association_requests
-      # write data to:
-      # - remove from list: DELETE /organizations/NAME/association_requests/id
-      # - add to list: POST /organizations/NAME/association_requests
-      class OrganizationInvitesEntry < RestListEntry
-        def initialize(name, parent, exists = nil)
-          super(name, parent)
-          @exists = exists
-        end
-
-        def data_handler
-          Chef::ChefFS::DataHandler::OrganizationInvitesDataHandler.new
-        end
-
-        # /organizations/foo/invites.json -> /organizations/foo/association_requests
-        def api_path
-          File.join(parent.api_path, 'association_requests')
-        end
-
-        def exists?
-          parent.exists?
-        end
-
-        def delete(recurse)
-          raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
-        end
-
-        def write(contents)
-          desired_invites = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
-          actual_invites = _read_json.inject({}) { |h,val| h[val['username']] = val['id']; h }
-          invites = actual_invites.keys
-          (desired_invites - invites).each do |invite|
-            begin
-              rest.post(api_path, { 'user' => invite })
-            rescue Net::HTTPServerException => e
-              if e.response.code == '409'
-                Chef::Log.warn("Could not invite #{invite} to organization #{org}: #{api_error_text(e.response)}")
-              else
-                raise
-              end
-            end
-          end
-          (invites - desired_invites).each do |invite|
-            rest.delete(File.join(api_path, actual_invites[invite]))
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/organization_members_entry.rb b/lib/chef/chef_fs/file_system/organization_members_entry.rb
deleted file mode 100644
index 94393b3..0000000
--- a/lib/chef/chef_fs/file_system/organization_members_entry.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/data_handler/organization_members_data_handler'
-require 'chef/json_compat'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      # /organizations/NAME/members.json
-      # reads data from:
-      # - GET /organizations/NAME/users
-      # writes data to:
-      # - remove from list: DELETE /organizations/NAME/users/name
-      # - add to list: POST /organizations/NAME/users/name
-      class OrganizationMembersEntry < RestListEntry
-        def initialize(name, parent, exists = nil)
-          super(name, parent)
-          @exists = exists
-        end
-
-        def data_handler
-          Chef::ChefFS::DataHandler::OrganizationMembersDataHandler.new
-        end
-
-        # /organizations/foo/members.json -> /organizations/foo/users
-        def api_path
-          File.join(parent.api_path, 'users')
-        end
-
-        def exists?
-          parent.exists?
-        end
-
-        def delete(recurse)
-          raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self)
-        end
-
-        def write(contents)
-          desired_members = minimize_value(Chef::JSONCompat.parse(contents, :create_additions => false))
-          members = minimize_value(_read_json)
-          (desired_members - members).each do |member|
-            begin
-              rest.post(File.join(api_path, member), {})
-            rescue Net::HTTPServerException => e
-              if e.response.code == '404'
-                raise "Chef server at #{api_path} does not allow you to directly add members.  Please either upgrade your Chef server or move the users you want into invitations.json instead of members.json."
-              else
-                raise
-              end
-            end
-          end
-          (members - desired_members).each do |member|
-            rest.delete(File.join(api_path, member))
-          end
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb
new file mode 100644
index 0000000..c347e80
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb
@@ -0,0 +1,39 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/file_system/chef_server/acls_dir"
+require "chef/chef_fs/data_handler/acl_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry
+          def initialize(name, parent, path = nil)
+            super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new)
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir ? Chef::ChefFS::FileSystem::ChefServer::AclsDir::ENTITY_TYPES.include?(name) : name == "organization.json"
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb
new file mode 100644
index 0000000..83c13e5
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemCookbookArtifactDir < ChefRepositoryFileSystemCookbookDir
+          # Override from parent
+          def cookbook_version
+            loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+            cookbook_name, _dash, identifier = name.rpartition("-")
+            # KLUDGE: We shouldn't have to use instance_variable_set
+            loader.instance_variable_set(:@cookbook_name, cookbook_name)
+            loader.load_cookbooks
+            cookbook_version = loader.cookbook_version
+            cookbook_version.identifier = identifier
+            cookbook_version
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifacts_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifacts_dir.rb
new file mode 100644
index 0000000..c7e2827
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifacts_dir.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifact_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemCookbookArtifactsDir < ChefRepositoryFileSystemCookbooksDir
+          def make_child_entry(child_name)
+            ChefRepositoryFileSystemCookbookArtifactDir.new(child_name, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
new file mode 100644
index 0000000..4c600d8
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir.rb
@@ -0,0 +1,95 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry"
+require "chef/chef_fs/file_system/chef_server/cookbook_dir"
+require "chef/chef_fs/file_system/chef_server/versioned_cookbook_dir"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/cookbook/chefignore"
+require "chef/cookbook/cookbook_version_loader"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemCookbookDir < ChefRepositoryFileSystemCookbookEntry
+          def chef_object
+            begin
+              cb = cookbook_version
+              if !cb
+                Chef::Log.error("Cookbook #{file_path} empty.")
+                raise "Cookbook #{file_path} empty."
+              end
+              cb
+            rescue => e
+              Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{e}")
+              Chef::Log.error(e.backtrace.join("\n"))
+              raise
+            end
+          end
+
+          def children
+            super.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
+          end
+
+          def can_have_child?(name, is_dir)
+            if is_dir
+              # Only the given directories will be uploaded.
+              return Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != "root_files"
+            elsif name == Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE
+              return false
+            end
+            super(name, is_dir)
+          end
+
+          # Exposed as a class method so that it can be used elsewhere
+          def self.canonical_cookbook_name(entry_name)
+            name_match = Chef::ChefFS::FileSystem::ChefServer::VersionedCookbookDir::VALID_VERSIONED_COOKBOOK_NAME.match(entry_name)
+            return nil if name_match.nil?
+            return name_match[1]
+          end
+
+          def canonical_cookbook_name(entry_name)
+            self.class.canonical_cookbook_name(entry_name)
+          end
+
+          def uploaded_cookbook_version_path
+            File.join(file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
+          end
+
+          def can_upload?
+            File.exists?(uploaded_cookbook_version_path) || children.size > 0
+          end
+
+          protected
+
+          def make_child_entry(child_name)
+            segment_info = Chef::ChefFS::FileSystem::ChefServer::CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
+            ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
+          end
+
+          def cookbook_version
+            loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+            loader.load_cookbooks
+            cb = loader.cookbook_version
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
new file mode 100644
index 0000000..80c3039
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb
@@ -0,0 +1,82 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir"
+require "chef/chef_fs/file_system/not_found_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemCookbookEntry < ChefRepositoryFileSystemEntry
+          def initialize(name, parent, file_path = nil, ruby_only = false, recursive = false)
+            super(name, parent, file_path)
+            @ruby_only = ruby_only
+            @recursive = recursive
+          end
+
+          attr_reader :ruby_only
+          attr_reader :recursive
+
+          def children
+            super.select { |entry| !(entry.dir? && entry.children.size == 0 ) }
+          end
+
+          def can_have_child?(name, is_dir)
+            if is_dir
+              return recursive && name != "." && name != ".."
+            elsif ruby_only
+              return false if name[-3..-1] != ".rb"
+            end
+
+            # Check chefignore
+            ignorer = parent
+            loop do
+              if ignorer.is_a?(ChefRepositoryFileSystemCookbooksDir)
+                # Grab the path from entry to child
+                path_to_child = name
+                child = self
+                while child.parent != ignorer
+                  path_to_child = PathUtils.join(child.name, path_to_child)
+                  child = child.parent
+                end
+                # Check whether that relative path is ignored
+                return !ignorer.chefignore || !ignorer.chefignore.ignored?(path_to_child)
+              end
+              ignorer = ignorer.parent
+              break unless ignorer
+            end
+
+            true
+          end
+
+          def write_pretty_json
+            false
+          end
+
+          protected
+
+          def make_child_entry(child_name)
+            ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir.rb
new file mode 100644
index 0000000..fa6ce9b
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir.rb
@@ -0,0 +1,84 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+require "chef/cookbook/chefignore"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemCookbooksDir < ChefRepositoryFileSystemEntry
+          def initialize(name, parent, file_path)
+            super(name, parent, file_path)
+            begin
+              @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
+            rescue Errno::EISDIR
+            rescue Errno::EACCES
+              # Work around a bug in Chefignore when chefignore is a directory
+            end
+          end
+
+          attr_reader :chefignore
+
+          def children
+            super.select do |entry|
+              # empty cookbooks and cookbook directories are ignored
+              if !entry.can_upload?
+                Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}")
+                false
+              else
+                true
+              end
+            end
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir && !name.start_with?(".")
+          end
+
+          def write_cookbook(cookbook_path, cookbook_version_json, from_fs)
+            cookbook_name = File.basename(cookbook_path)
+            child = make_child_entry(cookbook_name)
+
+            # Use the copy/diff algorithm to copy it down so we don't destroy
+            # chefignored data.  This is terribly un-thread-safe.
+            Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), from_fs, child, nil, { :purge => true })
+
+            # Write out .uploaded-cookbook-version.json
+            cookbook_file_path = File.join(file_path, cookbook_name)
+            if !File.exists?(cookbook_file_path)
+              FileUtils.mkdir_p(cookbook_file_path)
+            end
+            uploaded_cookbook_version_path = File.join(cookbook_file_path, Chef::Cookbook::CookbookVersionLoader::UPLOADED_COOKBOOK_VERSION_FILE)
+            File.open(uploaded_cookbook_version_path, "w") do |file|
+              file.write(cookbook_version_json)
+            end
+          end
+
+          protected
+
+          def make_child_entry(child_name)
+            ChefRepositoryFileSystemCookbookDir.new(child_name, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_data_bags_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_data_bags_dir.rb
new file mode 100644
index 0000000..63c7970
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_data_bags_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/data_handler/data_bag_item_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemDataBagsDir < ChefRepositoryFileSystemEntry
+          def initialize(name, parent, path = nil)
+            super(name, parent, path, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new)
+          end
+
+          def can_have_child?(name, is_dir)
+            is_dir && !name.start_with?(".")
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb
new file mode 100644
index 0000000..329e2e3
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb
@@ -0,0 +1,83 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/file_system_entry"
+require "chef/chef_fs/file_system/not_found_error"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        # ChefRepositoryFileSystemEntry works just like FileSystemEntry,
+        # except can inflate Chef objects
+        class ChefRepositoryFileSystemEntry < FileSystemEntry
+          def initialize(name, parent, file_path = nil, data_handler = nil)
+            super(name, parent, file_path)
+            @data_handler = data_handler
+          end
+
+          def write_pretty_json=(value)
+            @write_pretty_json = value
+          end
+
+          def write_pretty_json
+            @write_pretty_json.nil? ? root.write_pretty_json : @write_pretty_json
+          end
+
+          def data_handler
+            @data_handler || parent.data_handler
+          end
+
+          def chef_object
+            begin
+              return data_handler.chef_object(Chef::JSONCompat.parse(read))
+            rescue
+              Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}")
+            end
+            nil
+          end
+
+          def can_have_child?(name, is_dir)
+            !is_dir && name[-5..-1] == ".json"
+          end
+
+          def write(file_contents)
+            if file_contents && write_pretty_json && name[-5..-1] == ".json"
+              file_contents = minimize(file_contents, self)
+            end
+            super(file_contents)
+          end
+
+          def minimize(file_contents, entry)
+            object = Chef::JSONCompat.parse(file_contents)
+            object = data_handler.normalize(object, entry)
+            object = data_handler.minimize(object, entry)
+            Chef::JSONCompat.to_json_pretty(object)
+          end
+
+          protected
+
+          def make_child_entry(child_name)
+            ChefRepositoryFileSystemEntry.new(child_name, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
new file mode 100644
index 0000000..b979e30
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb
@@ -0,0 +1,38 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/data_handler/policy_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemPoliciesDir < ChefRepositoryFileSystemEntry
+          def initialize(name, parent, path = nil)
+            super(name, parent, path, Chef::ChefFS::DataHandler::PolicyDataHandler.new)
+          end
+
+          def can_have_child?(name, is_dir)
+            !is_dir && name.include?("-")
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
new file mode 100644
index 0000000..5f23888
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb
@@ -0,0 +1,210 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_artifacts_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_data_bags_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_entry"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir"
+require "chef/chef_fs/file_system/multiplexed_dir"
+require "chef/chef_fs/data_handler/client_data_handler"
+require "chef/chef_fs/data_handler/environment_data_handler"
+require "chef/chef_fs/data_handler/node_data_handler"
+require "chef/chef_fs/data_handler/policy_data_handler"
+require "chef/chef_fs/data_handler/policy_group_data_handler"
+require "chef/chef_fs/data_handler/role_data_handler"
+require "chef/chef_fs/data_handler/user_data_handler"
+require "chef/chef_fs/data_handler/group_data_handler"
+require "chef/chef_fs/data_handler/container_data_handler"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+
+        #
+        # Represents the root of a local Chef repository, with directories for
+        # nodes, cookbooks, roles, etc. under it.
+        #
+        class ChefRepositoryFileSystemRootDir < BaseFSDir
+          #
+          # Create a new Chef Repository File System root.
+          #
+          # == Parameters
+          # [child_paths]
+          #   A hash of child paths, e.g.:
+          #     "nodes" => [ '/var/nodes', '/home/jkeiser/nodes' ],
+          #     "roles" => [ '/var/roles' ],
+          #     ...
+          # [root_paths]
+          #   An array of paths representing the top level, where
+          #   +org.json+, +members.json+, and +invites.json+ will be stored.
+          # [chef_config] - a hash of options that looks suspiciously like the ones
+          #   stored in Chef::Config, containing at least these keys:
+          #   :versioned_cookbooks:: whether to include versions in cookbook names
+          def initialize(child_paths, root_paths = [], chef_config = Chef::Config)
+            super("", nil)
+            @child_paths = child_paths
+            @root_paths = root_paths
+            @versioned_cookbooks = chef_config[:versioned_cookbooks]
+          end
+
+          attr_accessor :write_pretty_json
+
+          attr_reader :root_paths
+          attr_reader :child_paths
+          attr_reader :versioned_cookbooks
+
+          CHILDREN = %w{org.json invitations.json members.json}
+
+          def children
+            @children ||= begin
+                            result = child_paths.keys.sort.map { |name| make_child_entry(name) }
+                            result += CHILDREN.map { |name| make_child_entry(name) }
+                            result.select { |c| c && c.exists? }.sort_by { |c| c.name }
+                          end
+          end
+
+          def can_have_child?(name, is_dir)
+            if is_dir
+              child_paths.has_key?(name)
+            elsif root_dir
+              CHILDREN.include?(name)
+            else
+              false
+            end
+          end
+
+          def create_child(name, file_contents = nil)
+            if file_contents
+              child = root_dir.create_child(name, file_contents)
+            else
+              child_paths[name].each do |path|
+                begin
+                  Dir.mkdir(path)
+                rescue Errno::EEXIST
+                end
+              end
+              child = make_child_entry(name)
+            end
+            @children = nil
+            child
+          end
+
+          def json_class
+            nil
+          end
+
+          # Used to print out a human-readable file system description
+          def fs_description
+            repo_paths = root_paths || [ File.dirname(child_paths["cookbooks"][0]) ]
+            result = "repository at #{repo_paths.join(', ')}\n"
+            if versioned_cookbooks
+              result << "  Multiple versions per cookbook\n"
+            else
+              result << "  One version per cookbook\n"
+            end
+            child_paths.each_pair do |name, paths|
+              if paths.any? { |path| !repo_paths.include?(File.dirname(path)) }
+                result << "  #{name} at #{paths.join(', ')}\n"
+              end
+            end
+            result
+          end
+
+          private
+
+          #
+          # A FileSystemEntry representing the root path where invites.json,
+          # members.json and org.json may be found.
+          #
+          def root_dir
+            existing_paths = root_paths.select { |path| File.exists?(path) }
+            if existing_paths.size > 0
+              MultiplexedDir.new(existing_paths.map do |path|
+                dir = ChefRepositoryFileSystemEntry.new(name, parent, path)
+                dir.write_pretty_json = !!write_pretty_json
+                dir
+              end)
+            end
+          end
+
+          #
+          # Create a child entry of the appropriate type:
+          # cookbooks, data_bags, acls, etc.  All will be multiplexed (i.e. if
+          # you have multiple paths for cookbooks, the multiplexed dir will grab
+          # cookbooks from all of them when you list or grab them).
+          #
+          def make_child_entry(name)
+            if CHILDREN.include?(name)
+              return nil if !root_dir
+              return root_dir.child(name)
+            end
+
+            paths = (child_paths[name] || []).select { |path| File.exists?(path) }
+            if paths.size == 0
+              return NonexistentFSObject.new(name, self)
+            end
+            case name
+            when "cookbooks"
+              if versioned_cookbooks
+                dirs = paths.map { |path| ChefRepositoryFileSystemVersionedCookbooksDir.new(name, self, path) }
+              else
+                dirs = paths.map { |path| ChefRepositoryFileSystemCookbooksDir.new(name, self, path) }
+              end
+            when "cookbook_artifacts"
+              dirs = paths.map { |path| ChefRepositoryFileSystemCookbookArtifactsDir.new(name, self, path) }
+            when "policies"
+              dirs = paths.map { |path| ChefRepositoryFileSystemPoliciesDir.new(name, self, path) }
+            when "data_bags"
+              dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) }
+            when "acls"
+              dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) }
+            else
+              data_handler = case name
+                             when "clients"
+                               Chef::ChefFS::DataHandler::ClientDataHandler.new
+                             when "environments"
+                               Chef::ChefFS::DataHandler::EnvironmentDataHandler.new
+                             when "nodes"
+                               Chef::ChefFS::DataHandler::NodeDataHandler.new
+                             when "policy_groups"
+                               Chef::ChefFS::DataHandler::PolicyGroupDataHandler.new
+                             when "roles"
+                               Chef::ChefFS::DataHandler::RoleDataHandler.new
+                             when "users"
+                               Chef::ChefFS::DataHandler::UserDataHandler.new
+                             when "groups"
+                               Chef::ChefFS::DataHandler::GroupDataHandler.new
+                             when "containers"
+                               Chef::ChefFS::DataHandler::ContainerDataHandler.new
+                             else
+                               raise "Unknown top level path #{name}"
+                             end
+              dirs = paths.map { |path| ChefRepositoryFileSystemEntry.new(name, self, path, data_handler) }
+            end
+            MultiplexedDir.new(dirs)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb
new file mode 100644
index 0000000..5dc74d8
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir.rb
@@ -0,0 +1,42 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemVersionedCookbookDir < ChefRepositoryFileSystemCookbookDir
+          # Override from parent
+          def cookbook_version
+            loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore)
+            # We need the canonical cookbook name if we are using versioned cookbooks, but we don't
+            # want to spend a lot of time adding code to the main Chef libraries
+            canonical_name = canonical_cookbook_name(File.basename(file_path))
+            raise "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z" unless canonical_name
+            # KLUDGE: We shouldn't have to use instance_variable_set
+            loader.instance_variable_set(:@cookbook_name, canonical_name)
+            loader.load_cookbooks
+            loader.cookbook_version
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir.rb
new file mode 100644
index 0000000..d1371f1
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbooks_dir.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_cookbooks_dir"
+require "chef/chef_fs/file_system/repository/chef_repository_file_system_versioned_cookbook_dir"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class ChefRepositoryFileSystemVersionedCookbooksDir < ChefRepositoryFileSystemCookbooksDir
+          def make_child_entry(child_name)
+            ChefRepositoryFileSystemVersionedCookbookDir.new(child_name, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/file_system_entry.rb b/lib/chef/chef_fs/file_system/repository/file_system_entry.rb
new file mode 100644
index 0000000..bee017f
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/file_system_entry.rb
@@ -0,0 +1,117 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/base_fs_dir"
+require "chef/chef_fs/file_system/chef_server/rest_list_dir"
+require "chef/chef_fs/file_system/already_exists_error"
+require "chef/chef_fs/file_system/must_delete_recursively_error"
+require "chef/chef_fs/file_system/not_found_error"
+require "chef/chef_fs/path_utils"
+require "fileutils"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class FileSystemEntry < BaseFSDir
+          def initialize(name, parent, file_path = nil)
+            super(name, parent)
+            @file_path = file_path || "#{parent.file_path}/#{name}"
+          end
+
+          attr_reader :file_path
+
+          def path_for_printing
+            file_path
+          end
+
+          def children
+            # Except cookbooks and data bag dirs, all things must be json files
+            begin
+              Dir.entries(file_path).sort.
+                map { |child_name| make_child_entry(child_name) }.
+                select { |child| child && can_have_child?(child.name, child.dir?) }
+            rescue Errno::ENOENT
+              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+            end
+          end
+
+          def create_child(child_name, file_contents = nil)
+            child = make_child_entry(child_name)
+            if child.exists?
+              raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+            end
+            if file_contents
+              child.write(file_contents)
+            else
+              begin
+                Dir.mkdir(child.file_path)
+              rescue Errno::EEXIST
+                raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, child)
+              end
+            end
+            child
+          end
+
+          def dir?
+            File.directory?(file_path)
+          end
+
+          def delete(recurse)
+            begin
+              if dir?
+                if !recurse
+                  raise MustDeleteRecursivelyError.new(self, $!)
+                end
+                FileUtils.rm_r(file_path)
+              else
+                File.delete(file_path)
+              end
+            rescue Errno::ENOENT
+              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+            end
+          end
+
+          def exists?
+            File.exists?(file_path) && (parent.nil? || parent.can_have_child?(name, dir?))
+          end
+
+          def read
+            begin
+              File.open(file_path, "rb") { |f| f.read }
+            rescue Errno::ENOENT
+              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+            end
+          end
+
+          def write(content)
+            File.open(file_path, "wb") do |file|
+              file.write(content)
+            end
+          end
+
+          protected
+
+          def make_child_entry(child_name)
+            FileSystemEntry.new(child_name, self)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/repository/file_system_root_dir.rb b/lib/chef/chef_fs/file_system/repository/file_system_root_dir.rb
new file mode 100644
index 0000000..e2bb27c
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/repository/file_system_root_dir.rb
@@ -0,0 +1,33 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/chef_fs/file_system/repository/file_system_entry"
+
+class Chef
+  module ChefFS
+    module FileSystem
+      module Repository
+        class FileSystemRootDir < FileSystemEntry
+          def initialize(file_path)
+            super("", nil, file_path)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/chef_fs/file_system/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb
deleted file mode 100644
index 672fa44..0000000
--- a/lib/chef/chef_fs/file_system/rest_list_dir.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_dir'
-require 'chef/chef_fs/file_system/rest_list_entry'
-require 'chef/chef_fs/file_system/not_found_error'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class RestListDir < BaseFSDir
-        def initialize(name, parent, api_path = nil, data_handler = nil)
-          super(name, parent)
-          @api_path = api_path || (parent.api_path == "" ? name : "#{parent.api_path}/#{name}")
-          @data_handler = data_handler
-        end
-
-        attr_reader :api_path
-        attr_reader :data_handler
-
-        def child(name)
-          result = @children.select { |child| child.name == name }.first if @children
-          result ||= can_have_child?(name, false) ?
-                     _make_child_entry(name) : NonexistentFSObject.new(name, self)
-        end
-
-        def can_have_child?(name, is_dir)
-          name =~ /\.json$/ && !is_dir
-        end
-
-        def children
-          begin
-            @children ||= root.get_json(api_path).keys.sort.map do |key|
-              _make_child_entry("#{key}.json", true)
-            end
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}"
-          rescue Net::HTTPServerException => e
-            if $!.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}"
-            end
-          end
-        end
-
-        def create_child(name, file_contents)
-          begin
-            object = Chef::JSONCompat.parse(file_contents)
-          rescue Chef::Exceptions::JSON::ParseError => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Parse error reading JSON creating child '#{name}': #{e}"
-          end
-
-          result = _make_child_entry(name, true)
-
-          if data_handler
-            object = data_handler.normalize_for_post(object, result)
-            data_handler.verify_integrity(object, result) do |error|
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self), "Error creating '#{name}': #{error}"
-            end
-          end
-
-          begin
-            rest.post(api_path, object)
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            elsif $!.response.code == "409"
-              raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Failure creating '#{name}': #{path}/#{name} already exists"
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Failure creating '#{name}': #{e.message}"
-            end
-          end
-
-          @children = nil
-
-          result
-        end
-
-        def org
-          parent.org
-        end
-
-        def environment
-          parent.environment
-        end
-
-        def rest
-          parent.rest
-        end
-
-        def _make_child_entry(name, exists = nil)
-          RestListEntry.new(name, self, exists)
-        end
-      end
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/file_system/rest_list_entry.rb b/lib/chef/chef_fs/file_system/rest_list_entry.rb
deleted file mode 100644
index f68794c..0000000
--- a/lib/chef/chef_fs/file_system/rest_list_entry.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/chef_fs/file_system/base_fs_object'
-require 'chef/chef_fs/file_system/not_found_error'
-require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/role'
-require 'chef/node'
-require 'chef/json_compat'
-
-class Chef
-  module ChefFS
-    module FileSystem
-      class RestListEntry < BaseFSObject
-        def initialize(name, parent, exists = nil)
-          super(name, parent)
-          @exists = exists
-        end
-
-        def data_handler
-          parent.data_handler
-        end
-
-        def api_child_name
-          if name.length < 5 || name[-5,5] != ".json"
-            raise "Invalid name #{path}: must end in .json"
-          end
-          name[0,name.length-5]
-        end
-
-        def api_path
-          "#{parent.api_path}/#{api_child_name}"
-        end
-
-        def org
-          parent.org
-        end
-
-        def environment
-          parent.environment
-        end
-
-        def exists?
-          if @exists.nil?
-            begin
-              @exists = parent.children.any? { |child| child.name == name }
-            rescue Chef::ChefFS::FileSystem::NotFoundError
-              @exists = false
-            end
-          end
-          @exists
-        end
-
-        def delete(recurse)
-          begin
-            rest.delete(api_path)
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
-            end
-          end
-        end
-
-        def read
-          Chef::JSONCompat.to_json_pretty(minimize_value(_read_json))
-        end
-
-        def _read_json
-          begin
-            # Minimize the value (get rid of defaults) so the results don't look terrible
-            root.get_json(api_path)
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
-          rescue Net::HTTPServerException => e
-            if $!.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
-            end
-          end
-        end
-
-        def chef_object
-          # REST will inflate the Chef object using json_class
-          data_handler.json_class.json_create(read)
-        end
-
-        def minimize_value(value)
-          data_handler.minimize(data_handler.normalize(value, self), self)
-        end
-
-        def compare_to(other)
-          # TODO this pair of reads can be parallelized
-
-          # Grab the other value
-          begin
-            other_value_json = other.read
-          rescue Chef::ChefFS::FileSystem::NotFoundError
-            return [ nil, nil, :none ]
-          end
-
-          # Grab this value
-          begin
-            value = _read_json
-          rescue Chef::ChefFS::FileSystem::NotFoundError
-            return [ false, :none, other_value_json ]
-          end
-
-          # Minimize (and normalize) both values for easy and beautiful diffs
-          value = minimize_value(value)
-          value_json = Chef::JSONCompat.to_json_pretty(value)
-          begin
-            other_value = Chef::JSONCompat.parse(other_value_json)
-          rescue Chef::Exceptions::JSON::ParseError => e
-            Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}")
-            return [ nil, value_json, other_value_json ]
-          end
-          other_value = minimize_value(other_value)
-          other_value_json = Chef::JSONCompat.to_json_pretty(other_value)
-
-          [ value == other_value, value_json, other_value_json ]
-        end
-
-        def rest
-          parent.rest
-        end
-
-        def write(file_contents)
-          begin
-            object = Chef::JSONCompat.parse(file_contents)
-          rescue Chef::Exceptions::JSON::ParseError => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Parse error reading JSON: #{e}"
-          end
-
-          if data_handler
-            object = data_handler.normalize_for_put(object, self)
-            data_handler.verify_integrity(object, self) do |error|
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), "#{error}"
-            end
-          end
-
-          begin
-            rest.put(api_path, object)
-          rescue Timeout::Error => e
-            raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
-          rescue Net::HTTPServerException => e
-            if e.response.code == "404"
-              raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e)
-            else
-              raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}"
-            end
-          end
-        end
-
-        def api_error_text(response)
-          begin
-            Chef::JSONCompat.parse(response.body)['error'].join("\n")
-          rescue
-            response.body
-          end
-        end
-      end
-
-    end
-  end
-end
diff --git a/lib/chef/chef_fs/knife.rb b/lib/chef/chef_fs/knife.rb
index 86872da..399bf1c 100644
--- a/lib/chef/chef_fs/knife.rb
+++ b/lib/chef/chef_fs/knife.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
+require "pathname"
 
 class Chef
   module ChefFS
@@ -24,11 +25,11 @@ class Chef
       # Workaround for CHEF-3932
       def self.deps
         super do
-          require 'chef/config'
-          require 'chef/chef_fs/parallelizer'
-          require 'chef/chef_fs/config'
-          require 'chef/chef_fs/file_pattern'
-          require 'chef/chef_fs/path_utils'
+          require "chef/config"
+          require "chef/chef_fs/parallelizer"
+          require "chef/chef_fs/config"
+          require "chef/chef_fs/file_pattern"
+          require "chef/chef_fs/path_utils"
           yield
         end
       end
@@ -44,16 +45,16 @@ class Chef
       end
 
       option :repo_mode,
-        :long => '--repo-mode MODE',
+        :long => "--repo-mode MODE",
         :description => "Specifies the local repository layout.  Values: static, everything, hosted_everything.  Default: everything/hosted_everything"
 
       option :chef_repo_path,
-        :long => '--chef-repo-path PATH',
-        :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+        :long => "--chef-repo-path PATH",
+        :description => "Overrides the location of chef repo. Default is specified by chef_repo_path in the config"
 
       option :concurrency,
-        :long => '--concurrency THREADS',
-        :description => 'Maximum number of simultaneous requests to send (default: 10)'
+        :long => "--concurrency THREADS",
+        :description => "Maximum number of simultaneous requests to send (default: 10)"
 
       def configure_chef
         super
@@ -63,7 +64,7 @@ class Chef
         # --chef-repo-path forcibly overrides all other paths
         if config[:chef_repo_path]
           Chef::Config[:chef_repo_path] = config[:chef_repo_path]
-          %w(acl client cookbook container data_bag environment group node role user).each do |variable_name|
+          Chef::ChefFS::Config::INFLECTIONS.each_value do |variable_name|
             Chef::Config.delete("#{variable_name}_path".to_sym)
           end
         end
@@ -98,14 +99,41 @@ class Chef
       end
 
       def pattern_arg_from(arg)
-        # TODO support absolute file paths and not just patterns?  Too much?
-        # Could be super useful in a world with multiple repo paths
-        if !@chef_fs_config.base_path && !Chef::ChefFS::PathUtils.is_absolute?(arg)
-          # Check if chef repo path is specified to give a better error message
-          ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path")
+        inferred_path = nil
+        if Chef::ChefFS::PathUtils.is_absolute?(arg)
+          # We should be able to use this as-is - but the user might have incorrectly provided
+          # us with a path that is based off of the OS root path instead of the Chef-FS root.
+          # Do a quick and dirty sanity check.
+          if possible_server_path = @chef_fs_config.server_path(arg)
+            ui.warn("The absolute path provided is suspicious: #{arg}")
+            ui.warn("If you wish to refer to a file location, please provide a path that is rooted at the chef-repo.")
+            ui.warn("Consider writing '#{possible_server_path}' instead of '#{arg}'")
+          end
+          # Use the original path because we can't be sure.
+          inferred_path = arg
+        elsif arg[0, 1] == "~"
+          # Let's be nice and fix it if possible - but warn the user.
+          ui.warn("A path relative to a user home directory has been provided: #{arg}")
+          ui.warn("Paths provided need to be rooted at the chef-repo being considered or be relative paths.")
+          inferred_path = @chef_fs_config.server_path(arg)
+          ui.warn("Using '#{inferred_path}' as the path instead of '#{arg}'.")
+        elsif Pathname.new(arg).absolute?
+          # It is definitely a system absolute path (such as C:\ or \\foo\bar) but it cannot be
+          # interpreted as a Chef-FS absolute path.  Again attempt to be nice but warn the user.
+          ui.warn("An absolute file system path that isn't a server path was provided: #{arg}")
+          ui.warn("Paths provided need to be rooted at the chef-repo being considered or be relative paths.")
+          inferred_path = @chef_fs_config.server_path(arg)
+          ui.warn("Using '#{inferred_path}' as the path instead of '#{arg}'.")
+        elsif @chef_fs_config.base_path.nil?
+          # These are all relative paths.  We can't resolve and root paths unless we are in the
+          # chef repo.
+          ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path.")
+          ui.error("Current working directory is '#{@chef_fs_config.cwd}'.")
           exit(1)
+        else
+          inferred_path = Chef::ChefFS::PathUtils::join(@chef_fs_config.base_path, arg)
         end
-        Chef::ChefFS::FilePattern.relative_to(@chef_fs_config.base_path, arg)
+        Chef::ChefFS::FilePattern.new(inferred_path)
       end
 
       def format_path(entry)
@@ -117,7 +145,7 @@ class Chef
       end
 
       def discover_repo_dir(dir)
-        %w(.chef cookbooks data_bags environments roles).each do |subdir|
+        %w{.chef cookbooks data_bags environments roles}.each do |subdir|
           return dir if File.directory?(File.join(dir, subdir))
         end
         # If this isn't it, check the parent
diff --git a/lib/chef/chef_fs/parallelizer.rb b/lib/chef/chef_fs/parallelizer.rb
index 116a626..5d05f41 100644
--- a/lib/chef/chef_fs/parallelizer.rb
+++ b/lib/chef/chef_fs/parallelizer.rb
@@ -1,5 +1,5 @@
-require 'thread'
-require 'chef/chef_fs/parallelizer/parallel_enumerable'
+require "thread"
+require "chef/chef_fs/parallelizer/parallel_enumerable"
 
 class Chef
   module ChefFS
@@ -54,7 +54,7 @@ class Chef
 
       def resize(to_threads, wait = true, timeout = nil)
         if to_threads < num_threads
-          threads_to_stop = @threads[to_threads..num_threads-1]
+          threads_to_stop = @threads[to_threads..num_threads - 1]
           @threads = @threads.slice(0, to_threads)
           threads_to_stop.each do |thread|
             @stop_thread[thread] = true
diff --git a/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb b/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
index 7321aa0..6094fab 100644
--- a/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
+++ b/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
@@ -23,7 +23,7 @@ class Chef
         def flatten(value, levels, &block)
           if levels != 0 && value.respond_to?(:each) && !value.is_a?(String)
             value.each do |child|
-              flatten(child, levels.nil? ? levels : levels-1, &block)
+              flatten(child, levels.nil? ? levels : levels - 1, &block)
             end
           else
             block.call(value)
diff --git a/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb b/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
index 8845b69..8df6a76 100644
--- a/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
+++ b/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/parallelizer/flatten_enumerable'
+require "chef/chef_fs/parallelizer/flatten_enumerable"
 
 class Chef
   module ChefFS
@@ -92,7 +92,7 @@ class Chef
           end
         end
 
-        def first(n=nil)
+        def first(n = nil)
           if n
             restricted_copy(@input_enumerable.first(n)).to_a
           else
@@ -266,7 +266,7 @@ class Chef
           begin
             output = @block.call(input)
             @unconsumed_output.push([ output, index, input, :result ])
-          rescue
+          rescue StandardError, ScriptError
             if @options[:stop_on_exception]
               @unconsumed_input.clear
             end
diff --git a/lib/chef/chef_fs/path_utils.rb b/lib/chef/chef_fs/path_utils.rb
index 9ef75ce..8ec5c3d 100644
--- a/lib/chef/chef_fs/path_utils.rb
+++ b/lib/chef/chef_fs/path_utils.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,36 +16,36 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs'
-require 'pathname'
+require "chef/chef_fs"
+require "pathname"
 
 class Chef
   module ChefFS
     class PathUtils
 
-      # If you are in 'source', this is what you would have to type to reach 'dest'
-      # relative_to('/a/b/c/d/e', '/a/b/x/y') == '../../c/d/e'
-      # relative_to('/a/b', '/a/b') == '.'
-      def self.relative_to(dest, source)
-        # Skip past the common parts
-        source_parts = Chef::ChefFS::PathUtils.split(source)
-        dest_parts = Chef::ChefFS::PathUtils.split(dest)
-        i = 0
-        until i >= source_parts.length || i >= dest_parts.length || source_parts[i] != dest_parts[i]
-          i+=1
-        end
-        # dot-dot up from 'source' to the common ancestor, then
-        # descend to 'dest' from the common ancestor
-        result = Chef::ChefFS::PathUtils.join(*(['..']*(source_parts.length-i) + dest_parts[i,dest.length-i]))
-        result == '' ? '.' : result
-      end
+      # A Chef-FS path is a path in a chef-repository that can be used to address
+      # both files on a local file-system as well as objects on a chef server.
+      # These paths are stricter than file-system paths allowed on various OSes.
+      # Absolute Chef-FS paths begin with "/" (on windows, "\" is acceptable as well).
+      # "/" is used as the path element separator (on windows, "\" is acceptable as well).
+      # No directory/path element may contain a literal "\" character.  Any such characters
+      # encountered are either dealt with as separators (on windows) or as escape
+      # characters (on POSIX systems).  Relative Chef-FS paths may use ".." or "." but
+      # may never use these to back-out of the root of a Chef-FS path.  Any such extraneous
+      # ".."s are ignored.
+      # Chef-FS paths are case sensitive (since the paths on the server are).
+      # On OSes with case insensitive paths, you may be unable to locally deal with two
+      # objects whose server paths only differ by case.  OTOH, the case of path segments
+      # that are outside the Chef-FS root (such as when looking at a file-system absolute
+      # path to discover the Chef-FS root path) are handled in accordance to the rules
+      # of the local file-system and OS.
 
       def self.join(*parts)
         return "" if parts.length == 0
         # Determine if it started with a slash
         absolute = parts[0].length == 0 || parts[0].length > 0 && parts[0] =~ /^#{regexp_path_separator}/
         # Remove leading and trailing slashes from each part so that the join will work (and the slash at the end will go away)
-        parts = parts.map { |part| part.gsub(/^\/|\/$/, "") }
+        parts = parts.map { |part| part.gsub(/^#{regexp_path_separator}+|#{regexp_path_separator}+$/, "") }
         # Don't join empty bits
         result = parts.select { |part| part != "" }.join("/")
         # Put the / back on
@@ -57,39 +57,71 @@ class Chef
       end
 
       def self.regexp_path_separator
-        Chef::ChefFS::windows? ? '[\/\\\\]' : '/'
+        Chef::ChefFS::windows? ? '[\/\\\\]' : "/"
+      end
+
+      # Given a server path, determines if it is absolute.
+      def self.is_absolute?(path)
+        !!(path =~ /^#{regexp_path_separator}/)
       end
 
       # Given a path which may only be partly real (i.e. /x/y/z when only /x exists,
       # or /x/y/*/blah when /x/y/z/blah exists), call File.realpath on the biggest
-      # part that actually exists.
+      # part that actually exists.  The paths operated on here are not Chef-FS paths.
+      # These are OS paths that may contain symlinks but may not also fully exist.
       #
       # If /x is a symlink to /blarghle, and has no subdirectories, then:
       # PathUtils.realest_path('/x/y/z') == '/blarghle/y/z'
       # PathUtils.realest_path('/x/*/z') == '/blarghle/*/z'
       # PathUtils.realest_path('/*/y/z') == '/*/y/z'
-      def self.realest_path(path)
-        path = Pathname.new(path)
-        begin
-          path.realpath.to_s
-        rescue Errno::ENOENT
-          dirname = path.dirname
-          if dirname
-            PathUtils.join(realest_path(dirname), path.basename.to_s)
-          else
-            path.to_s
+      #
+      # TODO: Move this to wherever util/path_helper is these days.
+      def self.realest_path(path, cwd = Dir.pwd)
+        path = File.expand_path(path, cwd)
+        parent_path = File.dirname(path)
+        suffix = []
+
+        # File.dirname happens to return the path as its own dirname if you're
+        # at the root (such as at \\foo\bar, C:\ or /)
+        until parent_path == path do
+          # This can occur if a path such as "C:" is given.  Ruby gives the parent as "C:."
+          # for reasons only it knows.
+          raise ArgumentError "Invalid path segment #{path}" if parent_path.length > path.length
+          begin
+            path = File.realpath(path)
+            break
+          rescue Errno::ENOENT
+            suffix << File.basename(path)
+            path = parent_path
+            parent_path = File.dirname(path)
           end
         end
+        File.join(path, *suffix.reverse)
       end
 
-      def self.descendant_of?(path, ancestor)
-        path[0,ancestor.length] == ancestor &&
-          (ancestor.length == path.length || path[ancestor.length,1] =~ /#{PathUtils.regexp_path_separator}/)
+      # Compares two path fragments according to the case-sentitivity of the host platform.
+      def self.os_path_eq?(left, right)
+        Chef::ChefFS::windows? ? left.casecmp(right) == 0 : left == right
       end
 
-      def self.is_absolute?(path)
-        path =~ /^#{regexp_path_separator}/
+      # Given two general OS-dependent file paths, determines the relative path of the
+      # child with respect to the ancestor.  Both child and ancestor must exist and be
+      # fully resolved - this is strictly a lexical comparison.  No trailing slashes
+      # and other shenanigans are allowed.
+      #
+      # TODO: Move this to util/path_helper.
+      def self.descendant_path(path, ancestor)
+        candidate_fragment = path[0, ancestor.length]
+        return nil unless PathUtils.os_path_eq?(candidate_fragment, ancestor)
+        if ancestor.length == path.length
+          ""
+        elsif path[ancestor.length, 1] =~ /#{PathUtils.regexp_path_separator}/
+          path[ancestor.length + 1..-1]
+        else
+          nil
+        end
       end
+
     end
   end
 end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index d04a3db..7d2dcf8 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,40 +18,41 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/path_sanity'
-require 'chef/log'
-require 'chef/rest'
-require 'chef/api_client'
-require 'chef/api_client/registration'
-require 'chef/audit/runner'
-require 'chef/node'
-require 'chef/role'
-require 'chef/file_cache'
-require 'chef/run_context'
-require 'chef/runner'
-require 'chef/run_status'
-require 'chef/cookbook/cookbook_collection'
-require 'chef/cookbook/file_vendor'
-require 'chef/cookbook/file_system_file_vendor'
-require 'chef/cookbook/remote_file_vendor'
-require 'chef/event_dispatch/dispatcher'
-require 'chef/event_loggers/base'
-require 'chef/event_loggers/windows_eventlog'
-require 'chef/exceptions'
-require 'chef/formatters/base'
-require 'chef/formatters/doc'
-require 'chef/formatters/minimal'
-require 'chef/version'
-require 'chef/resource_reporter'
-require 'chef/audit/audit_reporter'
-require 'chef/run_lock'
-require 'chef/policy_builder'
-require 'chef/request_id'
-require 'chef/platform/rebooter'
-require 'ohai'
-require 'rbconfig'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/path_sanity"
+require "chef/log"
+require "chef/server_api"
+require "chef/api_client"
+require "chef/api_client/registration"
+require "chef/audit/runner"
+require "chef/node"
+require "chef/role"
+require "chef/file_cache"
+require "chef/run_context"
+require "chef/runner"
+require "chef/run_status"
+require "chef/cookbook/cookbook_collection"
+require "chef/cookbook/file_vendor"
+require "chef/cookbook/file_system_file_vendor"
+require "chef/cookbook/remote_file_vendor"
+require "chef/event_dispatch/dispatcher"
+require "chef/event_loggers/base"
+require "chef/event_loggers/windows_eventlog"
+require "chef/exceptions"
+require "chef/formatters/base"
+require "chef/formatters/doc"
+require "chef/formatters/minimal"
+require "chef/version"
+require "chef/resource_reporter"
+require "chef/audit/audit_reporter"
+require "chef/run_lock"
+require "chef/policy_builder"
+require "chef/request_id"
+require "chef/platform/rebooter"
+require "chef/mixin/deprecation"
+require "ohai"
+require "rbconfig"
 
 class Chef
   # == Chef::Client
@@ -60,121 +61,292 @@ class Chef
   class Client
     include Chef::Mixin::PathSanity
 
-    # IO stream that will be used as 'STDOUT' for formatters. Formatters are
-    # configured during `initialize`, so this provides a convenience for
-    # setting alternative IO stream during tests.
-    STDOUT_FD = STDOUT
-
-    # IO stream that will be used as 'STDERR' for formatters. Formatters are
-    # configured during `initialize`, so this provides a convenience for
-    # setting alternative IO stream during tests.
-    STDERR_FD = STDERR
+    extend Chef::Mixin::Deprecation
 
-    # Clears all notifications for client run status events.
-    # Primarily for testing purposes.
-    def self.clear_notifications
-      @run_start_notifications = nil
-      @run_completed_successfully_notifications = nil
-      @run_failed_notifications = nil
-    end
-
-    # The list of notifications to be run when the client run starts.
-    def self.run_start_notifications
-      @run_start_notifications ||= []
-    end
-
-    # The list of notifications to be run when the client run completes
-    # successfully.
-    def self.run_completed_successfully_notifications
-      @run_completed_successfully_notifications ||= []
-    end
-
-    # The list of notifications to be run when the client run fails.
-    def self.run_failed_notifications
-      @run_failed_notifications ||= []
-    end
-
-    # Add a notification for the 'client run started' event. The notification
-    # is provided as a block. The current Chef::RunStatus object will be passed
-    # to the notification_block when the event is triggered.
-    def self.when_run_starts(&notification_block)
-      run_start_notifications << notification_block
-    end
+    #
+    # The status of the Chef run.
+    #
+    # @return [Chef::RunStatus]
+    #
+    attr_reader :run_status
 
-    # Add a notification for the 'client run success' event. The notification
-    # is provided as a block. The current Chef::RunStatus object will be passed
-    # to the notification_block when the event is triggered.
-    def self.when_run_completes_successfully(&notification_block)
-      run_completed_successfully_notifications << notification_block
+    #
+    # The node represented by this client.
+    #
+    # @return [Chef::Node]
+    #
+    def node
+      run_status.node
     end
 
-    # Add a notification for the 'client run failed' event. The notification
-    # is provided as a block. The current Chef::RunStatus is passed to the
-    # notification_block when the event is triggered.
-    def self.when_run_fails(&notification_block)
-      run_failed_notifications << notification_block
+    def node=(value)
+      run_status.node = value
     end
 
-    # Callback to fire notifications that the Chef run is starting
-    def run_started
-      self.class.run_start_notifications.each do |notification|
-        notification.call(run_status)
-      end
-      @events.run_started(run_status)
-    end
+    #
+    # The ohai system used by this client.
+    #
+    # @return [Ohai::System]
+    #
+    attr_reader :ohai
 
-    # Callback to fire notifications that the run completed successfully
-    def run_completed_successfully
-      success_handlers = self.class.run_completed_successfully_notifications
-      success_handlers.each do |notification|
-        notification.call(run_status)
-      end
-    end
+    #
+    # The rest object used to communicate with the Chef server.
+    #
+    # @return [Chef::ServerAPI]
+    #
+    attr_reader :rest
 
-    # Callback to fire notifications that the Chef run failed
-    def run_failed
-      failure_handlers = self.class.run_failed_notifications
-      failure_handlers.each do |notification|
-        notification.call(run_status)
-      end
-    end
+    #
+    # A rest object with validate_utf8 set to false.  This will not throw exceptions
+    # on non-UTF8 strings in JSON but will sanitize them so that e.g. POSTs will
+    # never fail.  Cannot be configured on a request-by-request basis, so we carry
+    # around another rest object for it.
+    #
+    attr_reader :rest_clean
 
-    attr_accessor :node
-    attr_accessor :ohai
-    attr_accessor :rest
+    #
+    # The runner used to converge.
+    #
+    # @return [Chef::Runner]
+    #
     attr_accessor :runner
 
+    #
+    # Extra node attributes that were applied to the node.
+    #
+    # @return [Hash]
+    #
     attr_reader :json_attribs
-    attr_reader :run_status
+
+    #
+    # The event dispatcher for the Chef run, including any configured output
+    # formatters and event loggers.
+    #
+    # @return [EventDispatch::Dispatcher]
+    #
+    # @see Chef::Formatters
+    # @see Chef::Config#formatters
+    # @see Chef::Config#stdout
+    # @see Chef::Config#stderr
+    # @see Chef::Config#force_logger
+    # @see Chef::Config#force_formatter
+    # TODO add stdout, stderr, and default formatters to Chef::Config so the
+    # defaults aren't calculated here.  Remove force_logger and force_formatter
+    # from this code.
+    # @see Chef::EventLoggers
+    # @see Chef::Config#disable_event_logger
+    # @see Chef::Config#event_loggers
+    # @see Chef::Config#event_handlers
+    #
     attr_reader :events
 
+    #
     # Creates a new Chef::Client.
-    def initialize(json_attribs=nil, args={})
+    #
+    # @param json_attribs [Hash] Node attributes to layer into the node when it is
+    #   fetched.
+    # @param args [Hash] Options:
+    # @option args [Array<RunList::RunListItem>] :override_runlist A runlist to
+    #   use instead of the node's embedded run list.
+    # @option args [Array<String>] :specific_recipes A list of recipe file paths
+    #   to load after the run list has been loaded.
+    #
+    def initialize(json_attribs = nil, args = {})
       @json_attribs = json_attribs || {}
-      @node = nil
-      @run_status = nil
-      @runner = nil
       @ohai = Ohai::System.new
 
       event_handlers = configure_formatters + configure_event_loggers
       event_handlers += Array(Chef::Config[:event_handlers])
 
       @events = EventDispatch::Dispatcher.new(*event_handlers)
+      # TODO it seems like a bad idea to be deletin' other peoples' hashes.
       @override_runlist = args.delete(:override_runlist)
       @specific_recipes = args.delete(:specific_recipes)
+      @run_status = Chef::RunStatus.new(nil, events)
 
       if new_runlist = args.delete(:runlist)
         @json_attribs["run_list"] = new_runlist
       end
+    end
 
-      # these slurp in the resource+provider world, so be exceedingly lazy about requiring them
-      require 'chef/platform/provider_priority_map' unless defined? Chef::Platform::ProviderPriorityMap
-      require 'chef/platform/resource_priority_map' unless defined? Chef::Platform::ResourcePriorityMap
+    #
+    # Do a full run for this Chef::Client.
+    #
+    # Locks the run while doing its job.
+    #
+    # Fires run_start before doing anything and fires run_completed or
+    # run_failed when finished.  Also notifies client listeners of run_started
+    # at the beginning of Compile, and run_completed_successfully or run_failed
+    # when all is complete.
+    #
+    # Phase 1: Setup
+    # --------------
+    # Gets information about the system and the run we are doing.
+    #
+    # 1. Run ohai to collect system information.
+    # 2. Register / connect to the Chef server (unless in solo mode).
+    # 3. Retrieve the node (or create a new one).
+    # 4. Merge in json_attribs, Chef::Config.environment, and override_run_list.
+    #
+    # @see #run_ohai
+    # @see #load_node
+    # @see #build_node
+    # @see Chef::Config#lockfile
+    # @see Chef::RunLock#acquire
+    #
+    # Phase 2: Compile
+    # ----------------
+    # Decides *what* we plan to converge by compiling recipes.
+    #
+    # 1. Sync required cookbooks to the local cache.
+    # 2. Load libraries from all cookbooks.
+    # 3. Load attributes from all cookbooks.
+    # 4. Load LWRPs from all cookbooks.
+    # 5. Load resource definitions from all cookbooks.
+    # 6. Load recipes in the run list.
+    # 7. Load recipes from the command line.
+    #
+    # @see #setup_run_context Syncs and compiles cookbooks.
+    # @see Chef::CookbookCompiler#compile
+    #
+    # Phase 3: Converge
+    # -----------------
+    # Brings the system up to date.
+    #
+    # 1. Converge the resources built from recipes in Phase 2.
+    # 2. Save the node.
+    # 3. Reboot if we were asked to.
+    #
+    # @see #converge_and_save
+    # @see Chef::Runner
+    #
+    # Phase 4: Audit
+    # --------------
+    # Runs 'control_group' audits in recipes.  This entire section can be enabled or disabled with config.
+    #
+    # 1. 'control_group' DSL collects audits during Phase 2
+    # 2. Audits are run using RSpec
+    # 3. Errors are collected and reported using the formatters
+    #
+    # @see #run_audits
+    # @see Chef::Audit::Runner#run
+    #
+    # @raise [Chef::Exceptions::RunFailedWrappingError] If converge or audit failed.
+    #
+    # @see Chef::Config#enforce_path_sanity
+    # @see Chef::Config#solo
+    # @see Chef::Config#audit_mode
+    #
+    # @return Always returns true.
+    #
+    def run
+      start_profiling
 
-      Chef.set_provider_priority_map(Chef::Platform::ProviderPriorityMap.instance)
-      Chef.set_resource_priority_map(Chef::Platform::ResourcePriorityMap.instance)
+      run_error = nil
+
+      runlock = RunLock.new(Chef::Config.lockfile)
+      # TODO feels like acquire should have its own block arg for this
+      runlock.acquire
+      # don't add code that may fail before entering this section to be sure to release lock
+      begin
+        runlock.save_pid
+
+        request_id = Chef::RequestID.instance.request_id
+        run_context = nil
+        events.run_start(Chef::VERSION)
+        Chef::Log.info("*** Chef #{Chef::VERSION} ***")
+        Chef::Log.info "Chef-client pid: #{Process.pid}"
+        Chef::Log.debug("Chef-client request_id: #{request_id}")
+        enforce_path_sanity
+        run_ohai
+
+        register unless Chef::Config[:solo]
+
+        load_node
+
+        build_node
+
+        run_status.run_id = request_id
+        run_status.start_clock
+        Chef::Log.info("Starting Chef Run for #{node.name}")
+        run_started
+
+        do_windows_admin_check
+
+        run_context = setup_run_context
+
+        if Chef::Config[:audit_mode] != :audit_only
+          converge_error = converge_and_save(run_context)
+        end
+
+        if Chef::Config[:why_run] == true
+          # why_run should probably be renamed to why_converge
+          Chef::Log.debug("Not running controls in 'why-run' mode - this mode is used to see potential converge changes")
+        elsif Chef::Config[:audit_mode] != :disabled
+          audit_error = run_audits(run_context)
+        end
+
+        # Raise converge_error so run_failed reporters/events are processed.
+        raise converge_error if converge_error
+
+        run_status.stop_clock
+        Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
+        run_completed_successfully
+        events.run_completed(node)
+
+        # keep this inside the main loop to get exception backtraces
+        end_profiling
+
+        # rebooting has to be the last thing we do, no exceptions.
+        Chef::Platform::Rebooter.reboot_if_needed!(node)
+      rescue Exception => run_error
+        # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
+        Chef::Log.debug("Re-raising exception: #{run_error.class} - #{run_error.message}\n#{run_error.backtrace.join("\n  ")}")
+        # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
+        if run_status
+          run_status.stop_clock
+          run_status.exception = run_error
+          run_failed
+        end
+        events.run_failed(run_error)
+      ensure
+        Chef::RequestID.instance.reset_request_id
+        request_id = nil
+        @run_status = nil
+        run_context = nil
+        runlock.release
+      end
+
+      # Raise audit, converge, and other errors here so that we exit
+      # with the proper exit status code and everything gets raised
+      # as a RunFailedWrappingError
+      if run_error || converge_error || audit_error
+        error = if Chef::Config[:audit_mode] == :disabled
+                  run_error || converge_error
+                else
+                  e = if run_error == converge_error
+                        Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
+                      else
+                        Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
+                      end
+                  e.fill_backtrace
+                  e
+                end
+
+        Chef::Application.debug_stacktrace(error)
+        raise error
+      end
+
+      true
     end
 
+    #
+    # Private API
+    # TODO make this stuff protected or private
+    #
+
+    # @api private
     def configure_formatters
       formatters_for_run.map do |formatter_name, output_path|
         if output_path.nil?
@@ -187,6 +359,7 @@ class Chef
       end
     end
 
+    # @api private
     def formatters_for_run
       if Chef::Config.formatters.empty?
         [default_formatter]
@@ -195,6 +368,7 @@ class Chef
       end
     end
 
+    # @api private
     def default_formatter
       if (STDOUT.tty? && !Chef::Config[:force_logger]) || Chef::Config[:force_formatter]
         [:doc]
@@ -203,6 +377,7 @@ class Chef
       end
     end
 
+    # @api private
     def configure_event_loggers
       if Chef::Config.disable_event_logger
         []
@@ -219,54 +394,145 @@ class Chef
       end
     end
 
-    # Resource repoters send event information back to the chef server for processing.
-    # Can only be called after we have a @rest object
+    # Rest client for use by API reporters.  This rest client will not fail with an exception if
+    # it is fed non-UTF8 data.
+    #
+    # @api private
+    def rest_clean(client_name = node_name, config = Chef::Config)
+      @rest_clean ||=
+        Chef::ServerAPI.new(config[:chef_server_url], client_name: client_name,
+                                                      signing_key_filename: config[:client_key], validate_utf8: false)
+    end
+
+    # Resource reporters send event information back to the chef server for
+    # processing.  Can only be called after we have a @rest object
+    # @api private
     def register_reporters
       [
-        Chef::ResourceReporter.new(rest),
-        Chef::Audit::AuditReporter.new(rest)
+        Chef::ResourceReporter.new(rest_clean),
+        Chef::Audit::AuditReporter.new(rest_clean),
       ].each do |r|
         events.register(r)
       end
     end
 
+    #
+    # Callback to fire notifications that the Chef run is starting
+    #
+    # @api private
+    #
+    def run_started
+      self.class.run_start_notifications.each do |notification|
+        notification.call(run_status)
+      end
+      events.run_started(run_status)
+    end
+
+    #
+    # Callback to fire notifications that the run completed successfully
+    #
+    # @api private
+    #
+    def run_completed_successfully
+      success_handlers = self.class.run_completed_successfully_notifications
+      success_handlers.each do |notification|
+        notification.call(run_status)
+      end
+    end
+
+    #
+    # Callback to fire notifications that the Chef run failed
+    #
+    # @api private
+    #
+    def run_failed
+      failure_handlers = self.class.run_failed_notifications
+      failure_handlers.each do |notification|
+        notification.call(run_status)
+      end
+    end
+
+    #
     # Instantiates a Chef::Node object, possibly loading the node's prior state
-    # when using chef-client. Delegates to policy_builder.  Injects the built node
-    # into the Chef class.
+    # when using chef-client. Sets Chef.node to the new node.
     #
     # @return [Chef::Node] The node object for this Chef run
+    #
+    # @see Chef::PolicyBuilder#load_node
+    #
+    # @api private
+    #
     def load_node
       policy_builder.load_node
-      @node = policy_builder.node
-      Chef.set_node(@node)
+      run_status.node = policy_builder.node
+      Chef.set_node(policy_builder.node)
       node
     end
 
-    # Mutates the `node` object to prepare it for the chef run. Delegates to
-    # policy_builder
+    #
+    # Mutates the `node` object to prepare it for the chef run.
     #
     # @return [Chef::Node] The updated node object
+    #
+    # @see Chef::PolicyBuilder#build_node
+    #
+    # @api private
+    #
     def build_node
       policy_builder.build_node
-      @run_status = Chef::RunStatus.new(node, events)
+      run_status.node = node
       node
     end
 
+    #
+    # Sync cookbooks to local cache.
+    #
+    # TODO this appears to be unused.
+    #
+    # @see Chef::PolicyBuilder#sync_cookbooks
+    #
+    # @api private
+    #
+    def sync_cookbooks
+      policy_builder.sync_cookbooks
+    end
+
+    #
+    # Sets up the run context.
+    #
+    # @see Chef::PolicyBuilder#setup_run_context
+    #
+    # @return The newly set up run context
+    #
+    # @api private
     def setup_run_context
-      run_context = policy_builder.setup_run_context(@specific_recipes)
+      run_context = policy_builder.setup_run_context(specific_recipes)
       assert_cookbook_path_not_empty(run_context)
       run_status.run_context = run_context
       run_context
     end
 
-    def sync_cookbooks
-      policy_builder.sync_cookbooks
-    end
-
+    #
+    # The PolicyBuilder strategy for figuring out run list and cookbooks.
+    #
+    # @return [Chef::PolicyBuilder::Policyfile, Chef::PolicyBuilder::ExpandNodeObject]
+    #
+    # @api private
+    #
     def policy_builder
-      @policy_builder ||= Chef::PolicyBuilder.strategy.new(node_name, ohai.data, json_attribs, @override_runlist, events)
+      @policy_builder ||= Chef::PolicyBuilder::Dynamic.new(node_name, ohai.data, json_attribs, override_runlist, events)
     end
 
+    #
+    # Save the updated node to Chef.
+    #
+    # Does not save if we are in solo mode or using override_runlist.
+    #
+    # @see Chef::Node#save
+    # @see Chef::Config#solo
+    #
+    # @api private
+    #
     def save_updated_node
       if Chef::Config[:solo]
         # nothing to do
@@ -274,72 +540,135 @@ class Chef
         Chef::Log.warn("Skipping final node save because override_runlist was given")
       else
         Chef::Log.debug("Saving the current state of node #{node_name}")
-        @node.save
+        node.save
       end
     end
 
+    #
+    # Run ohai plugins.  Runs all ohai plugins unless minimal_ohai is specified.
+    #
+    # Sends the ohai_completed event when finished.
+    #
+    # @see Chef::EventDispatcher#
+    # @see Chef::Config#minimal_ohai
+    #
+    # @api private
+    #
     def run_ohai
-      filter = Chef::Config[:minimal_ohai] ? %w[fqdn machinename hostname platform platform_version os os_version] : nil
+      filter = Chef::Config[:minimal_ohai] ? %w{fqdn machinename hostname platform platform_version os os_version} : nil
       ohai.all_plugins(filter)
-      @events.ohai_completed(node)
+      events.ohai_completed(node)
     end
 
+    #
+    # Figure out the node name we are working with.
+    #
+    # It tries these, in order:
+    # - Chef::Config.node_name
+    # - ohai[:fqdn]
+    # - ohai[:machinename]
+    # - ohai[:hostname]
+    #
+    # @raise [Chef::Exceptions::CannotDetermineNodeName] If the node name is not
+    #   set and cannot be determined via ohai.
+    #
+    # @see Chef::Config#node_name
+    #
+    # @api private
+    #
     def node_name
       name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:machinename] || ohai[:hostname]
       Chef::Config[:node_name] = name
 
       raise Chef::Exceptions::CannotDetermineNodeName unless name
 
-      # node names > 90 bytes only work with authentication protocol >= 1.1
-      # see discussion in config.rb.
-      if name.bytesize > 90
-        Chef::Config[:authentication_protocol_version] = "1.1"
-      end
-
       name
     end
 
     #
-    # === Returns
-    # rest<Chef::REST>:: returns Chef::REST connection object
-    def register(client_name=node_name, config=Chef::Config)
+    # Determine our private key and set up the connection to the Chef server.
+    #
+    # Skips registration and fires the `skipping_registration` event if
+    # Chef::Config.client_key is unspecified or already exists.
+    #
+    # If Chef::Config.client_key does not exist, we register the client with the
+    # Chef server and fire the registration_start and registration_completed events.
+    #
+    # @return [Chef::ServerAPI] The server connection object.
+    #
+    # @see Chef::Config#chef_server_url
+    # @see Chef::Config#client_key
+    # @see Chef::ApiClient::Registration#run
+    # @see Chef::EventDispatcher#skipping_registration
+    # @see Chef::EventDispatcher#registration_start
+    # @see Chef::EventDispatcher#registration_completed
+    # @see Chef::EventDispatcher#registration_failed
+    #
+    # @api private
+    #
+    def register(client_name = node_name, config = Chef::Config)
       if !config[:client_key]
-        @events.skipping_registration(client_name, config)
+        events.skipping_registration(client_name, config)
         Chef::Log.debug("Client key is unspecified - skipping registration")
       elsif File.exists?(config[:client_key])
-        @events.skipping_registration(client_name, config)
+        events.skipping_registration(client_name, config)
         Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration")
       else
-        @events.registration_start(node_name, config)
+        events.registration_start(node_name, config)
         Chef::Log.info("Client key #{config[:client_key]} is not present - registering")
         Chef::ApiClient::Registration.new(node_name, config[:client_key]).run
-        @events.registration_completed
+        events.registration_completed
       end
       # We now have the client key, and should use it from now on.
-      @rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key])
+      @rest = Chef::ServerAPI.new(config[:chef_server_url], client_name: client_name,
+                                                            signing_key_filename: config[:client_key])
+      # force initialization of the rest_clean API object
+      rest_clean(client_name, config)
       register_reporters
     rescue Exception => e
+      # TODO this should probably only ever fire if we *started* registration.
+      # Move it to the block above.
       # TODO: munge exception so a semantic failure message can be given to the
       # user
-      @events.registration_failed(client_name, e, config)
+      events.registration_failed(client_name, e, config)
       raise
     end
 
-    # Converges the node.
     #
-    # === Returns
-    # The thrown exception, if there was one.  If this returns nil the converge was successful.
+    # Converges all compiled resources.
+    #
+    # Fires the converge_start, converge_complete and converge_failed events.
+    #
+    # If the exception `:end_client_run_early` is thrown during convergence, it
+    # does not mark the run complete *or* failed, and returns `nil`
+    #
+    # @param run_context The run context.
+    #
+    # @return The thrown exception, if we are in audit mode. `nil` means the
+    #   converge was successful or ended early.
+    #
+    # @raise Any converge exception, unless we are in audit mode, in which case
+    #   we *return* the exception.
+    #
+    # @see Chef::Runner#converge
+    # @see Chef::Config#audit_mode
+    # @see Chef::EventDispatch#converge_start
+    # @see Chef::EventDispatch#converge_complete
+    # @see Chef::EventDispatch#converge_failed
+    #
+    # @api private
+    #
     def converge(run_context)
       converge_exception = nil
       catch(:end_client_run_early) do
         begin
-          @events.converge_start(run_context)
+          events.converge_start(run_context)
           Chef::Log.debug("Converging node #{node_name}")
           @runner = Chef::Runner.new(run_context)
-          runner.converge
-          @events.converge_complete
+          @runner.converge
+          events.converge_complete
         rescue Exception => e
-          @events.converge_failed(e)
+          events.converge_failed(e)
           raise e if Chef::Config[:audit_mode] == :disabled
           converge_exception = e
         end
@@ -347,8 +676,28 @@ class Chef
       converge_exception
     end
 
+    #
+    # Converge the node via and then save it if successful.
+    #
+    # @param run_context The run context.
+    #
+    # @return The thrown exception, if we are in audit mode. `nil` means the
+    #   converge was successful or ended early.
+    #
+    # @raise Any converge or node save exception, unless we are in audit mode,
+    #   in which case we *return* the exception.
+    #
+    # @see #converge
+    # @see #save_updated_mode
+    # @see Chef::Config#audit_mode
+    #
+    # @api private
+    #
     # We don't want to change the old API on the `converge` method to have it perform
     # saving.  So we wrap it in this method.
+    # TODO given this seems to be pretty internal stuff, how badly do we need to
+    # split this stuff up?
+    #
     def converge_and_save(run_context)
       converge_exception = converge(run_context)
       unless converge_exception
@@ -362,37 +711,67 @@ class Chef
       converge_exception
     end
 
+    #
+    # Run the audit phase.
+    #
+    # Triggers the audit_phase_start, audit_phase_complete and
+    # audit_phase_failed events.
+    #
+    # @param run_context The run context.
+    #
+    # @return Any thrown exceptions. `nil` if successful.
+    #
+    # @see Chef::Audit::Runner#run
+    # @see Chef::EventDispatch#audit_phase_start
+    # @see Chef::EventDispatch#audit_phase_complete
+    # @see Chef::EventDispatch#audit_phase_failed
+    #
+    # @api private
+    #
     def run_audits(run_context)
-      audit_exception = nil
       begin
-        @events.audit_phase_start(run_status)
+        events.audit_phase_start(run_status)
         Chef::Log.info("Starting audit phase")
         auditor = Chef::Audit::Runner.new(run_context)
         auditor.run
         if auditor.failed?
-          raise Chef::Exceptions::AuditsFailed.new(auditor.num_failed, auditor.num_total)
+          audit_exception = Chef::Exceptions::AuditsFailed.new(auditor.num_failed, auditor.num_total)
+          @events.audit_phase_failed(audit_exception, Chef::Audit::Logger.read_buffer)
+        else
+          @events.audit_phase_complete(Chef::Audit::Logger.read_buffer)
         end
-        @events.audit_phase_complete
       rescue Exception => e
         Chef::Log.error("Audit phase failed with error message: #{e.message}")
-        @events.audit_phase_failed(e)
+        @events.audit_phase_failed(e, Chef::Audit::Logger.read_buffer)
         audit_exception = e
       end
       audit_exception
     end
 
-    # Expands the run list. Delegates to the policy_builder.
     #
-    # Normally this does not need to be called from here, it will be called by
-    # build_node. This is provided so external users (like the chefspec
-    # project) can inject custom behavior into the run process.
+    # Expands the run list.
+    #
+    # @return [Chef::RunListExpansion] The expanded run list.
+    #
+    # @see Chef::PolicyBuilder#expand_run_list
     #
-    # === Returns
-    # RunListExpansion: A RunListExpansion or API compatible object.
     def expanded_run_list
       policy_builder.expand_run_list
     end
 
+    #
+    # Check if the user has Administrator privileges on windows.
+    #
+    # Throws an error if the user is not an admin, and
+    # `Chef::Config.fatal_windows_admin_check` is true.
+    #
+    # @raise [Chef::Exceptions::WindowsNotAdmin] If the user is not an admin.
+    #
+    # @see Chef::platform#windows?
+    # @see Chef::Config#fatal_windows_admin_check
+    #
+    # @api private
+    #
     def do_windows_admin_check
       if Chef::Platform.windows?
         Chef::Log.debug("Checking for administrator privileges....")
@@ -412,98 +791,142 @@ class Chef
       end
     end
 
-    # Do a full run for this Chef::Client.  Calls:
-    #
-    #  * run_ohai - Collect information about the system
-    #  * build_node - Get the last known state, merge with local changes
-    #  * register - If not in solo mode, make sure the server knows about this client
-    #  * sync_cookbooks - If not in solo mode, populate the local cache with the node's cookbooks
-    #  * converge - Bring this system up to date
-    #
-    # === Returns
-    # true:: Always returns true.
-    def run
-      runlock = RunLock.new(Chef::Config.lockfile)
-      runlock.acquire
-      # don't add code that may fail before entering this section to be sure to release lock
-      begin
-        runlock.save_pid
+    # Notification registration
+    class<<self
+      #
+      # Add a listener for the 'client run started' event.
+      #
+      # @param notification_block The callback (takes |run_status| parameter).
+      # @yieldparam [Chef::RunStatus] run_status The run status.
+      #
+      def when_run_starts(&notification_block)
+        run_start_notifications << notification_block
+      end
 
-        request_id = Chef::RequestID.instance.request_id
-        run_context = nil
-        @events.run_start(Chef::VERSION)
-        Chef::Log.info("*** Chef #{Chef::VERSION} ***")
-        Chef::Log.info "Chef-client pid: #{Process.pid}"
-        Chef::Log.debug("Chef-client request_id: #{request_id}")
-        enforce_path_sanity
-        run_ohai
+      #
+      # Add a listener for the 'client run success' event.
+      #
+      # @param notification_block The callback (takes |run_status| parameter).
+      # @yieldparam [Chef::RunStatus] run_status The run status.
+      #
+      def when_run_completes_successfully(&notification_block)
+        run_completed_successfully_notifications << notification_block
+      end
 
-        register unless Chef::Config[:solo]
+      #
+      # Add a listener for the 'client run failed' event.
+      #
+      # @param notification_block The callback (takes |run_status| parameter).
+      # @yieldparam [Chef::RunStatus] run_status The run status.
+      #
+      def when_run_fails(&notification_block)
+        run_failed_notifications << notification_block
+      end
 
-        load_node
+      #
+      # Clears all listeners for client run status events.
+      #
+      # Primarily for testing purposes.
+      #
+      # @api private
+      #
+      def clear_notifications
+        @run_start_notifications = nil
+        @run_completed_successfully_notifications = nil
+        @run_failed_notifications = nil
+      end
 
-        build_node
+      #
+      # TODO These seem protected to me.
+      #
+
+      #
+      # Listeners to be run when the client run starts.
+      #
+      # @return [Array<Proc>]
+      #
+      # @api private
+      #
+      def run_start_notifications
+        @run_start_notifications ||= []
+      end
 
-        run_status.run_id = request_id
-        run_status.start_clock
-        Chef::Log.info("Starting Chef Run for #{node.name}")
-        run_started
+      #
+      # Listeners to be run when the client run completes successfully.
+      #
+      # @return [Array<Proc>]
+      #
+      # @api private
+      #
+      def run_completed_successfully_notifications
+        @run_completed_successfully_notifications ||= []
+      end
 
-        do_windows_admin_check
+      #
+      # Listeners to be run when the client run fails.
+      #
+      # @return [Array<Proc>]
+      #
+      # @api private
+      #
+      def run_failed_notifications
+        @run_failed_notifications ||= []
+      end
+    end
 
-        run_context = setup_run_context
+    #
+    # IO stream that will be used as 'STDOUT' for formatters. Formatters are
+    # configured during `initialize`, so this provides a convenience for
+    # setting alternative IO stream during tests.
+    #
+    # @api private
+    #
+    STDOUT_FD = STDOUT
 
-        if Chef::Config[:audit_mode] != :audit_only
-          converge_error = converge_and_save(run_context)
-        end
+    #
+    # IO stream that will be used as 'STDERR' for formatters. Formatters are
+    # configured during `initialize`, so this provides a convenience for
+    # setting alternative IO stream during tests.
+    #
+    # @api private
+    #
+    STDERR_FD = STDERR
 
-        if Chef::Config[:why_run] == true
-          # why_run should probably be renamed to why_converge
-          Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
-        elsif Chef::Config[:audit_mode] != :disabled
-          audit_error = run_audits(run_context)
-        end
+    #
+    # Deprecated writers
+    #
 
-        if converge_error || audit_error
-          e = Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
-          e.fill_backtrace
-          raise e
-        end
+    include Chef::Mixin::Deprecation
+    deprecated_attr_writer :ohai, "There is no alternative. Leave ohai alone!"
+    deprecated_attr_writer :rest, "There is no alternative. Leave rest alone!"
+    deprecated_attr :runner, "There is no alternative. Leave runner alone!"
 
-        run_status.stop_clock
-        Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds")
-        run_completed_successfully
-        @events.run_completed(node)
+    private
 
-        # rebooting has to be the last thing we do, no exceptions.
-        Chef::Platform::Rebooter.reboot_if_needed!(node)
+    attr_reader :override_runlist
+    attr_reader :specific_recipes
 
-        true
+    def profiling_prereqs!
+      require "ruby-prof"
+    rescue LoadError
+      raise "You must have the ruby-prof gem installed in order to use --profile-ruby"
+    end
 
-      rescue Exception => e
-        # CHEF-3336: Send the error first in case something goes wrong below and we don't know why
-        Chef::Log.debug("Re-raising exception: #{e.class} - #{e.message}\n#{e.backtrace.join("\n  ")}")
-        # If we failed really early, we may not have a run_status yet. Too early for these to be of much use.
-        if run_status
-          run_status.stop_clock
-          run_status.exception = e
-          run_failed
-        end
-        Chef::Application.debug_stacktrace(e)
-        @events.run_failed(e)
-        raise
-      ensure
-        Chef::RequestID.instance.reset_request_id
-        request_id = nil
-        @run_status = nil
-        run_context = nil
-        runlock.release
-        GC.start
-      end
-      true
+    def start_profiling
+      return unless Chef::Config[:profile_ruby]
+      profiling_prereqs!
+      RubyProf.start
     end
 
-    private
+    def end_profiling
+      return unless Chef::Config[:profile_ruby]
+      profiling_prereqs!
+      path = Chef::FileCache.create_cache_path("graph_profile.out", false)
+      File.open(path, "w+") do |file|
+        RubyProf::GraphPrinter.new(RubyProf.stop).print(file, {})
+      end
+      Chef::Log.warn("Ruby execution profile dumped to #{path}")
+    end
 
     def empty_directory?(path)
       !File.exists?(path) || (Dir.entries(path).size <= 2)
@@ -520,7 +943,7 @@ class Chef
         # if it's an array, go through it and check each one, raise error at the last one if no files are found
         cookbook_paths = Array(Chef::Config[:cookbook_path])
         Chef::Log.debug "Loading from cookbook_path: #{cookbook_paths.map { |path| File.expand_path(path) }.join(', ')}"
-        if cookbook_paths.all? {|path| empty_directory?(path) }
+        if cookbook_paths.all? { |path| empty_directory?(path) }
           msg = "None of the cookbook paths set in Chef::Config[:cookbook_path], #{cookbook_paths.inspect}, contain any cookbooks"
           Chef::Log.fatal(msg)
           raise Chef::Exceptions::CookbookNotFound, msg
@@ -528,19 +951,17 @@ class Chef
       else
         Chef::Log.warn("Node #{node_name} has an empty run list.") if run_context.node.run_list.empty?
       end
-
     end
 
     def has_admin_privileges?
-      require 'chef/win32/security'
+      require "chef/win32/security"
 
       Chef::ReservedNames::Win32::Security.has_admin_privileges?
     end
-
   end
 end
 
 # HACK cannot load this first, but it must be loaded.
-require 'chef/cookbook_loader'
-require 'chef/cookbook_version'
-require 'chef/cookbook/synchronizer'
+require "chef/cookbook_loader"
+require "chef/cookbook_version"
+require "chef/cookbook/synchronizer"
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index 25557b0..549872b 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -1,10 +1,10 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Mark Mzyk (<mmzyk at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Mark Mzyk (<mmzyk at chef.io>)
 # Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,728 +19,67 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/log'
-require 'chef/exceptions'
-require 'mixlib/config'
-require 'chef/util/selinux'
-require 'chef/util/path_helper'
-require 'pathname'
-require 'chef/mixin/shell_out'
+require "chef/log"
+require "chef-config/logger"
 
-class Chef
-  class Config
-
-    extend Mixlib::Config
-    extend Chef::Mixin::ShellOut
-
-    PathHelper = Chef::Util::PathHelper
-
-    # Evaluates the given string as config.
-    #
-    # +filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file.
-    def self.from_string(string, filename)
-      self.instance_eval(string, filename, 1)
-    end
-
-    # Manages the chef secret session key
-    # === Returns
-    # <newkey>:: A new or retrieved session key
-    #
-    def self.manage_secret_key
-      newkey = nil
-      if Chef::FileCache.has_key?("chef_server_cookie_id")
-        newkey = Chef::FileCache.load("chef_server_cookie_id")
-      else
-        chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
-        newkey = ""
-        40.times { |i| newkey << chars[rand(chars.size-1)] }
-        Chef::FileCache.store("chef_server_cookie_id", newkey)
-      end
-      newkey
-    end
-
-    def self.inspect
-      configuration.inspect
-    end
-
-    def self.platform_specific_path(path)
-      path = PathHelper.cleanpath(path)
-      if Chef::Platform.windows?
-        # turns \etc\chef\client.rb and \var\chef\client.rb into C:/chef/client.rb
-        if env['SYSTEMDRIVE'] && path[0] == '\\' && path.split('\\')[2] == 'chef'
-          path = PathHelper.join(env['SYSTEMDRIVE'], path.split('\\', 3)[2])
-        end
-      end
-      path
-    end
-
-    def self.add_formatter(name, file_path=nil)
-      formatters << [name, file_path]
-    end
-
-    def self.add_event_logger(logger)
-      event_handlers << logger
-    end
-
-    # Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
-    configurable(:config_file)
-
-    default(:config_dir) do
-      if config_file
-        PathHelper.dirname(config_file)
-      else
-        PathHelper.join(user_home, ".chef", "")
-      end
-    end
-
-    default :formatters, []
-
-    # Override the config dispatch to set the value of multiple server options simultaneously
-    #
-    # === Parameters
-    # url<String>:: String to be set for all of the chef-server-api URL's
-    #
-    configurable(:chef_server_url).writes_value { |url| url.to_s.strip }
-
-    # When you are using ActiveSupport, they monkey-patch 'daemonize' into Kernel.
-    # So while this is basically identical to what method_missing would do, we pull
-    # it up here and get a real method written so that things get dispatched
-    # properly.
-    configurable(:daemonize).writes_value { |v| v }
-
-    # The root where all local chef object data is stored.  cookbooks, data bags,
-    # environments are all assumed to be in separate directories under this.
-    # chef-solo uses these directories for input data.  knife commands
-    # that upload or download files (such as knife upload, knife role from file,
-    # etc.) work.
-    default :chef_repo_path do
-      if self.configuration[:cookbook_path]
-        if self.configuration[:cookbook_path].kind_of?(String)
-          File.expand_path('..', self.configuration[:cookbook_path])
-        else
-          self.configuration[:cookbook_path].map do |path|
-            File.expand_path('..', path)
-          end
-        end
-      else
-        cache_path
-      end
-    end
-
-    def self.find_chef_repo_path(cwd)
-      # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
-      # This allows us to run config-free.
-      path = cwd
-      until File.directory?(PathHelper.join(path, "cookbooks"))
-        new_path = File.expand_path('..', path)
-        if new_path == path
-          Chef::Log.warn("No cookbooks directory found at or above current directory.  Assuming #{Dir.pwd}.")
-          return Dir.pwd
-        end
-        path = new_path
-      end
-      Chef::Log.info("Auto-discovered chef repository at #{path}")
-      path
-    end
-
-    def self.derive_path_from_chef_repo_path(child_path)
-      if chef_repo_path.kind_of?(String)
-        PathHelper.join(chef_repo_path, child_path)
-      else
-        chef_repo_path.map { |path| PathHelper.join(path, child_path)}
-      end
-    end
-
-    # Location of acls on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/acls.
-    # Only applies to Enterprise Chef commands.
-    default(:acl_path) { derive_path_from_chef_repo_path('acls') }
-
-    # Location of clients on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/acls.
-    default(:client_path) { derive_path_from_chef_repo_path('clients') }
-
-    # Location of cookbooks on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/cookbooks.  If chef_repo_path
-    # is not specified, this is set to [/var/chef/cookbooks, /var/chef/site-cookbooks]).
-    default(:cookbook_path) do
-      if self.configuration[:chef_repo_path]
-        derive_path_from_chef_repo_path('cookbooks')
-      else
-        Array(derive_path_from_chef_repo_path('cookbooks')).flatten +
-          Array(derive_path_from_chef_repo_path('site-cookbooks')).flatten
-      end
-    end
-
-    # Location of containers on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/containers.
-    # Only applies to Enterprise Chef commands.
-    default(:container_path) { derive_path_from_chef_repo_path('containers') }
-
-    # Location of data bags on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/data_bags.
-    default(:data_bag_path) { derive_path_from_chef_repo_path('data_bags') }
-
-    # Location of environments on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/environments.
-    default(:environment_path) { derive_path_from_chef_repo_path('environments') }
-
-    # Location of groups on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/groups.
-    # Only applies to Enterprise Chef commands.
-    default(:group_path) { derive_path_from_chef_repo_path('groups') }
-
-    # Location of nodes on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/nodes.
-    default(:node_path) { derive_path_from_chef_repo_path('nodes') }
-
-    # Location of roles on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/roles.
-    default(:role_path) { derive_path_from_chef_repo_path('roles') }
-
-    # Location of users on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/users.
-    # Does not apply to Enterprise Chef commands.
-    default(:user_path) { derive_path_from_chef_repo_path('users') }
-
-    # Location of policies on disk. String or array of strings.
-    # Defaults to <chef_repo_path>/policies.
-    default(:policy_path) { derive_path_from_chef_repo_path('policies') }
-
-    # Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity
-    default :enforce_path_sanity, true
-
-    # Formatted Chef Client output is a beta feature, disabled by default:
-    default :formatter, "null"
-
-    # The number of times the client should retry when registering with the server
-    default :client_registration_retries, 5
-
-    # An array of paths to search for knife exec scripts if they aren't in the current directory
-    default :script_path, []
-
-    # The root of all caches (checksums, cache and backup).  If local mode is on,
-    # this is under the user's home directory.
-    default(:cache_path) do
-      if local_mode
-        PathHelper.join(config_dir, 'local-mode-cache')
-      else
-        primary_cache_root = platform_specific_path("/var")
-        primary_cache_path = platform_specific_path("/var/chef")
-        # Use /var/chef as the cache path only if that folder exists and we can read and write
-        # into it, or /var exists and we can read and write into it (we'll create /var/chef later).
-        # Otherwise, we'll create .chef under the user's home directory and use that as
-        # the cache path.
-        unless path_accessible?(primary_cache_path) || path_accessible?(primary_cache_root)
-          secondary_cache_path = PathHelper.join(user_home, '.chef')
-          Chef::Log.info("Unable to access cache at #{primary_cache_path}. Switching cache to #{secondary_cache_path}")
-          secondary_cache_path
-        else
-          primary_cache_path
-        end
-      end
-    end
-
-    # Returns true only if the path exists and is readable and writeable for the user.
-    def self.path_accessible?(path)
-      File.exists?(path) && File.readable?(path) && File.writable?(path)
-    end
-
-    # Where cookbook files are stored on the server (by content checksum)
-    default(:checksum_path) { PathHelper.join(cache_path, "checksums") }
-
-    # Where chef's cache files should be stored
-    default(:file_cache_path) { PathHelper.join(cache_path, "cache") }
-
-    # Where backups of chef-managed files should go
-    default(:file_backup_path) { PathHelper.join(cache_path, "backup") }
-
-    # The chef-client (or solo) lockfile.
-    #
-    # If your `file_cache_path` resides on a NFS (or non-flock()-supporting
-    # fs), it's recommended to set this to something like
-    # '/tmp/chef-client-running.pid'
-    default(:lockfile) { PathHelper.join(file_cache_path, "chef-client-running.pid") }
-
-    ## Daemonization Settings ##
-    # What user should Chef run as?
-    default :user, nil
-    default :group, nil
-    default :umask, 0022
-
-    # Valid log_levels are:
-    # * :debug
-    # * :info
-    # * :warn
-    # * :fatal
-    # These work as you'd expect. There is also a special `:auto` setting.
-    # When set to :auto, Chef will auto adjust the log verbosity based on
-    # context. When a tty is available (usually because the user is running chef
-    # in a console), the log level is set to :warn, and output formatters are
-    # used as the primary mode of output. When a tty is not available, the
-    # logger is the primary mode of output, and the log level is set to :info
-    default :log_level, :auto
-
-    # Logging location as either an IO stream or string representing log file path
-    default :log_location, STDOUT
-
-    # Using `force_formatter` causes chef to default to formatter output when STDOUT is not a tty
-    default :force_formatter, false
-
-    # Using `force_logger` causes chef to default to logger output when STDOUT is a tty
-    default :force_logger, false
-
-    default :http_retry_count, 5
-    default :http_retry_delay, 5
-    default :interval, nil
-    default :once, nil
-    default :json_attribs, nil
-    # toggle info level log items that can create a lot of output
-    default :verbose_logging, true
-    default :node_name, nil
-    default :diff_disabled,           false
-    default :diff_filesize_threshold, 10000000
-    default :diff_output_threshold,   1000000
-    default :local_mode, false
-
-    default :pid_file, nil
-
-    # Whether Chef Zero local mode should bind to a port. All internal requests
-    # will go through the socketless code path regardless, so the socket is
-    # only needed if other processes will connect to the local mode server.
-    #
-    # For compatibility this is set to true but it will be changed to false in
-    # the future.
-    default :listen, true
+# DI our logger into ChefConfig before we load the config. Some defaults are
+# auto-detected, and this emits log messages on some systems, all of which will
+# occur at require-time. So we need to set the logger first.
+ChefConfig.logger = Chef::Log
 
-    config_context :chef_zero do
-      config_strict_mode true
-      default(:enabled) { Chef::Config.local_mode }
-      default :host, 'localhost'
-      default :port, 8889.upto(9999) # Will try ports from 8889-9999 until one works
-    end
-    default :chef_server_url,   "https://localhost:443"
-
-    default :rest_timeout, 300
-    default :yum_timeout, 900
-    default :yum_lock_timeout, 30
-    default :solo,  false
-    default :splay, nil
-    default :why_run, false
-    default :color, false
-    default :client_fork, true
-    default :ez, false
-    default :enable_reporting, true
-    default :enable_reporting_url_fatals, false
-    # Possible values for :audit_mode
-    # :enabled, :disabled, :audit_only,
-    #
-    # TODO: 11 Dec 2014: Currently audit-mode is an experimental feature
-    # and is disabled by default. When users choose to enable audit-mode,
-    # a warning is issued in application/client#reconfigure.
-    # This can be removed when audit-mode is enabled by default.
-    default :audit_mode, :disabled
-
-    # Chef only needs ohai to run the hostname plugin for the most basic
-    # functionality. If the rest of the ohai plugins are not needed (like in
-    # most of our testing scenarios)
-    default :minimal_ohai, false
-
-    # Policyfile is an experimental feature where a node gets its run list and
-    # cookbook version set from a single document on the server instead of
-    # expanding the run list and having the server compute the cookbook version
-    # set based on environment constraints.
-    #
-    # Because this feature is experimental, it is not recommended for
-    # production use. Developent/release of this feature may not adhere to
-    # semver guidelines.
-    default :use_policyfile, false
-
-    # Set these to enable SSL authentication / mutual-authentication
-    # with the server
-
-    # Client side SSL cert/key for mutual auth
-    default :ssl_client_cert, nil
-    default :ssl_client_key, nil
-
-    # Whether or not to verify the SSL cert for all HTTPS requests. When set to
-    # :verify_peer (default), all HTTPS requests will be validated regardless of other
-    # SSL verification settings. When set to :verify_none no HTTPS requests will
-    # be validated.
-    default :ssl_verify_mode, :verify_peer
-
-    # Whether or not to verify the SSL cert for HTTPS requests to the Chef
-    # server API. If set to `true`, the server's cert will be validated
-    # regardless of the :ssl_verify_mode setting. This is set to `true` when
-    # running in local-mode.
-    # NOTE: This is a workaround until verify_peer is enabled by default.
-    default(:verify_api_cert) { Chef::Config.local_mode }
+require "chef-config/config"
+require "chef/platform/query_helpers"
 
-    # Path to the default CA bundle files.
-    default :ssl_ca_path, nil
-    default(:ssl_ca_file) do
-      if Chef::Platform.windows? and embedded_path = embedded_dir
-        cacert_path = File.join(embedded_path, "ssl/certs/cacert.pem")
-        cacert_path if File.exist?(cacert_path)
-      else
-        nil
-      end
-    end
-
-    # A directory that contains additional SSL certificates to trust. Any
-    # certificates in this directory will be added to whatever CA bundle ruby
-    # is using. Use this to add self-signed certs for your Chef Server or local
-    # HTTP file servers.
-    default(:trusted_certs_dir) { PathHelper.join(config_dir, "trusted_certs") }
-
-    # Where should chef-solo download recipes from?
-    default :recipe_url, nil
-
-    # Sets the version of the signed header authentication protocol to use (see
-    # the 'mixlib-authorization' project for more detail). Currently, versions
-    # 1.0 and 1.1 are available; however, the chef-server must first be
-    # upgraded to support version 1.1 before clients can begin using it.
-    #
-    # Version 1.1 of the protocol is required when using a `node_name` greater
-    # than ~90 bytes (~90 ascii characters), so chef-client will automatically
-    # switch to using version 1.1 when `node_name` is too large for the 1.0
-    # protocol. If you intend to use large node names, ensure that your server
-    # supports version 1.1. Automatic detection of large node names means that
-    # users will generally not need to manually configure this.
-    #
-    # In the future, this configuration option may be replaced with an
-    # automatic negotiation scheme.
-    default :authentication_protocol_version, "1.0"
-
-    # This key will be used to sign requests to the Chef server. This location
-    # must be writable by Chef during initial setup when generating a client
-    # identity on the server.
-    #
-    # The chef-server will look up the public key for the client using the
-    # `node_name` of the client.
-    #
-    # If chef-zero is enabled, this defaults to nil (no authentication).
-    default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
-
-    # When registering the client, should we allow the client key location to
-    # be a symlink?  eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
-    # If the path of the key goes through a directory like /tmp this should
-    # never be set to true or its possibly an easily exploitable security hole.
-    default :follow_client_key_symlink, false
-
-    # This secret is used to decrypt encrypted data bag items.
-    default(:encrypted_data_bag_secret) do
-      if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret"))
-        platform_specific_path("/etc/chef/encrypted_data_bag_secret")
-      else
-        nil
-      end
-    end
-
-    # As of Chef 11.0, version "1" is the default encrypted data bag item
-    # format. Version "2" is available which adds encrypt-then-mac protection.
-    # To maintain compatibility, versions other than 1 must be opt-in.
-    #
-    # Set this to `2` if you have chef-client 11.6.0+ in your infrastructure.
-    # Set this to `3` if you have chef-client 11.?.0+, ruby 2 and OpenSSL >= 1.0.1 in your infrastructure. (TODO)
-    default :data_bag_encrypt_version, 1
-
-    # When reading data bag items, any supported version is accepted. However,
-    # if all encrypted data bags have been generated with the version 2 format,
-    # it is recommended to disable support for earlier formats to improve
-    # security. For example, the version 2 format is identical to version 1
-    # except for the addition of an HMAC, so an attacker with MITM capability
-    # could downgrade an encrypted data bag to version 1 as part of an attack.
-    default :data_bag_decrypt_minimum_version, 0
-
-    # If there is no file in the location given by `client_key`, chef-client
-    # will temporarily use the "validator" identity to generate one. If the
-    # `client_key` is not present and the `validation_key` is also not present,
-    # chef-client will not be able to authenticate to the server.
-    #
-    # The `validation_key` is never used if the `client_key` exists.
-    #
-    # If chef-zero is enabled, this defaults to nil (no authentication).
-    default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
-    default :validation_client_name, "chef-validator"
-
-    # When creating a new client via the validation_client account, Chef 11
-    # servers allow the client to generate a key pair locally and send the
-    # public key to the server. This is more secure and helps offload work from
-    # the server, enhancing scalability. If enabled and the remote server
-    # implements only the Chef 10 API, client registration will not work
-    # properly.
-    #
-    # The default value is `true`. Set to `false` to disable client-side key
-    # generation (server generates client keys).
-    default(:local_key_generation) { true }
+# Ohai::Config defines its own log_level and log_location. When loaded, it will
+# override the default ChefConfig::Config values. We save them here before
+# loading ohai/config so that we can override them again inside Chef::Config.
+#
+# REMOVEME once these configurables are removed from the top level of Ohai.
+LOG_LEVEL = ChefConfig::Config[:log_level] unless defined? LOG_LEVEL
+LOG_LOCATION = ChefConfig::Config[:log_location] unless defined? LOG_LOCATION
 
-    # Zypper package provider gpg checks. Set to true to enable package
-    # gpg signature checking. This will be default in the
-    # future. Setting to false disables the warnings.
-    # Leaving this set to nil or false is a security hazard!
-    default :zypper_check_gpg, nil
+# Load the ohai config into the chef config. We can't have an empty ohai
+# configuration context because `ohai.plugins_path << some_path` won't work,
+# and providing default ohai config values here isn't DRY.
+require "ohai/config"
 
-    # Report Handlers
-    default :report_handlers, []
+class Chef
+  Config = ChefConfig::Config
 
-    # Event Handlers
-    default :event_handlers, []
+  # We re-open ChefConfig::Config to add additional settings. Generally,
+  # everything should go in chef-config so it's shared with whoever uses that.
+  # We make execeptions to that rule when:
+  # * The functionality isn't likely to be useful outside of Chef
+  # * The functionality makes use of a dependency we don't want to add to chef-config
+  class Config
 
-    default :disable_event_loggers, false
     default :event_loggers do
       evt_loggers = []
-      if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
+      if ChefConfig.windows? && !(Chef::Platform.windows_server_2003? ||
+          Chef::Platform.windows_nano_server?)
         evt_loggers << :win_evt
       end
       evt_loggers
     end
 
-    # Exception Handlers
-    default :exception_handlers, []
-
-    # Start handlers
-    default :start_handlers, []
-
-    # Syntax Check Cache. Knife keeps track of files that is has already syntax
-    # checked by storing files in this directory. `syntax_check_cache_path` is
-    # the new (and preferred) configuration setting. If not set, knife will
-    # fall back to using cache_options[:path], which is deprecated but exists in
-    # many client configs generated by pre-Chef-11 bootstrappers.
-    default(:syntax_check_cache_path) { cache_options[:path] }
-
-    # Deprecated:
-    # Move this to the default value of syntax_cache_path when this is removed.
-    default(:cache_options) { { :path => PathHelper.join(config_dir, "syntaxcache") } }
-
-    # Whether errors should be raised for deprecation warnings. When set to
-    # `false` (the default setting), a warning is emitted but code using
-    # deprecated methods/features/etc. should work normally otherwise. When set
-    # to `true`, usage of deprecated methods/features will raise a
-    # `DeprecatedFeatureError`. This is used by Chef's tests to ensure that
-    # deprecated functionality is not used internally by Chef.  End users
-    # should generally leave this at the default setting (especially in
-    # production), but it may be useful when testing cookbooks or other code if
-    # the user wishes to aggressively address deprecations.
-    default(:treat_deprecation_warnings_as_errors) do
-      # Using an environment variable allows this setting to be inherited in
-      # tests that spawn new processes.
-      ENV.key?("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
-    end
-
-    # knife configuration data
-    config_context :knife do
-      default :ssh_port, nil
-      default :ssh_user, nil
-      default :ssh_attribute, nil
-      default :ssh_gateway, nil
-      default :bootstrap_version, nil
-      default :bootstrap_proxy, nil
-      default :bootstrap_template, nil
-      default :secret, nil
-      default :secret_file, nil
-      default :identity_file, nil
-      default :host_key_verify, nil
-      default :forward_agent, nil
-      default :sort_status_reverse, nil
-      default :hints, {}
-    end
-
-    def self.set_defaults_for_windows
-      # Those lists of regular expressions define what chef considers a
-      # valid user and group name
-      # From http://technet.microsoft.com/en-us/library/cc776019(WS.10).aspx
-      principal_valid_regex_part = '[^"\/\\\\\[\]\:;|=,+*?<>]+'
-      default :user_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
-      default :group_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
-
-      default :fatal_windows_admin_check, false
-    end
-
-    def self.set_defaults_for_nix
-      # Those lists of regular expressions define what chef considers a
-      # valid user and group name
-      #
-      # user/group cannot start with '-', '+' or '~'
-      # user/group cannot contain ':', ',' or non-space-whitespace or null byte
-      # everything else is allowed (UTF-8, spaces, etc) and we delegate to your O/S useradd program to barf or not
-      # copies: http://anonscm.debian.org/viewvc/pkg-shadow/debian/trunk/debian/patches/506_relaxed_usernames?view=markup
-      default :user_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
-      default :group_valid_regex, [ /^[^-+~:,\t\r\n\f\0]+[^:,\t\r\n\f\0]*$/ ]
-    end
-
-    # Those lists of regular expressions define what chef considers a
-    # valid user and group name
-    if Chef::Platform.windows?
-      set_defaults_for_windows
-    else
-      set_defaults_for_nix
-    end
-
-    # This provides a hook which rspec can stub so that we can avoid twiddling
-    # global state in tests.
-    def self.env
-      ENV
-    end
-
-    def self.windows_home_path
-      Chef::Log.deprecation("Chef::Config.windows_home_path is now deprecated.  Consider using Chef::Util::PathHelper.home instead.")
-      PathHelper.home
-    end
-
-    # returns a platform specific path to the user home dir if set, otherwise default to current directory.
-    default( :user_home ) { PathHelper.home || Dir.pwd }
-
-    # Enable file permission fixup for selinux. Fixup will be done
-    # only if selinux is enabled in the system.
-    default :enable_selinux_file_permission_fixup, true
-
-    # Use atomic updates (i.e. move operation) while updating contents
-    # of the files resources. When set to false copy operation is
-    # used to update files.
-    default :file_atomic_update, true
-
-    # There are 3 possible values for this configuration setting.
-    # true => file staging is done in the destination directory
-    # false => file staging is done via tempfiles under ENV['TMP']
-    # :auto => file staging will try using destination directory if possible and
-    #   will fall back to ENV['TMP'] if destination directory is not usable.
-    default :file_staging_uses_destdir, :auto
-
-    # Exit if another run is in progress and the chef-client is unable to
-    # get the lock before time expires. If nil, no timeout is enforced. (Exits
-    # immediately if 0.)
-    default :run_lock_timeout, nil
-
-    # Number of worker threads for syncing cookbooks in parallel. Increasing
-    # this number can result in gateway errors from the server (namely 503 and 504).
-    # If you are seeing this behavior while using the default setting, reducing
-    # the number of threads will help.
-    default :cookbook_sync_threads, 10
-
-    # At the beginning of the Chef Client run, the cookbook manifests are downloaded which
-    # contain URLs for every file in every relevant cookbook.  Most of the files
-    # (recipes, resources, providers, libraries, etc) are immediately synchronized
-    # at the start of the run.  The handling of "files" and "templates" directories,
-    # however, have two modes of operation.  They can either all be downloaded immediately
-    # at the start of the run (no_lazy_load==true) or else they can be lazily loaded as
-    # cookbook_file or template resources are converged which require them (no_lazy_load==false).
-    #
-    # The advantage of lazily loading these files is that unnecessary files are not
-    # synchronized.  This may be useful to users with large files checked into cookbooks which
-    # are only selectively downloaded to a subset of clients which use the cookbook.  However,
-    # better solutions are to either isolate large files into individual cookbooks and only
-    # include those cookbooks in the run lists of the servers that need them -- or move to
-    # using remote_file and a more appropriate backing store like S3 for large file
-    # distribution.
+    # Override the default values that were set by Ohai.
     #
-    # The disadvantages of lazily loading files are that users some time find it
-    # confusing that their cookbooks are not fully synchronzied to the cache initially,
-    # and more importantly the time-sensitive URLs which are in the manifest may time
-    # out on long Chef runs before the resource that uses the file is converged
-    # (leading to many confusing 403 errors on template/cookbook_file resources).
-    #
-    default :no_lazy_load, true
-
-    # Default for the chef_gem compile_time attribute.  Nil is the same as true but will emit
-    # warnings on every use of chef_gem prompting the user to be explicit.  If the user sets this to
-    # true then the user will get backcompat behavior but with a single nag warning that cookbooks
-    # may break with this setting in the future.  The false setting is the recommended setting and
-    # will become the default.
-    default :chef_gem_compile_time, nil
-
-    # A whitelisted array of attributes you want sent over the wire when node
-    # data is saved.
-    # The default setting is nil, which collects all data. Setting to [] will not
-    # collect any data for save.
-    default :automatic_attribute_whitelist, nil
-    default :default_attribute_whitelist, nil
-    default :normal_attribute_whitelist, nil
-    default :override_attribute_whitelist, nil
-
-    config_context :windows_service do
-      # Set `watchdog_timeout` to the number of seconds to wait for a chef-client run
-      # to finish
-      default :watchdog_timeout, 2 * (60 * 60) # 2 hours
-    end
+    # REMOVEME once these configurables are removed from the top level of Ohai.
+    default :log_level, LOG_LEVEL
+    default :log_location, LOG_LOCATION
 
-    # Chef requires an English-language UTF-8 locale to function properly.  We attempt
-    # to use the 'locale -a' command and search through a list of preferences until we
-    # find one that we can use.  On Ubuntu systems we should find 'C.UTF-8' and be
-    # able to use that even if there is no English locale on the server, but Mac, Solaris,
-    # AIX, etc do not have that locale.  We then try to find an English locale and fall
-    # back to 'C' if we do not.  The choice of fallback is pick-your-poison.  If we try
-    # to do the work to return a non-US UTF-8 locale then we fail inside of providers when
-    # things like 'svn info' return Japanese and we can't parse them.  OTOH, if we pick 'C' then
-    # we will blow up on UTF-8 characters.  Between the warn we throw and the Encoding
-    # exception that ruby will throw it is more obvious what is broken if we drop UTF-8 by
-    # default rather than drop English.
+    # Ohai::Config[:log_level] is deprecated and warns when set. Unfortunately,
+    # there is no way to distinguish between setting log_level and setting
+    # Ohai::Config[:log_level]. Since log_level and log_location are used by
+    # chef-client and other tools (e.g., knife), we will mute the warnings here
+    # by redefining the config_attr_writer to not warn for these options.
     #
-    # If there is no 'locale -a' then we return 'en_US.UTF-8' since that is the most commonly
-    # available English UTF-8 locale.  However, all modern POSIXen should support 'locale -a'.
-    def self.guess_internal_locale
-      # https://github.com/opscode/chef/issues/2181
-      # Some systems have the `locale -a` command, but the result has
-      # invalid characters for the default encoding.
-      #
-      # For example, on CentOS 6 with ENV['LANG'] = "en_US.UTF-8",
-      # `locale -a`.split fails with ArgumentError invalid UTF-8 encoding.
-      locales = shell_out_with_systems_locale!("locale -a").stdout.split
-      case
-      when locales.include?('C.UTF-8')
-        'C.UTF-8'
-      when locales.include?('en_US.UTF-8'), locales.include?('en_US.utf8')
-        'en_US.UTF-8'
-      when locales.include?('en.UTF-8')
-        'en.UTF-8'
-      else
-        # Will match en_ZZ.UTF-8, en_ZZ.utf-8, en_ZZ.UTF8, en_ZZ.utf8
-        guesses = locales.select { |l| l =~ /^en_.*UTF-?8$/i }
-        unless guesses.empty?
-          guessed_locale = guesses.first
-          # Transform into the form en_ZZ.UTF-8
-          guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
-        else
-          Chef::Log.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
-          'C'
-        end
-      end
-    rescue
-      if Chef::Platform.windows?
-        Chef::Log.debug "Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else."
-      else
-        Chef::Log.debug "No usable locale -a command found, assuming you have en_US.UTF-8 installed."
+    # REMOVEME once the warnings for these configurables are removed from Ohai.
+    [ :log_level, :log_location ].each do |option|
+      config_attr_writer option do |value|
+        value
       end
-      'en_US.UTF-8'
     end
 
-    default :internal_locale, guess_internal_locale
-
-    # Force UTF-8 Encoding, for when we fire up in the 'C' locale or other strange locales (e.g.
-    # japanese windows encodings).  If we do not do this, then knife upload will fail when a cookbook's
-    # README.md has UTF-8 characters that do not encode in whatever surrounding encoding we have been
-    # passed.  Effectively, the Chef Ecosystem is globally UTF-8 by default.  Anyone who wants to be
-    # able to upload Shift_JIS or ISO-8859-1 files needs to mark *those* files explicitly with
-    # magic tags to make ruby correctly identify the encoding being used.  Changing this default will
-    # break Chef community cookbooks and is very highly discouraged.
-    default :ruby_encoding, Encoding::UTF_8
-
-    # If installed via an omnibus installer, this gives the path to the
-    # "embedded" directory which contains all of the software packaged with
-    # omnibus. This is used to locate the cacert.pem file on windows.
-    def self.embedded_dir
-      Pathname.new(_this_file).ascend do |path|
-        if path.basename.to_s == "embedded"
-          return path.to_s
-        end
-      end
-
-      nil
-    end
-
-    # Path to this file in the current install.
-    def self._this_file
-      File.expand_path(__FILE__)
-    end
   end
 end
diff --git a/lib/chef/config_fetcher.rb b/lib/chef/config_fetcher.rb
index a8aad07..13f9fc3 100644
--- a/lib/chef/config_fetcher.rb
+++ b/lib/chef/config_fetcher.rb
@@ -1,7 +1,7 @@
-require 'chef/application'
-require 'chef/chef_fs/path_utils'
-require 'chef/http/simple'
-require 'chef/json_compat'
+require "chef/application"
+require "chef/chef_fs/path_utils"
+require "chef/http/simple"
+require "chef/json_compat"
 
 class Chef
   class ConfigFetcher
@@ -12,6 +12,14 @@ class Chef
       @config_location = config_location
     end
 
+    def expanded_path
+      if config_location.nil? || remote_config?
+        config_location
+      else
+        File.expand_path(config_location)
+      end
+    end
+
     def fetch_json
       config_data = read_config
       begin
diff --git a/lib/chef/constants.rb b/lib/chef/constants.rb
new file mode 100644
index 0000000..f32c3e6
--- /dev/null
+++ b/lib/chef/constants.rb
@@ -0,0 +1,28 @@
+#
+# Author:: John Keiser <jkeiser at chef.io>
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Chef
+  NOT_PASSED = Object.new
+  def NOT_PASSED.to_s
+    "NOT_PASSED"
+  end
+
+  def NOT_PASSED.inspect
+    to_s
+  end
+  NOT_PASSED.freeze
+end
diff --git a/lib/chef/cookbook/chefignore.rb b/lib/chef/cookbook/chefignore.rb
index aa9345e..71ef53c 100644
--- a/lib/chef/cookbook/chefignore.rb
+++ b/lib/chef/cookbook/chefignore.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,7 @@ class Chef
       end
 
       def ignored?(file_name)
-        @ignores.any? {|glob| File.fnmatch?(glob, file_name)}
+        @ignores.any? { |glob| File.fnmatch?(glob, file_name) }
       end
 
       private
@@ -61,7 +61,7 @@ class Chef
         if File.basename(path) =~ /chefignore/
           path
         else
-          File.join(path, 'chefignore')
+          File.join(path, "chefignore")
         end
       end
 
@@ -72,4 +72,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/cookbook/cookbook_collection.rb b/lib/chef/cookbook/cookbook_collection.rb
index ae63abf..81e7bb9 100644
--- a/lib/chef/cookbook/cookbook_collection.rb
+++ b/lib/chef/cookbook/cookbook_collection.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/mash'
+require "chef/mash"
 
 class Chef
   # == Chef::CookbookCollection
@@ -33,13 +33,26 @@ class Chef
 
     # The input is a mapping of cookbook name to CookbookVersion objects. We
     # simply extract them
-    def initialize(cookbook_versions={})
+    def initialize(cookbook_versions = {})
       super() do |hash, key|
         raise Chef::Exceptions::CookbookNotFound, "Cookbook #{key} not found. " <<
           "If you're loading #{key} from another cookbook, make sure you configure the dependency in your metadata"
       end
-      cookbook_versions.each{ |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
+      cookbook_versions.each { |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
     end
 
+    # Validates that the cookbook metadata allows it to run on this instance.
+    #
+    # Currently checks chef_version and ohai_version in the cookbook metadata
+    # against the running Chef::VERSION and Ohai::VERSION.
+    #
+    # @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the Chef::VERSION fails validation
+    # @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the Ohai::VERSION fails validation
+    def validate!
+      each do |cookbook_name, cookbook_version|
+        cookbook_version.metadata.validate_chef_version!
+        cookbook_version.metadata.validate_ohai_version!
+      end
+    end
   end
 end
diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb
index bcbfcbe..04be8c7 100644
--- a/lib/chef/cookbook/cookbook_version_loader.rb
+++ b/lib/chef/cookbook/cookbook_version_loader.rb
@@ -1,8 +1,8 @@
 
-require 'chef/cookbook_version'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/metadata'
-require 'chef/util/path_helper'
+require "chef/cookbook_version"
+require "chef/cookbook/chefignore"
+require "chef/cookbook/metadata"
+require "chef/util/path_helper"
 
 class Chef
   class Cookbook
@@ -32,7 +32,7 @@ class Chef
 
       attr_reader :metadata_error
 
-      def initialize(path, chefignore=nil)
+      def initialize(path, chefignore = nil)
         @cookbook_path = File.expand_path( path ) # cookbook_path from which this was loaded
         # We keep a list of all cookbook paths that have been merged in
         @cookbook_paths = [ cookbook_path ]
@@ -51,7 +51,7 @@ class Chef
           :library_filenames    => {},
           :resource_filenames   => {},
           :provider_filenames   => {},
-          :root_filenames       => {}
+          :root_filenames       => {},
         }
 
         @metadata_filenames = []
@@ -78,10 +78,10 @@ class Chef
         # re-raise any exception that occurred when reading the metadata
         raise_metadata_error!
 
-        load_as(:attribute_filenames, 'attributes', '*.rb')
-        load_as(:definition_filenames, 'definitions', '*.rb')
-        load_as(:recipe_filenames, 'recipes', '*.rb')
-        load_recursively_as(:library_filenames, 'libraries', '*.rb')
+        load_as(:attribute_filenames, "attributes", "*.rb")
+        load_as(:definition_filenames, "definitions", "*.rb")
+        load_as(:recipe_filenames, "recipes", "*.rb")
+        load_recursively_as(:library_filenames, "libraries", "*.rb")
         load_recursively_as(:template_filenames, "templates", "*")
         load_recursively_as(:file_filenames, "files", "*")
         load_recursively_as(:resource_filenames, "resources", "*.rb")
@@ -91,7 +91,7 @@ class Chef
         remove_ignored_files
 
         if empty?
-          Chef::Log.warn "found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
+          Chef::Log.warn "Found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
         end
         @cookbook_settings
       end
@@ -213,7 +213,7 @@ class Chef
       end
 
       def load_root_files
-        Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), '*'), File::FNM_DOTMATCH).each do |file|
+        Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), "*"), File::FNM_DOTMATCH).each do |file|
           file = Chef::Util::PathHelper.cleanpath(file)
           next if File.directory?(file)
           next if File.basename(file) == UPLOADED_COOKBOOK_VERSION_FILE
@@ -223,7 +223,7 @@ class Chef
       end
 
       def load_recursively_as(category, category_dir, glob)
-        file_spec = File.join(Chef::Util::PathHelper.escape_glob(cookbook_path, category_dir), '**', glob)
+        file_spec = File.join(Chef::Util::PathHelper.escape_glob(cookbook_path, category_dir), "**", glob)
         Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
           file = Chef::Util::PathHelper.cleanpath(file)
           next if File.directory?(file)
@@ -269,7 +269,7 @@ class Chef
       def apply_json_cookbook_version_metadata(file)
         begin
           data = Chef::JSONCompat.parse(IO.read(file))
-          @metadata.from_hash(data['metadata'])
+          @metadata.from_hash(data["metadata"])
           # the JSON cookbok metadata file is only used by chef-zero.
           # The Chef Server API currently does not enforce that the metadata
           # have a `name` field, but that will cause an error when attempting
@@ -278,7 +278,7 @@ class Chef
           #
           # This behavior can be removed if/when Chef Server enforces that the
           # metadata contains a name key.
-          @metadata.name(data['cookbook_name']) unless data['metadata'].key?('name')
+          @metadata.name(data["cookbook_name"]) unless data["metadata"].key?("name")
         rescue Chef::Exceptions::JSON::ParseError
           Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in " + file)
           raise
@@ -289,7 +289,7 @@ class Chef
         if uploaded_cookbook_version_file
           begin
             data = Chef::JSONCompat.parse(IO.read(uploaded_cookbook_version_file))
-            @frozen = data['frozen?']
+            @frozen = data["frozen?"]
           rescue Chef::Exceptions::JSON::ParseError
             Chef::Log.error("Couldn't parse cookbook metadata JSON for #@inferred_cookbook_name in #{uploaded_cookbook_version_file}")
             raise
diff --git a/lib/chef/cookbook/file_system_file_vendor.rb b/lib/chef/cookbook/file_system_file_vendor.rb
index e351ec4..91f1c9f 100644
--- a/lib/chef/cookbook/file_system_file_vendor.rb
+++ b/lib/chef/cookbook/file_system_file_vendor.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/cookbook/file_vendor'
+require "chef/cookbook/file_vendor"
 
 class Chef
   class Cookbook
diff --git a/lib/chef/cookbook/file_vendor.rb b/lib/chef/cookbook/file_vendor.rb
index b82b52f..f849f79 100644
--- a/lib/chef/cookbook/file_vendor.rb
+++ b/lib/chef/cookbook/file_vendor.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
 # limitations under the License.
 #
 
-
 class Chef
   class Cookbook
     # == Chef::Cookbook::FileVendor
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 781d3b4..7cc4be9 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,15 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/mash'
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
-require 'chef/log'
-require 'chef/version_class'
-require 'chef/version_constraint'
-require 'chef/json_compat'
+require "chef/exceptions"
+require "chef/mash"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
+require "chef/log"
+require "chef/version_class"
+require "chef/version_constraint"
+require "chef/version_constraint/platform"
+require "chef/json_compat"
 
 class Chef
   class Cookbook
@@ -35,38 +36,43 @@ class Chef
     # about Chef Cookbooks.
     class Metadata
 
-      NAME                   = 'name'.freeze
-      DESCRIPTION            = 'description'.freeze
-      LONG_DESCRIPTION       = 'long_description'.freeze
-      MAINTAINER             = 'maintainer'.freeze
-      MAINTAINER_EMAIL       = 'maintainer_email'.freeze
-      LICENSE                = 'license'.freeze
-      PLATFORMS              = 'platforms'.freeze
-      DEPENDENCIES           = 'dependencies'.freeze
-      RECOMMENDATIONS        = 'recommendations'.freeze
-      SUGGESTIONS            = 'suggestions'.freeze
-      CONFLICTING            = 'conflicting'.freeze
-      PROVIDING              = 'providing'.freeze
-      REPLACING              = 'replacing'.freeze
-      ATTRIBUTES             = 'attributes'.freeze
-      GROUPINGS              = 'groupings'.freeze
-      RECIPES                = 'recipes'.freeze
-      VERSION                = 'version'.freeze
-      SOURCE_URL             = 'source_url'.freeze
-      ISSUES_URL             = 'issues_url'.freeze
+      NAME                   = "name".freeze
+      DESCRIPTION            = "description".freeze
+      LONG_DESCRIPTION       = "long_description".freeze
+      MAINTAINER             = "maintainer".freeze
+      MAINTAINER_EMAIL       = "maintainer_email".freeze
+      LICENSE                = "license".freeze
+      PLATFORMS              = "platforms".freeze
+      DEPENDENCIES           = "dependencies".freeze
+      RECOMMENDATIONS        = "recommendations".freeze
+      SUGGESTIONS            = "suggestions".freeze
+      CONFLICTING            = "conflicting".freeze
+      PROVIDING              = "providing".freeze
+      REPLACING              = "replacing".freeze
+      ATTRIBUTES             = "attributes".freeze
+      GROUPINGS              = "groupings".freeze
+      RECIPES                = "recipes".freeze
+      VERSION                = "version".freeze
+      SOURCE_URL             = "source_url".freeze
+      ISSUES_URL             = "issues_url".freeze
+      PRIVACY                = "privacy".freeze
+      CHEF_VERSIONS          = "chef_versions".freeze
+      OHAI_VERSIONS          = "ohai_versions".freeze
 
       COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer,
                             :maintainer_email, :license, :platforms, :dependencies,
                             :recommendations, :suggestions, :conflicting, :providing,
                             :replacing, :attributes, :groupings, :recipes, :version,
-                            :source_url, :issues_url ]
+                            :source_url, :issues_url, :privacy, :chef_versions, :ohai_versions ]
 
-      VERSION_CONSTRAINTS = {:depends     => DEPENDENCIES,
-                             :recommends  => RECOMMENDATIONS,
-                             :suggests    => SUGGESTIONS,
-                             :conflicts   => CONFLICTING,
-                             :provides    => PROVIDING,
-                             :replaces    => REPLACING }
+      VERSION_CONSTRAINTS = { :depends      => DEPENDENCIES,
+                              :recommends   => RECOMMENDATIONS,
+                              :suggests     => SUGGESTIONS,
+                              :conflicts    => CONFLICTING,
+                              :provides     => PROVIDING,
+                              :replaces     => REPLACING,
+                              :chef_version => CHEF_VERSIONS,
+                              :ohai_version => OHAI_VERSIONS }
 
       include Chef::Mixin::ParamsValidate
       include Chef::Mixin::FromFile
@@ -83,6 +89,11 @@ class Chef
       attr_reader :recipes
       attr_reader :version
 
+      # @return [Array<Gem::Dependency>] Array of supported Chef versions
+      attr_reader :chef_versions
+      # @return [Array<Gem::Dependency>] Array of supported Ohai versions
+      attr_reader :ohai_versions
+
       # Builds a new Chef::Cookbook::Metadata object.
       #
       # === Parameters
@@ -94,11 +105,11 @@ class Chef
       # === Returns
       # metadata<Chef::Cookbook::Metadata>
       def initialize
-        @name =  nil
+        @name = nil
 
-        @description = ''
-        @long_description = ''
-        @license = 'All rights reserved'
+        @description = ""
+        @long_description = ""
+        @license = "All rights reserved"
 
         @maintainer = nil
         @maintainer_email = nil
@@ -114,8 +125,11 @@ class Chef
         @groupings = Mash.new
         @recipes = Mash.new
         @version = Version.new("0.0.0")
-        @source_url = ''
-        @issues_url = ''
+        @source_url = ""
+        @issues_url = ""
+        @privacy = false
+        @chef_versions = []
+        @ohai_versions = []
 
         @errors = []
       end
@@ -159,11 +173,11 @@ class Chef
       #
       # === Returns
       # maintainer<String>:: Returns the current maintainer.
-      def maintainer(arg=nil)
+      def maintainer(arg = nil)
         set_or_return(
           :maintainer,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -174,11 +188,11 @@ class Chef
       #
       # === Returns
       # maintainer_email<String>:: Returns the current maintainer email.
-      def maintainer_email(arg=nil)
+      def maintainer_email(arg = nil)
         set_or_return(
           :maintainer_email,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -189,11 +203,11 @@ class Chef
       #
       # === Returns
       # license<String>:: Returns the current license
-      def license(arg=nil)
+      def license(arg = nil)
         set_or_return(
           :license,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -204,11 +218,11 @@ class Chef
       #
       # === Returns
       # description<String>:: Returns the description
-      def description(arg=nil)
+      def description(arg = nil)
         set_or_return(
           :description,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -219,11 +233,11 @@ class Chef
       #
       # === Returns
       # long_description<String>:: Returns the long description
-      def long_description(arg=nil)
+      def long_description(arg = nil)
         set_or_return(
           :long_description,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -235,7 +249,7 @@ class Chef
       #
       # === Returns
       # version<String>:: Returns the current version
-      def version(arg=nil)
+      def version(arg = nil)
         if arg
           @version = Chef::Version.new(arg)
         end
@@ -250,11 +264,11 @@ class Chef
       #
       # === Returns
       # name<String>:: Returns the current cookbook name.
-      def name(arg=nil)
+      def name(arg = nil)
         set_or_return(
           :name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -286,9 +300,13 @@ class Chef
       # === Returns
       # versions<Array>:: Returns the list of versions for the platform
       def depends(cookbook, *version_args)
-        version = new_args_format(:depends, cookbook, version_args)
-        constraint = validate_version_constraint(:depends, cookbook, version)
-        @dependencies[cookbook] = constraint.to_s
+        if cookbook == name
+          Chef::Log.warn "Ignoring self-dependency in cookbook #{name}, please remove it (in the future this will be fatal)."
+        else
+          version = new_args_format(:depends, cookbook, version_args)
+          constraint = validate_version_constraint(:depends, cookbook, version)
+          @dependencies[cookbook] = constraint.to_s
+        end
         @dependencies[cookbook]
       end
 
@@ -303,7 +321,7 @@ class Chef
       # === Returns
       # versions<Array>:: Returns the list of versions for the platform
       def recommends(cookbook, *version_args)
-        version = new_args_format(:recommends, cookbook,  version_args)
+        version = new_args_format(:recommends, cookbook, version_args)
         constraint = validate_version_constraint(:recommends, cookbook, version)
         @recommendations[cookbook] = constraint.to_s
         @recommendations[cookbook]
@@ -380,6 +398,28 @@ class Chef
         @replacing[cookbook]
       end
 
+      # Metadata DSL to set a valid chef_version.  May be declared multiple times
+      # with the result being 'OR'd such that if any statements match, the version
+      # is considered supported.  Uses Gem::Requirement for its implementation.
+      #
+      # @param version_args [Array<String>] Version constraint in String form
+      # @return [Array<Gem::Dependency>] Current chef_versions array
+      def chef_version(*version_args)
+        @chef_versions << Gem::Dependency.new("chef", *version_args) unless version_args.empty?
+        @chef_versions
+      end
+
+      # Metadata DSL to set a valid ohai_version.  May be declared multiple times
+      # with the result being 'OR'd such that if any statements match, the version
+      # is considered supported.  Uses Gem::Requirement for its implementation.
+      #
+      # @param version_args [Array<String>] Version constraint in String form
+      # @return [Array<Gem::Dependency>] Current ohai_versions array
+      def ohai_version(*version_args)
+        @ohai_versions << Gem::Dependency.new("ohai", *version_args) unless version_args.empty?
+        @ohai_versions
+      end
+
       # Adds a description for a recipe.
       #
       # === Parameters
@@ -450,8 +490,9 @@ class Chef
             :recipes => { :kind_of => [ Array ], :default => [] },
             :default => { :kind_of => [ String, Array, Hash, Symbol, Numeric, TrueClass, FalseClass ] },
             :source_url => { :kind_of => String },
-            :issues_url => { :kind_of => String }
-          }
+            :issues_url => { :kind_of => String },
+            :privacy => { :kind_of => [ TrueClass, FalseClass ] },
+          },
         )
         options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil?
         validate_choice_array(options)
@@ -467,13 +508,47 @@ class Chef
           options,
           {
             :title => { :kind_of => String },
-            :description => { :kind_of => String }
-          }
+            :description => { :kind_of => String },
+          },
         )
         @groupings[name] = options
         @groupings[name]
       end
 
+      # Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to an Array.
+      #
+      # Gem::Dependencey#to_s is not useful, and there is no #to_json defined on it or its component
+      # objets, so we have to write our own rendering method.
+      #
+      # [ Gem::Dependency.new(">= 12.5"), Gem::Dependency.new(">= 11.18.0", "< 12.0") ]
+      #
+      # results in:
+      #
+      # [ [ ">= 12.5" ], [ ">= 11.18.0", "< 12.0" ] ]
+      #
+      # @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
+      # @return [Array<Array<String>]] Simple object representation of version constraints (for json)
+      def gem_requirements_to_array(*deps)
+        deps.map do |dep|
+          dep.requirement.requirements.map do |op, version|
+            "#{op} #{version}"
+          end.sort
+        end
+      end
+
+      # Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to a hash.
+      #
+      # This is the inverse of #gem_requirements_to_array
+      #
+      # @param what [String] What version constraint we are constructing ('chef' or 'ohai' presently)
+      # @param array [Array<Array<String>]] Simple object representation of version constraints (from json)
+      # @return [Array<Gem::Dependency>] Multiple Gem-style version constraints
+      def gem_requirements_from_array(what, array)
+        array.map do |dep|
+          Gem::Dependency.new(what, *dep)
+        end
+      end
+
       def to_hash
         {
           NAME                   => self.name,
@@ -494,7 +569,10 @@ class Chef
           RECIPES                => self.recipes,
           VERSION                => self.version,
           SOURCE_URL             => self.source_url,
-          ISSUES_URL             => self.issues_url
+          ISSUES_URL             => self.issues_url,
+          PRIVACY                => self.privacy,
+          CHEF_VERSIONS          => gem_requirements_to_array(*self.chef_versions),
+          OHAI_VERSIONS          => gem_requirements_to_array(*self.ohai_versions),
         }
       end
 
@@ -528,6 +606,9 @@ class Chef
         @version                      = o[VERSION] if o.has_key?(VERSION)
         @source_url                   = o[SOURCE_URL] if o.has_key?(SOURCE_URL)
         @issues_url                   = o[ISSUES_URL] if o.has_key?(ISSUES_URL)
+        @privacy                      = o[PRIVACY] if o.has_key?(PRIVACY)
+        @chef_versions                = gem_requirements_from_array("chef", o[CHEF_VERSIONS]) if o.has_key?(CHEF_VERSIONS)
+        @ohai_versions                = gem_requirements_from_array("ohai", o[OHAI_VERSIONS]) if o.has_key?(OHAI_VERSIONS)
         self
       end
 
@@ -541,11 +622,11 @@ class Chef
         metadata = new()
         VERSION_CONSTRAINTS.each do |dependency_type, hash_key|
           if dependency_group = o[hash_key]
-           dependency_group.each do |cb_name, constraints|
-             if metadata.respond_to?(method_name)
-               metadata.public_send(method_name, cb_name, *Array(constraints))
-             end
-           end
+            dependency_group.each do |cb_name, constraints|
+              if metadata.respond_to?(method_name)
+                metadata.public_send(method_name, cb_name, *Array(constraints))
+              end
+            end
           end
         end
         true
@@ -563,11 +644,11 @@ class Chef
       #
       # === Returns
       # source_url<String>:: Returns the current source URL.
-      def source_url(arg=nil)
+      def source_url(arg = nil)
         set_or_return(
           :source_url,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -578,16 +659,68 @@ class Chef
       #
       # === Returns
       # issues_url<String>:: Returns the current issues URL.
-      def issues_url(arg=nil)
+      def issues_url(arg = nil)
         set_or_return(
           :issues_url,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
+        )
+      end
+
+      #
+      # Sets the cookbook's privacy flag, or returns it.
+      #
+      # === Parameters
+      # privacy<TrueClass,FalseClass>:: Whether this cookbook is private or not
+      #
+      # === Returns
+      # privacy<TrueClass,FalseClass>:: Whether this cookbook is private or not
+      #
+      def privacy(arg = nil)
+        set_or_return(
+          :privacy,
+          arg,
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
+      # Validates that the Ohai::VERSION of the running chef-client matches one of the
+      # configured ohai_version statements in this cookbooks metadata.
+      #
+      # @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the cookbook fails validation
+      def validate_ohai_version!
+        unless gem_dep_matches?("ohai", Gem::Version.new(Ohai::VERSION), *ohai_versions)
+          raise Exceptions::CookbookOhaiVersionMismatch.new(Ohai::VERSION, name, version, *ohai_versions)
+        end
+      end
+
+      # Validates that the Chef::VERSION of the running chef-client matches one of the
+      # configured chef_version statements in this cookbooks metadata.
+      #
+      # @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the cookbook fails validation
+      def validate_chef_version!
+        unless gem_dep_matches?("chef", Gem::Version.new(Chef::VERSION), *chef_versions)
+          raise Exceptions::CookbookChefVersionMismatch.new(Chef::VERSION, name, version, *chef_versions)
+        end
+      end
+
     private
 
+      # Helper to match a gem style version (ohai_version/chef_version) against a set of
+      # Gem::Dependency version constraints.  If none are present, it always matches.  if
+      # multiple are present, one must match.  Returns false if none matches.
+      #
+      # @param what [String] the name of the constraint (e.g. 'chef' or 'ohai')
+      # @param version [String] the version to compare against the constraints
+      # @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
+      # @return [Boolean] true if no constraints or a match, false if no match
+      def gem_dep_matches?(what, version, *deps)
+        # always match if we have no chef_version at all
+        return true unless deps.length > 0
+        # match if we match any of the chef_version lines
+        deps.any? { |dep| dep.match?(what, version) }
+      end
+
       def run_validation
         if name.nil?
           @errors = ["The `name' attribute is required in cookbook metadata"]
@@ -600,33 +733,33 @@ class Chef
         elsif version_constraints.size == 1
           version_constraints.first
         else
-          msg=<<-OBSOLETED
+          msg = <<-OBSOLETED
 The dependency specification syntax you are using is no longer valid. You may not
 specify more than one version constraint for a particular cookbook.
-Consult http://wiki.opscode.com/display/chef/Metadata for the updated syntax.
+Consult https://docs.chef.io/config_rb_metadata.html for the updated syntax.
 
-Called by: #{caller_name} '#{dep_name}', #{version_constraints.map {|vc| vc.inspect}.join(", ")}
+Called by: #{caller_name} '#{dep_name}', #{version_constraints.map { |vc| vc.inspect }.join(", ")}
 Called from:
-#{caller[0...5].map {|line| "  " + line}.join("\n")}
+#{caller[0...5].map { |line| "  " + line }.join("\n")}
 OBSOLETED
           raise Exceptions::ObsoleteDependencySyntax, msg
         end
       end
 
       def validate_version_constraint(caller_name, dep_name, constraint_str)
-        Chef::VersionConstraint.new(constraint_str)
+        Chef::VersionConstraint::Platform.new(constraint_str)
       rescue Chef::Exceptions::InvalidVersionConstraint => e
         Log.debug(e)
 
-        msg=<<-INVALID
+        msg = <<-INVALID
 The version constraint syntax you are using is not valid. If you recently
 upgraded to Chef 0.10.0, be aware that you no may longer use "<<" and ">>" for
 'less than' and 'greater than'; use '<' and '>' instead.
-Consult http://wiki.opscode.com/display/chef/Metadata for more information.
+Consult https://docs.chef.io/config_rb_metadata.html for more information.
 
 Called by: #{caller_name} '#{dep_name}', '#{constraint_str}'
 Called from:
-#{caller[0...5].map {|line| "  " + line}.join("\n")}
+#{caller[0...5].map { |line| "  " + line }.join("\n")}
 INVALID
         raise Exceptions::InvalidVersionConstraint, msg
       end
@@ -640,7 +773,7 @@ INVALID
       def validate_string_array(arry)
         if arry.kind_of?(Array)
           arry.each do |choice|
-            validate( {:choice => choice}, {:choice => {:kind_of => String}} )
+            validate( { :choice => choice }, { :choice => { :kind_of => String } } )
           end
         end
       end
@@ -650,28 +783,28 @@ INVALID
       # Raise an exception if the members of the array do not match the defaults
       # === Parameters
       # opts<Hash>:: The options hash
-        def validate_choice_array(opts)
-          if opts[:choice].kind_of?(Array)
-            case opts[:type]
-            when "string"
-              validator = [ String ]
-            when "array"
-              validator = [ Array ]
-            when "hash"
-              validator = [ Hash ]
-            when "symbol"
-              validator = [ Symbol ]
-            when "boolean"
-              validator = [ TrueClass, FalseClass ]
-            when "numeric"
-              validator = [ Numeric ]
-            end
+      def validate_choice_array(opts)
+        if opts[:choice].kind_of?(Array)
+          case opts[:type]
+          when "string"
+            validator = [ String ]
+          when "array"
+            validator = [ Array ]
+          when "hash"
+            validator = [ Hash ]
+          when "symbol"
+            validator = [ Symbol ]
+          when "boolean"
+            validator = [ TrueClass, FalseClass ]
+          when "numeric"
+            validator = [ Numeric ]
+          end
 
-            opts[:choice].each do |choice|
-              validate( {:choice => choice}, {:choice => {:kind_of => validator}} )
-            end
+          opts[:choice].each do |choice|
+            validate( { :choice => choice }, { :choice => { :kind_of => validator } } )
           end
         end
+      end
 
       # For backwards compatibility, remap Boolean values to String
       #   true is mapped to "required"
@@ -727,7 +860,7 @@ INVALID
       def handle_deprecated_constraints(specification)
         specification.inject(Mash.new) do |acc, (cb, constraints)|
           constraints = Array(constraints)
-          acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<</, '<')
+          acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, ">").gsub(/<</, "<")
           acc
         end
       end
diff --git a/lib/chef/cookbook/remote_file_vendor.rb b/lib/chef/cookbook/remote_file_vendor.rb
index 9d895b1..e63d094 100644
--- a/lib/chef/cookbook/remote_file_vendor.rb
+++ b/lib/chef/cookbook/remote_file_vendor.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/cookbook/file_vendor'
+require "chef/cookbook/file_vendor"
 
 class Chef
   class Cookbook
@@ -45,10 +45,10 @@ class Chef
         end
 
         raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest[segment]
-        found_manifest_record = @manifest[segment].find {|manifest_record| manifest_record[:path] == filename }
+        found_manifest_record = @manifest[segment].find { |manifest_record| manifest_record[:path] == filename }
         raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record
 
-        cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record['path'])
+        cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record["path"])
 
         # update valid_cache_entries so the upstream cache cleaner knows what
         # we've used.
@@ -62,14 +62,14 @@ class Chef
         # If the checksums are different between on-disk (current) and on-server
         # (remote, per manifest), do the update. This will also execute if there
         # is no current checksum.
-        if current_checksum != found_manifest_record['checksum']
-          raw_file = @rest.get_rest(found_manifest_record[:url], true)
+        if current_checksum != found_manifest_record["checksum"]
+          raw_file = @rest.streaming_request(found_manifest_record[:url])
 
           Chef::Log.debug("Storing updated #{cache_filename} in the cache.")
           Chef::FileCache.move_to(raw_file.path, cache_filename)
         else
           Chef::Log.debug("Not fetching #{cache_filename}, as the cache is up to date.")
-          Chef::Log.debug("current checksum: #{current_checksum}; manifest checksum: #{found_manifest_record['checksum']})")
+          Chef::Log.debug("Current checksum: #{current_checksum}; manifest checksum: #{found_manifest_record['checksum']})")
         end
 
         full_path_cache_filename = Chef::FileCache.load(cache_filename, false)
diff --git a/lib/chef/cookbook/synchronizer.rb b/lib/chef/cookbook/synchronizer.rb
index 1b96d05..e8b90a4 100644
--- a/lib/chef/cookbook/synchronizer.rb
+++ b/lib/chef/cookbook/synchronizer.rb
@@ -1,6 +1,7 @@
-require 'chef/client'
-require 'chef/util/threaded_job_queue'
-require 'singleton'
+require "chef/client"
+require "chef/util/threaded_job_queue"
+require "chef/server_api"
+require "singleton"
 
 class Chef
 
@@ -131,7 +132,7 @@ class Chef
       files_remaining_by_cookbook[file.cookbook] -= 1
 
       if files_remaining_by_cookbook[file.cookbook] == 0
-        @events.synchronized_cookbook(file.cookbook.name)
+        @events.synchronized_cookbook(file.cookbook.name, file.cookbook)
       end
     end
 
@@ -140,7 +141,7 @@ class Chef
     # === Returns
     # true:: Always returns true
     def sync_cookbooks
-      Chef::Log.info("Loading cookbooks [#{cookbooks.map {|ckbk| ckbk.name + '@' + ckbk.version}.join(', ')}]")
+      Chef::Log.info("Loading cookbooks [#{cookbooks.map { |ckbk| ckbk.name + '@' + ckbk.version }.join(', ')}]")
       Chef::Log.debug("Cookbooks detail: #{cookbooks.inspect}")
 
       clear_obsoleted_cookbooks
@@ -175,7 +176,7 @@ class Chef
     # Saves the full_path to the file of the cookbook to be updated
     # in the manifest later
     def save_full_file_path(file, full_path)
-      @cookbook_full_file_paths[file.cookbook] ||= { }
+      @cookbook_full_file_paths[file.cookbook] ||= {}
       @cookbook_full_file_paths[file.cookbook][file.segment] ||= [ ]
       @cookbook_full_file_paths[file.cookbook][file.segment] << full_path
     end
@@ -244,14 +245,14 @@ class Chef
     # === Returns
     # Full path to the cached file as a String
     def sync_file(file)
-      cache_filename = File.join("cookbooks", file.cookbook.name, file.manifest_record['path'])
+      cache_filename = File.join("cookbooks", file.cookbook.name, file.manifest_record["path"])
       mark_cached_file_valid(cache_filename)
 
       # If the checksums are different between on-disk (current) and on-server
       # (remote, per manifest), do the update. This will also execute if there
       # is no current checksum.
-      if !cached_copy_up_to_date?(cache_filename, file.manifest_record['checksum'])
-        download_file(file.manifest_record['url'], cache_filename)
+      if !cached_copy_up_to_date?(cache_filename, file.manifest_record["checksum"])
+        download_file(file.manifest_record["url"], cache_filename)
         @events.updated_cookbook_file(file.cookbook.name, cache_filename)
       else
         Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
@@ -274,7 +275,7 @@ class Chef
     # downloaded to the path +destination+ which is relative to the Chef file
     # cache root.
     def download_file(url, destination)
-      raw_file = server_api.get_rest(url, true)
+      raw_file = server_api.streaming_request(url)
 
       Chef::Log.info("Storing updated #{destination} in the cache.")
       cache.move_to(raw_file.path, destination)
@@ -286,7 +287,7 @@ class Chef
     end
 
     def server_api
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
   end
diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb
index 96fc7e7..fd7835d 100644
--- a/lib/chef/cookbook/syntax_check.rb
+++ b/lib/chef/cookbook/syntax_check.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'pathname'
-require 'stringio'
-require 'erubis'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/checksum'
-require 'chef/util/path_helper'
+require "pathname"
+require "stringio"
+require "erubis"
+require "chef/mixin/shell_out"
+require "chef/mixin/checksum"
+require "chef/util/path_helper"
 
 class Chef
   class Cookbook
@@ -43,7 +43,7 @@ class Chef
 
         # Create a new PersistentSet. Values in the set are persisted by
         # creating a file in the +cache_path+ directory.
-        def initialize(cache_path=Chef::Config[:syntax_check_cache_path])
+        def initialize(cache_path = Chef::Config[:syntax_check_cache_path])
           @cache_path = cache_path
           @cache_path_created = false
         end
@@ -82,7 +82,7 @@ class Chef
 
       # Creates a new SyntaxCheck given the +cookbook_name+ and a +cookbook_path+.
       # If no +cookbook_path+ is given, +Chef::Config.cookbook_path+ is used.
-      def self.for_cookbook(cookbook_name, cookbook_path=nil)
+      def self.for_cookbook(cookbook_name, cookbook_path = nil)
         cookbook_path ||= Chef::Config.cookbook_path
         unless cookbook_path
           raise ArgumentError, "Cannot find cookbook #{cookbook_name} unless Chef::Config.cookbook_path is set or an explicit cookbook path is given"
@@ -115,7 +115,7 @@ class Chef
 
       def ruby_files
         path  = Chef::Util::PathHelper.escape_glob(cookbook_path)
-        files = Dir[File.join(path, '**', '*.rb')]
+        files = Dir[File.join(path, "**", "*.rb")]
         files = remove_ignored_files(files)
         files = remove_uninteresting_ruby_files(files)
         files
@@ -133,7 +133,7 @@ class Chef
       end
 
       def template_files
-        remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), '**/templates/**', '*.erb')]
+        remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), "**/templates/**", "*.erb")]
       end
 
       def untested_template_files
@@ -209,7 +209,7 @@ class Chef
 
       # Debug a syntax error in a template.
       def invalid_erb_file(erb_file, error_message)
-        file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
+        file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path + File::Separator)}(.*)/, 1]
         Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:")
         error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
         nil
@@ -244,7 +244,7 @@ class Chef
       # Debugs ruby syntax errors by printing the path to the file and any
       # diagnostic info given in +error_message+
       def invalid_ruby_file(ruby_file, error_message)
-        file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
+        file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path + File::Separator)}(.*)/, 1]
         Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:")
         error_message.each_line { |l| Chef::Log.fatal(l.chomp) }
         false
diff --git a/lib/chef/cookbook_loader.rb b/lib/chef/cookbook_loader.rb
index c05fedb..9bab6f0 100644
--- a/lib/chef/cookbook_loader.rb
+++ b/lib/chef/cookbook_loader.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/cookbook/cookbook_version_loader'
-require 'chef/cookbook_version'
-require 'chef/cookbook/chefignore'
-require 'chef/cookbook/metadata'
+require "chef/config"
+require "chef/exceptions"
+require "chef/cookbook/cookbook_version_loader"
+require "chef/cookbook_version"
+require "chef/cookbook/chefignore"
+require "chef/cookbook/metadata"
 
 #
 # CookbookLoader class loads the cookbooks lazily as read
@@ -44,7 +44,7 @@ class Chef
       @cookbooks_by_name = Mash.new
       @loaded_cookbooks = {}
       @metadata = Mash.new
-      @cookbooks_paths = Hash.new {|h,k| h[k] = []} # for deprecation warnings
+      @cookbooks_paths = Hash.new { |h, k| h[k] = [] } # for deprecation warnings
       @chefignores = {}
       @repo_paths = repo_paths.map do |repo_path|
         repo_path = File.expand_path(repo_path)
@@ -62,7 +62,7 @@ class Chef
 
     def merged_cookbook_paths # for deprecation warnings
       merged_cookbook_paths = {}
-      @merged_cookbooks.each {|c| merged_cookbook_paths[c] = @cookbooks_paths[c]}
+      @merged_cookbooks.each { |c| merged_cookbook_paths[c] = @cookbooks_paths[c] }
       merged_cookbook_paths
     end
 
@@ -106,7 +106,7 @@ class Chef
       if @cookbooks_by_name.has_key?(cookbook.to_sym) or load_cookbook(cookbook.to_sym)
         @cookbooks_by_name[cookbook.to_sym]
       else
-        raise Exceptions::CookbookNotFoundInRepo, "Cannot find a cookbook named #{cookbook.to_s}; did you forget to add metadata to a cookbook? (http://wiki.opscode.com/display/chef/Metadata)"
+        raise Exceptions::CookbookNotFoundInRepo, "Cannot find a cookbook named #{cookbook}; did you forget to add metadata to a cookbook? (https://docs.chef.io/config_rb_metadata.html)"
       end
     end
 
@@ -119,7 +119,7 @@ class Chef
     alias :key? :has_key?
 
     def each
-      @cookbooks_by_name.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |cname|
+      @cookbooks_by_name.keys.sort { |a, b| a.to_s <=> b.to_s }.each do |cname|
         yield(cname, @cookbooks_by_name[cname])
       end
     end
diff --git a/lib/chef/cookbook_manifest.rb b/lib/chef/cookbook_manifest.rb
index 10654a4..6e7458a 100644
--- a/lib/chef/cookbook_manifest.rb
+++ b/lib/chef/cookbook_manifest.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at chef.io>)
-# Copyright:: Copyright 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'forwardable'
-require 'chef/util/path_helper'
-require 'chef/log'
+require "forwardable"
+require "chef/util/path_helper"
+require "chef/log"
 
 class Chef
 
@@ -127,14 +127,14 @@ class Chef
 
     def to_hash
       result = manifest.dup
-      result['frozen?'] = frozen_version?
-      result['chef_type'] = 'cookbook_version'
+      result["frozen?"] = frozen_version?
+      result["chef_type"] = "cookbook_version"
       result.to_hash
     end
 
     def to_json(*a)
       result = to_hash
-      result['json_class'] = "Chef::CookbookVersion"
+      result["json_class"] = "Chef::CookbookVersion"
       Chef::JSONCompat.to_json(result, *a)
     end
 
@@ -152,6 +152,7 @@ class Chef
     def named_cookbook_url
       "#{cookbook_url_path}/#{name}"
     end
+
     # Adds the `force=true` parameter to the upload URL. This allows
     # the user to overwrite a frozen cookbook (a PUT against the
     # normal #save_url raises a 409 Conflict in this case).
@@ -169,7 +170,7 @@ class Chef
 
       COOKBOOK_SEGMENTS.each do |segment|
         next unless @manifest.has_key?(segment)
-        filenames = @manifest[segment].map{|manifest_record| manifest_record['name']}
+        filenames = @manifest[segment].map { |manifest_record| manifest_record["name"] }
 
         cookbook_version.replace_segment_filenames(segment, filenames)
       end
@@ -193,8 +194,8 @@ class Chef
         :templates => Array.new,
         :resources => Array.new,
         :providers => Array.new,
-        :root_files => Array.new
-      })
+        :root_files => Array.new,
+      },)
       @checksums = {}
 
       if !root_paths || root_paths.size == 0
@@ -215,8 +216,8 @@ class Chef
             :name => file_name,
             :path => path,
             :checksum => csum,
-            :specificity => specificity
-          })
+            :specificity => specificity,
+          },)
 
           manifest[segment] << rs
         end
@@ -243,17 +244,17 @@ class Chef
 
         parts = pathname.each_filename.take(2)
         # Check if path is actually under root_path
-        next if parts[0] == '..'
+        next if parts[0] == ".."
         if segment == :templates || segment == :files
           # Check if pathname looks like files/foo or templates/foo (unscoped)
           if pathname.each_filename.to_a.length == 2
             # Use root_default in case the same path exists at root_default and default
-            return [ pathname.to_s, 'root_default' ]
+            return [ pathname.to_s, "root_default" ]
           else
             return [ pathname.to_s, parts[1] ]
           end
         else
-          return [ pathname.to_s, 'default' ]
+          return [ pathname.to_s, "default" ]
         end
       end
       Chef::Log.error("Cookbook file #{segment_file} not under cookbook root paths #{root_paths.inspect}.")
diff --git a/lib/chef/cookbook_site_streaming_uploader.rb b/lib/chef/cookbook_site_streaming_uploader.rb
index 9e7a55c..d6a270b 100644
--- a/lib/chef/cookbook_site_streaming_uploader.rb
+++ b/lib/chef/cookbook_site_streaming_uploader.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Stanislav Vitvitskiy
-# Author:: Nuo Yan (nuo at opscode.com)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (nuo at chef.io)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2009-2016, 2010-2016 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,20 +18,20 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'net/http'
-require 'mixlib/authentication/signedheaderauth'
-require 'openssl'
+require "uri"
+require "net/http"
+require "mixlib/authentication/signedheaderauth"
+require "openssl"
 
 class Chef
   # == Chef::CookbookSiteStreamingUploader
   # A streaming multipart HTTP upload implementation. Used to upload cookbooks
-  # (in tarball form) to http://cookbooks.opscode.com
+  # (in tarball form) to https://supermarket.chef.io
   #
   # inspired by http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
   class CookbookSiteStreamingUploader
 
-    DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION }
+    DefaultHeaders = { "accept" => "application/json", "x-chef-version" => ::Chef::VERSION }
 
     class << self
 
@@ -73,7 +73,7 @@ class Chef
       end
 
       def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
-        boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
+        boundary = "----RubyMultipartClient" + rand(1000000).to_s + "ZZZZZ"
         parts = []
         content_file = nil
 
@@ -106,7 +106,7 @@ class Chef
 
         url = URI.parse(to_url)
 
-        Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
+        Chef::Log.logger.debug("Signing: method: #{http_verb}, url: #{url}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
 
         # We use the body for signing the request if the file parameter
         # wasn't a valid file or wasn't included. Extract the body (with
@@ -114,14 +114,14 @@ class Chef
         # TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
         # always hash the entire request body. In the file case it would just be
         # expanded multipart text - the entire body of the POST.
-        content_body = parts.inject("") { |result,part| result + part.read(0, part.size) }
+        content_body = parts.inject("") { |result, part| result + part.read(0, part.size) }
         content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
 
         signing_options = {
-          :http_method=>http_verb,
-          :path=>url.path,
-          :user_id=>user_id,
-          :timestamp=>timestamp}
+          :http_method => http_verb,
+          :path => url.path,
+          :user_id => user_id,
+          :timestamp => timestamp }
         (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
 
         headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
@@ -129,7 +129,7 @@ class Chef
         content_file.rewind if content_file
 
         # net/http doesn't like symbols for header keys, so we'll to_s each one just in case
-        headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten])
+        headers = DefaultHeaders.merge(Hash[*headers.map { |k, v| [k.to_s, v] }.flatten])
 
         req = case http_verb
               when :put
@@ -138,16 +138,11 @@ class Chef
                 Net::HTTP::Post.new(url.path, headers)
               end
         req.content_length = body_stream.size
-        req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
+        req.content_type = "multipart/form-data; boundary=" + boundary unless parts.empty?
         req.body_stream = body_stream
 
-        http = Net::HTTP.new(url.host, url.port)
-        if url.scheme == "https"
-          http.use_ssl = true
-          http.verify_mode = verify_mode
-        end
+        http = Chef::HTTP::BasicClient.new(url).http_client
         res = http.request(req)
-        #res = http.start {|http_proc| http_proc.request(req) }
 
         # alias status to code and to_s to body for test purposes
         # TODO: stop the following madness!
@@ -166,17 +161,6 @@ class Chef
         res
       end
 
-      private
-
-      def verify_mode
-        verify_mode = Chef::Config[:ssl_verify_mode]
-        if verify_mode == :verify_none
-          OpenSSL::SSL::VERIFY_NONE
-        elsif verify_mode == :verify_peer
-          OpenSSL::SSL::VERIFY_PEER
-        end
-      end
-
     end
 
     class StreamPart
@@ -217,12 +201,12 @@ class Chef
       end
 
       def size
-        @parts.inject(0) {|size, part| size + part.size}
+        @parts.inject(0) { |size, part| size + part.size }
       end
 
       def read(how_much, dst_buf = nil)
         if @part_no >= @parts.size
-          dst_buf.replace('') if dst_buf
+          dst_buf.replace("") if dst_buf
           return dst_buf
         end
 
@@ -245,14 +229,14 @@ class Chef
           next_part = read(how_much_next_part)
           result = current_part + if next_part
                                     next_part
-          else
-            ''
-          end
+                                  else
+                                    ""
+                                  end
         else
           @part_offset += how_much_current_part
           result = current_part
         end
-        dst_buf ? dst_buf.replace(result || '') : result
+        dst_buf ? dst_buf.replace(result || "") : result
       end
     end
 
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index f24ce2c..95c2779 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -1,14 +1,15 @@
 
-require 'set'
-require 'chef/exceptions'
-require 'chef/knife/cookbook_metadata'
-require 'chef/digester'
-require 'chef/cookbook_manifest'
-require 'chef/cookbook_version'
-require 'chef/cookbook/syntax_check'
-require 'chef/cookbook/file_system_file_vendor'
-require 'chef/util/threaded_job_queue'
-require 'chef/sandbox'
+require "set"
+require "chef/exceptions"
+require "chef/knife/cookbook_metadata"
+require "chef/digester"
+require "chef/cookbook_manifest"
+require "chef/cookbook_version"
+require "chef/cookbook/syntax_check"
+require "chef/cookbook/file_system_file_vendor"
+require "chef/util/threaded_job_queue"
+require "chef/sandbox"
+require "chef/server_api"
 
 class Chef
   class CookbookUploader
@@ -31,15 +32,15 @@ class Chef
     #           uploading the cookbook. This allows frozen CookbookVersion
     #           documents on the server to be overwritten (otherwise a 409 is
     #           returned by the server)
-    # * :rest   A Chef::REST object that you have configured the way you like it.
+    # * :rest   A Chef::ServerAPI object that you have configured the way you like it.
     #           If you don't provide this, one will be created using the values
     #           in Chef::Config.
     # * :concurrency   An integer that decided how many threads will be used to
     #           perform concurrent uploads
-    def initialize(cookbooks, opts={})
+    def initialize(cookbooks, opts = {})
       @opts = opts
       @cookbooks = Array(cookbooks)
-      @rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url])
+      @rest = opts[:rest] || Chef::ServerAPI.new(Chef::Config[:chef_server_url])
       @concurrency = opts[:concurrency] || 10
       @policy_mode = opts[:policy_mode] || false
     end
@@ -54,7 +55,7 @@ class Chef
         checksum_files.merge!(cb.checksums)
       end
 
-      checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
+      checksums = checksum_files.inject({}) { |memo, elt| memo[elt.first] = nil ; memo }
       new_sandbox = rest.post("sandboxes", { :checksums => checksums })
 
       Chef::Log.info("Uploading files")
@@ -64,11 +65,11 @@ class Chef
       checksums_to_upload = Set.new
 
       # upload the new checksums and commit the sandbox
-      new_sandbox['checksums'].each do |checksum, info|
-        if info['needs_upload'] == true
+      new_sandbox["checksums"].each do |checksum, info|
+        if info["needs_upload"] == true
           checksums_to_upload << checksum
           Chef::Log.info("Uploading #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}")
-          queue << uploader_function_for(checksum_files[checksum], checksum, info['url'], checksums_to_upload)
+          queue << uploader_function_for(checksum_files[checksum], checksum, info["url"], checksums_to_upload)
         else
           Chef::Log.debug("#{checksum_files[checksum]} has not changed")
         end
@@ -76,13 +77,13 @@ class Chef
 
       queue.process(@concurrency)
 
-      sandbox_url = new_sandbox['uri']
+      sandbox_url = new_sandbox["uri"]
       Chef::Log.debug("Committing sandbox")
       # Retry if S3 is claims a checksum doesn't exist (the eventual
       # in eventual consistency)
       retries = 0
       begin
-        rest.put(sandbox_url, {:is_completed => true})
+        rest.put(sandbox_url, { :is_completed => true })
       rescue Net::HTTPServerException => e
         if e.message =~ /^400/ && (retries += 1) <= 5
           sleep 2
@@ -119,10 +120,10 @@ class Chef
         # but we need the base64 encoding for the content-md5
         # header
         checksum64 = Base64.encode64([checksum].pack("H*")).strip
-        file_contents = File.open(file, "rb") {|f| f.read}
+        file_contents = File.open(file, "rb") { |f| f.read }
 
         # Custom headers. 'content-type' disables JSON serialization of the request body.
-        headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, "accept" => 'application/json' }
+        headers = { "content-type" => "application/x-binary", "content-md5" => checksum64, "accept" => "application/json" }
 
         begin
           rest.put(url, file_contents, headers)
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 8d302ee..9ebf705 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -1,10 +1,10 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/log'
-require 'chef/cookbook/file_vendor'
-require 'chef/cookbook/metadata'
-require 'chef/version_class'
-require 'chef/digester'
-require 'chef/cookbook_manifest'
+require "chef/log"
+require "chef/cookbook/file_vendor"
+require "chef/cookbook/metadata"
+require "chef/version_class"
+require "chef/digester"
+require "chef/cookbook_manifest"
+require "chef/server_api"
 
 class Chef
 
@@ -51,12 +52,12 @@ class Chef
     attr_accessor :metadata_filenames
 
     def status=(new_status)
-      Chef::Log.deprecation("Deprecated method `status' called from #{caller(1).first}. This method will be removed")
+      Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
       @status = new_status
     end
 
     def status
-      Chef::Log.deprecation("Deprecated method `status' called from #{caller(1).first}. This method will be removed")
+      Chef.log_deprecation("Deprecated method `status' called. This method will be removed.")
       @status
     end
 
@@ -299,19 +300,19 @@ class Chef
         if segment == :files || segment == :templates
           error_message = "Cookbook '#{name}' (#{version}) does not contain a file at any of these locations:\n"
           error_locations = if filename.is_a?(Array)
-            filename.map{|name| "  #{File.join(segment.to_s, name)}"}
-          else
-            [
-              "  #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
-              "  #{segment}/#{node[:platform]}/#{filename}",
-              "  #{segment}/default/#{filename}",
-              "  #{segment}/#{filename}",
-            ]
-          end
+                              filename.map { |name| "  #{File.join(segment.to_s, name)}" }
+                            else
+                              [
+                                "  #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}",
+                                "  #{segment}/#{node[:platform]}/#{filename}",
+                                "  #{segment}/default/#{filename}",
+                                "  #{segment}/#{filename}",
+                              ]
+                            end
           error_message << error_locations.join("\n")
           existing_files = segment_filenames(segment)
           # Strip the root_dir prefix off all files for readability
-          existing_files.map!{|path| path[root_dir.length+1..-1]} if root_dir
+          existing_files.map! { |path| path[root_dir.length + 1..-1] } if root_dir
           # Show the files that the cookbook does have. If the user made a typo,
           # hopefully they'll see it here.
           unless existing_files.empty?
@@ -324,12 +325,12 @@ class Chef
       end
     end
 
-    def preferred_filename_on_disk_location(node, segment, filename, current_filepath=nil)
+    def preferred_filename_on_disk_location(node, segment, filename, current_filepath = nil)
       manifest_record = preferred_manifest_record(node, segment, filename)
-      if current_filepath && (manifest_record['checksum'] == self.class.checksum_cookbook_file(current_filepath))
+      if current_filepath && (manifest_record["checksum"] == self.class.checksum_cookbook_file(current_filepath))
         nil
       else
-        file_vendor.get_filename(manifest_record['path'])
+        file_vendor.get_filename(manifest_record["path"])
       end
     end
 
@@ -368,7 +369,6 @@ class Chef
       raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/default/#{dirname}" unless best_pref
 
       filenames_by_pref[best_pref]
-
     end
 
     # Determine the manifest records from the most specific directory
@@ -384,10 +384,10 @@ class Chef
 
         # extract the preference part from the path.
         if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/
-          # Note the specificy_dirname includes the segment and
-          # dirname argument as above, which is what
-          # preferences_for_path returns. It could be
-          # "files/ubuntu-9.10/dirname", for example.
+            # Note the specificy_dirname includes the segment and
+            # dirname argument as above, which is what
+            # preferences_for_path returns. It could be
+            # "files/ubuntu-9.10/dirname", for example.
           specificity_dirname = $1
 
           # Record the specificity_dirname only if it's in the list of
@@ -412,54 +412,60 @@ class Chef
       # only files and templates can be platform-specific
       if segment.to_sym == :files || segment.to_sym == :templates
         relative_search_path = if path.is_a?(Array)
-          path
+                                 path
+                               else
+                                 begin
+                                   platform, version = Chef::Platform.find_platform_and_version(node)
+                                 rescue ArgumentError => e
+                                   # Skip platform/version if they were not found by find_platform_and_version
+                                   if e.message =~ /Cannot find a (?:platform|version)/
+                                     platform = "/unknown_platform/"
+                                     version = "/unknown_platform_version/"
+                                   else
+                                     raise
+                                   end
+                                 end
+
+                                 fqdn = node[:fqdn]
+
+                                 # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
+                                 search_versions = []
+                                 parts = version.to_s.split(".")
+
+                                 parts.size.times do
+                                   search_versions << parts.join(".")
+                                   parts.pop
+                                 end
+
+                                 # Most specific to least specific places to find the path
+                                 search_path = [ File.join("host-#{fqdn}", path) ]
+                                 search_versions.each do |v|
+                                   search_path << File.join("#{platform}-#{v}", path)
+                                 end
+                                 search_path << File.join(platform.to_s, path)
+                                 search_path << File.join("default", path)
+                                 search_path << path
+
+                                 search_path
+                               end
+        relative_search_path.map { |relative_path| File.join(segment.to_s, relative_path) }
+      else
+        if segment.to_sym == :root_files
+          [path]
         else
-          begin
-            platform, version = Chef::Platform.find_platform_and_version(node)
-          rescue ArgumentError => e
-            # Skip platform/version if they were not found by find_platform_and_version
-            if e.message =~ /Cannot find a (?:platform|version)/
-              platform = "/unknown_platform/"
-              version = "/unknown_platform_version/"
-            else
-              raise
-            end
-          end
-
-          fqdn = node[:fqdn]
-
-          # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ]
-          search_versions = []
-          parts = version.to_s.split('.')
-
-          parts.size.times do
-            search_versions << parts.join('.')
-            parts.pop
-          end
-
-          # Most specific to least specific places to find the path
-          search_path = [ File.join("host-#{fqdn}", path) ]
-          search_versions.each do |v|
-            search_path << File.join("#{platform}-#{v}", path)
-          end
-          search_path << File.join(platform.to_s, path)
-          search_path << File.join("default", path)
-          search_path << path
-
-          search_path
+          [File.join(segment, path)]
         end
-        relative_search_path.map {|relative_path| File.join(segment.to_s, relative_path)}
-      else
-        [File.join(segment, path)]
       end
     end
     private :preferences_for_path
 
-    def self.json_create(o)
-      cookbook_version = new(o["cookbook_name"])
+    def self.from_hash(o)
+      cookbook_version = new(o["cookbook_name"] || o["name"])
+
       # We want the Chef::Cookbook::Metadata object to always be inflated
       cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
       cookbook_version.manifest = o
+      cookbook_version.identifier = o["identifier"] if o.key?("identifier")
 
       # We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
       cookbook_version.manifest["metadata"] = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(cookbook_version.metadata))
@@ -468,19 +474,19 @@ class Chef
       cookbook_version
     end
 
+    def self.json_create(o)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::CookbookVersion#from_hash")
+      from_hash(o)
+    end
+
     def self.from_cb_artifact_data(o)
-      cookbook_version = new(o["name"])
-      # We want the Chef::Cookbook::Metadata object to always be inflated
-      cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
-      cookbook_version.manifest = o
-      cookbook_version.identifier = o["identifier"]
-      cookbook_version
+      from_hash(o)
     end
 
     # @deprecated This method was used by the Ruby Chef Server and is no longer
     #   needed. There is no replacement.
     def generate_manifest_with_urls(&url_generator)
-      Chef::Log.deprecation("Deprecated method #generate_manifest_with_urls called from #{caller(1).first}")
+      Chef.log_deprecation("Deprecated method #generate_manifest_with_urls.")
 
       rendered_manifest = manifest.dup
       COOKBOOK_SEGMENTS.each do |segment|
@@ -494,7 +500,6 @@ class Chef
       rendered_manifest
     end
 
-
     def to_hash
       # TODO: this should become deprecated when the API for CookbookManifest becomes stable
       cookbook_manifest.to_hash
@@ -505,7 +510,6 @@ class Chef
       cookbook_manifest.to_json
     end
 
-
     def metadata_json_file
       File.join(root_paths[0], "metadata.json")
     end
@@ -539,22 +543,22 @@ class Chef
     end
 
     def self.chef_server_rest
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def destroy
-      chef_server_rest.delete_rest("cookbooks/#{name}/#{version}")
+      chef_server_rest.delete("cookbooks/#{name}/#{version}")
       self
     end
 
-    def self.load(name, version="_latest")
+    def self.load(name, version = "_latest")
       version = "_latest" if version == "latest"
-      chef_server_rest.get_rest("cookbooks/#{name}/#{version}")
+      from_hash(chef_server_rest.get("cookbooks/#{name}/#{version}"))
     end
 
     # The API returns only a single version of each cookbook in the result from the cookbooks method
     def self.list
-      chef_server_rest.get_rest('cookbooks')
+      chef_server_rest.get("cookbooks")
     end
 
     # Alias latest_cookbooks as list
@@ -563,7 +567,7 @@ class Chef
     end
 
     def self.list_all_versions
-      chef_server_rest.get_rest('cookbooks?num_versions=all')
+      chef_server_rest.get("cookbooks?num_versions=all")
     end
 
     ##
@@ -573,7 +577,7 @@ class Chef
     # [String]::  Array of cookbook versions, which are strings like 'x.y.z'
     # nil::       if the cookbook doesn't exist. an error will also be logged.
     def self.available_versions(cookbook_name)
-      chef_server_rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map do |cb|
+      chef_server_rest.get("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map do |cb|
         cb["version"]
       end
     rescue Net::HTTPServerException => e
@@ -603,13 +607,13 @@ class Chef
       preferences = preferences_for_path(node, segment, filename)
 
       # in order of prefernce, look for the filename in the manifest
-      preferences.find {|preferred_filename| manifest_records_by_path[preferred_filename] }
+      preferences.find { |preferred_filename| manifest_records_by_path[preferred_filename] }
     end
 
     # For each filename, produce a mapping of base filename (i.e. recipe name
     # or attribute file) to on disk location
     def filenames_by_name(filenames)
-      filenames.select{|filename| filename =~ /\.rb$/}.inject({}){|memo, filename| memo[File.basename(filename, '.rb')] = filename ; memo }
+      filenames.select { |filename| filename =~ /\.rb$/ }.inject({}) { |memo, filename| memo[File.basename(filename, ".rb")] = filename ; memo }
     end
 
     def file_vendor
diff --git a/lib/chef/daemon.rb b/lib/chef/daemon.rb
index e5abca2..2424198 100644
--- a/lib/chef/daemon.rb
+++ b/lib/chef/daemon.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 
 # I love you Merb (lib/merb-core/server.rb)
 
-require 'chef/config'
-require 'chef/run_lock'
-require 'etc'
+require "chef/config"
+require "chef/run_lock"
+require "etc"
 
 class Chef
   class Daemon
@@ -61,7 +61,7 @@ class Chef
       # String::
       #   Location of the pid file for @name
       def pid_file
-         Chef::Config[:pid_file] or "/tmp/#{@name}.pid"
+        Chef::Config[:pid_file] or "/tmp/#{@name}.pid"
       end
 
       # Suck the pid out of pid_file
@@ -100,7 +100,7 @@ class Chef
       # ==== Alternatives
       # If group is left out, the user will be used (changing to user:user)
       #
-      def _change_privilege(user, group=user)
+      def _change_privilege(user, group = user)
         uid, gid = Process.euid, Process.egid
 
         begin
diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb
index 8475774..d17dd8d 100644
--- a/lib/chef/data_bag.rb
+++ b/lib/chef/data_bag.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,13 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/data_bag_item'
-require 'chef/mash'
-require 'chef/json_compat'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/data_bag_item"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/server_api"
 
 class Chef
   class DataBag
@@ -43,23 +44,23 @@ class Chef
 
     # Create a new Chef::DataBag
     def initialize(chef_server_rest: nil)
-      @name = ''
+      @name = ""
       @chef_server_rest = chef_server_rest
     end
 
-    def name(arg=nil)
+    def name(arg = nil)
       set_or_return(
         :name,
         arg,
-        :regex => VALID_NAME
+        :regex => VALID_NAME,
       )
     end
 
     def to_hash
       result = {
-        'name'       => @name,
-        'json_class' => self.class.name,
-        'chef_type'  => 'data_bag',
+        "name"       => @name,
+        "json_class" => self.class.name,
+        "chef_type"  => "data_bag",
       }
       result
     end
@@ -70,21 +71,26 @@ class Chef
     end
 
     def chef_server_rest
-      @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def self.chef_server_rest
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     # Create a Chef::Role from JSON
     def self.json_create(o)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::DataBag#from_hash")
+      from_hash(o)
+    end
+
+    def self.from_hash(o)
       bag = new
       bag.name(o["name"])
       bag
     end
 
-    def self.list(inflate=false)
+    def self.list(inflate = false)
       if Chef::Config[:solo]
         paths = Array(Chef::Config[:data_bag_path])
         names = []
@@ -93,9 +99,9 @@ class Chef
             raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
           end
 
-          names += Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path), "*")).map{|f|File.basename(f)}.sort
+          names += Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path), "*")).map { |f| File.basename(f) }.sort
         end
-        names.inject({}) {|h, n| h[n] = n; h}
+        names.inject({}) { |h, n| h[n] = n; h }
       else
         if inflate
           # Can't search for all data bags like other objects, fall back to N+1 :(
@@ -104,7 +110,7 @@ class Chef
             response
           end
         else
-          Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data")
+          Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data")
         end
       end
     end
@@ -120,7 +126,7 @@ class Chef
           end
 
           Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(path, name.to_s), "*.json")).inject({}) do |bag, f|
-            item = Chef::JSONCompat.from_json(IO.read(f))
+            item = Chef::JSONCompat.parse(IO.read(f))
 
             # Check if we have multiple items with similar names (ids) and raise if their content differs
             if data_bag.has_key?(item["id"]) && data_bag[item["id"]] != item
@@ -132,19 +138,19 @@ class Chef
         end
         return data_bag
       else
-        Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
+        Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data/#{name}")
       end
     end
 
     def destroy
-      chef_server_rest.delete_rest("data/#{@name}")
+      chef_server_rest.delete("data/#{@name}")
     end
 
     # Save the Data Bag via RESTful API
     def save
       begin
         if Chef::Config[:why_run]
-          Chef::Log.warn("In whyrun mode, so NOT performing data bag save.")
+          Chef::Log.warn("In why-run mode, so NOT performing data bag save.")
         else
           create
         end
@@ -156,7 +162,7 @@ class Chef
 
     #create a data bag via RESTful API
     def create
-      chef_server_rest.post_rest("data", self)
+      chef_server_rest.post("data", self)
       self
     end
 
diff --git a/lib/chef/data_bag_item.rb b/lib/chef/data_bag_item.rb
index 9f92e26..facaf68 100644
--- a/lib/chef/data_bag_item.rb
+++ b/lib/chef/data_bag_item.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,15 @@
 # limitations under the License.
 #
 
-require 'forwardable'
+require "forwardable"
 
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/data_bag'
-require 'chef/mash'
-require 'chef/json_compat'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/data_bag"
+require "chef/mash"
+require "chef/server_api"
+require "chef/json_compat"
 
 class Chef
   class DataBagItem
@@ -58,11 +59,11 @@ class Chef
     end
 
     def chef_server_rest
-      @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def self.chef_server_rest
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def raw_data
@@ -81,11 +82,11 @@ class Chef
       @raw_data = new_data
     end
 
-    def data_bag(arg=nil)
+    def data_bag(arg = nil)
       set_or_return(
         :data_bag,
         arg,
-        :regex => /^[\-[:alnum:]_]+$/
+        :regex => /^[\-[:alnum:]_]+$/,
       )
     end
 
@@ -94,10 +95,10 @@ class Chef
     end
 
     def object_name
-      raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?('id')
+      raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?("id")
       raise Exceptions::ValidationFailed, "You must have declared what bag this item belongs to!" unless data_bag
 
-      id = raw_data['id']
+      id = raw_data["id"]
       "data_bag_item_#{data_bag}_#{id}"
     end
 
@@ -119,28 +120,30 @@ class Chef
         "json_class" => self.class.name,
         "chef_type"  => "data_bag_item",
         "data_bag"   => data_bag,
-        "raw_data"   => raw_data
+        "raw_data"   => raw_data,
       }
       Chef::JSONCompat.to_json(result, *a)
     end
 
     def self.from_hash(h)
+      h.delete("chef_type")
+      h.delete("json_class")
+      h.delete("name")
+
       item = new
-      item.raw_data = h
+      item.data_bag(h.delete("data_bag")) if h.key?("data_bag")
+      if h.key?("raw_data")
+        item.raw_data = Mash.new(h["raw_data"])
+      else
+        item.raw_data = h
+      end
       item
     end
 
     # Create a Chef::DataBagItem from JSON
     def self.json_create(o)
-      bag_item = new
-      bag_item.data_bag(o["data_bag"])
-      o.delete("data_bag")
-      o.delete("chef_type")
-      o.delete("json_class")
-      o.delete("name")
-
-      bag_item.raw_data = Mash.new(o["raw_data"])
-      bag_item
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::DataBagItem#from_hash")
+      from_hash(o)
     end
 
     # Load a Data Bag Item by name via either the RESTful API or local data_bag_path if run in solo mode
@@ -149,7 +152,7 @@ class Chef
         bag = Chef::DataBag.load(data_bag)
         item = bag[name]
       else
-        item = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{data_bag}/#{name}")
+        item = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("data/#{data_bag}/#{name}")
       end
 
       if item.kind_of?(DataBagItem)
@@ -161,37 +164,37 @@ class Chef
       end
     end
 
-    def destroy(data_bag=data_bag(), databag_item=name)
-      chef_server_rest.delete_rest("data/#{data_bag}/#{databag_item}")
+    def destroy(data_bag = self.data_bag(), databag_item = name)
+      chef_server_rest.delete("data/#{data_bag}/#{databag_item}")
     end
 
     # Save this Data Bag Item via RESTful API
-    def save(item_id=@raw_data['id'])
+    def save(item_id = @raw_data["id"])
       r = chef_server_rest
       begin
         if Chef::Config[:why_run]
-          Chef::Log.warn("In whyrun mode, so NOT performing data bag item save.")
+          Chef::Log.warn("In why-run mode, so NOT performing data bag item save.")
         else
-          r.put_rest("data/#{data_bag}/#{item_id}", self)
+          r.put("data/#{data_bag}/#{item_id}", self)
         end
       rescue Net::HTTPServerException => e
         raise e unless e.response.code == "404"
-        r.post_rest("data/#{data_bag}", self)
+        r.post("data/#{data_bag}", self)
       end
       self
     end
 
     # Create this Data Bag Item via RESTful API
     def create
-      chef_server_rest.post_rest("data/#{data_bag}", self)
+      chef_server_rest.post("data/#{data_bag}", self)
       self
     end
 
     def ==(other)
       other.respond_to?(:to_hash) &&
-      other.respond_to?(:data_bag) &&
-      (other.to_hash == to_hash) &&
-      (other.data_bag.to_s == data_bag.to_s)
+        other.respond_to?(:data_bag) &&
+        (other.to_hash == to_hash) &&
+        (other.data_bag.to_s == data_bag.to_s)
     end
 
     # As a string
@@ -204,11 +207,11 @@ class Chef
     end
 
     def pretty_print(pretty_printer)
-      pretty_printer.pp({"data_bag_item('#{data_bag}', '#{id}')" => self.to_hash})
+      pretty_printer.pp({ "data_bag_item('#{data_bag}', '#{id}')" => self.to_hash })
     end
 
     def id
-      @raw_data['id']
+      @raw_data["id"]
     end
 
   end
diff --git a/lib/chef/delayed_evaluator.rb b/lib/chef/delayed_evaluator.rb
new file mode 100644
index 0000000..25cd3a1
--- /dev/null
+++ b/lib/chef/delayed_evaluator.rb
@@ -0,0 +1,21 @@
+#
+# Author:: John Keiser <jkeiser at chef.io>
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class Chef
+  class DelayedEvaluator < Proc
+  end
+end
diff --git a/lib/chef/deprecation/mixin/template.rb b/lib/chef/deprecation/mixin/template.rb
index 36d18ad..0c90212 100644
--- a/lib/chef/deprecation/mixin/template.rb
+++ b/lib/chef/deprecation/mixin/template.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'erubis'
+require "tempfile"
+require "erubis"
 
 class Chef
   module Deprecation
@@ -25,7 +25,7 @@ class Chef
       # == Deprecation::Provider::Mixin::Template
       # This module contains the deprecated functions of
       # Chef::Mixin::Template. These functions are refactored to different
-      # components. They are frozen and will be removed in Chef 12.
+      # components. They are frozen and will be removed in Chef 13.
       #
 
       module Template
@@ -46,4 +46,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/deprecation/provider/cookbook_file.rb b/lib/chef/deprecation/provider/cookbook_file.rb
index dfbf4a3..d6e8a75 100644
--- a/lib/chef/deprecation/provider/cookbook_file.rb
+++ b/lib/chef/deprecation/provider/cookbook_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
 # limitations under the License.
 #
 
-
 class Chef
   module Deprecation
     module Provider
@@ -24,7 +23,7 @@ class Chef
       # == Deprecation::Provider::CookbookFile
       # This module contains the deprecated functions of
       # Chef::Provider::CookbookFile. These functions are refactored to
-      # different components. They are frozen and will be removed in Chef 12.
+      # different components. They are frozen and will be removed in Chef 13.
       #
       module CookbookFile
 
diff --git a/lib/chef/deprecation/provider/file.rb b/lib/chef/deprecation/provider/file.rb
index 125f31f..4db9101 100644
--- a/lib/chef/deprecation/provider/file.rb
+++ b/lib/chef/deprecation/provider/file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/util/path_helper'
+require "chef/util/path_helper"
 
 class Chef
   module Deprecation
@@ -25,7 +25,7 @@ class Chef
       # == Deprecation::Provider::File
       # This module contains the deprecated functions of
       # Chef::Provider::File. These functions are refactored to different
-      # components. They are frozen and will be removed in Chef 12.
+      # components. They are frozen and will be removed in Chef 13.
       #
       module File
 
@@ -52,14 +52,14 @@ class Chef
           suppress_resource_reporting = false
 
           return [ "(diff output suppressed by config)" ] if Chef::Config[:diff_disabled]
-          return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path)  # should never happen?
+          return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path) # should never happen?
 
           # solaris does not support diff -N, so create tempfile to diff against if we are creating a new file
           target_path = if ::File.exists?(@current_resource.path)
                           @current_resource.path
                         else
-                          suppress_resource_reporting = true  # suppress big diffs going to resource reporting service
-                          tempfile = Tempfile.new('chef-tempfile')
+                          suppress_resource_reporting = true # suppress big diffs going to resource reporting service
+                          tempfile = Tempfile.new("chef-tempfile")
                           tempfile.path
                         end
 
@@ -119,13 +119,13 @@ class Chef
             description << diff_current_from_content(@new_resource.content)
             converge_by(description) do
               backup @new_resource.path if ::File.exists?(@new_resource.path)
-              ::File.open(@new_resource.path, "w") {|f| f.write @new_resource.content }
+              ::File.open(@new_resource.path, "w") { |f| f.write @new_resource.content }
               Chef::Log.info("#{@new_resource} contents updated")
             end
           end
         end
 
-        def update_new_file_state(path=@new_resource.path)
+        def update_new_file_state(path = @new_resource.path)
           if !::File.directory?(path)
             @new_resource.checksum(checksum(path))
           end
@@ -163,7 +163,7 @@ class Chef
           end
         end
 
-        def backup(file=nil)
+        def backup(file = nil)
           file ||= @new_resource.path
           if @new_resource.backup != false && @new_resource.backup > 0 && ::File.exist?(file)
             time = Time.now
@@ -181,7 +181,7 @@ class Chef
 
             # Clean up after the number of backups
             slice_number = @new_resource.backup
-            backup_files = Dir[Chef::Util::PathHelper.escape_glob(prefix, ".#{@new_resource.path}") + ".chef-*"].sort { |a,b| b <=> a }
+            backup_files = Dir[Chef::Util::PathHelper.escape_glob(prefix, ".#{@new_resource.path}") + ".chef-*"].sort { |a, b| b <=> a }
             if backup_files.length >= @new_resource.backup
               remainder = backup_files.slice(slice_number..-1)
               remainder.each do |backup_to_delete|
diff --git a/lib/chef/deprecation/provider/remote_directory.rb b/lib/chef/deprecation/provider/remote_directory.rb
new file mode 100644
index 0000000..4e28fdc
--- /dev/null
+++ b/lib/chef/deprecation/provider/remote_directory.rb
@@ -0,0 +1,52 @@
+#
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module Deprecation
+    module Provider
+      module RemoteDirectory
+
+        def directory_root_in_cookbook_cache
+          Chef.log_deprecation "the Chef::Provider::RemoteDirectory#directory_root_in_cookbook_cache method is deprecated"
+
+          @directory_root_in_cookbook_cache ||=
+            begin
+              cookbook = run_context.cookbook_collection[resource_cookbook]
+              cookbook.preferred_filename_on_disk_location(node, :files, source, path)
+            end
+        end
+
+        # List all excluding . and ..
+        def ls(path)
+          files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), "**", "*"),
+                           ::File::FNM_DOTMATCH)
+
+          # Remove current directory and previous directory
+          files = files.reject do |name|
+            basename = Pathname.new(name).basename().to_s
+            [".", ".."].include?(basename)
+          end
+
+          # Clean all the paths... this is required because of the join
+          files.map { |f| Chef::Util::PathHelper.cleanpath(f) }
+        end
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/deprecation/provider/remote_file.rb b/lib/chef/deprecation/provider/remote_file.rb
index 4452de6..9f115a2 100644
--- a/lib/chef/deprecation/provider/remote_file.rb
+++ b/lib/chef/deprecation/provider/remote_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ class Chef
       # == Deprecation::Provider::RemoteFile
       # This module contains the deprecated functions of
       # Chef::Provider::RemoteFile. These functions are refactored to different
-      # components. They are frozen and will be removed in Chef 12.
+      # components. They are frozen and will be removed in Chef 13.
       #
       module RemoteFile
 
@@ -64,7 +64,7 @@ class Chef
         end
 
         def http_client_opts(source)
-          opts={}
+          opts = {}
           # CHEF-3140
           # 1. If it's already compressed, trying to compress it more will
           # probably be counter-productive.
@@ -83,4 +83,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/deprecation/provider/template.rb b/lib/chef/deprecation/provider/template.rb
index d7a228e..ea5a880 100644
--- a/lib/chef/deprecation/provider/template.rb
+++ b/lib/chef/deprecation/provider/template.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/deprecation/mixin/template'
+require "chef/deprecation/mixin/template"
 
 class Chef
   module Deprecation
@@ -25,7 +25,7 @@ class Chef
       # == Deprecation::Provider::Template
       # This module contains the deprecated functions of
       # Chef::Provider::Template. These functions are refactored to different
-      # components. They are frozen and will be removed in Chef 12.
+      # components. They are frozen and will be removed in Chef 13.
       #
       module Template
 
diff --git a/lib/chef/deprecation/warnings.rb b/lib/chef/deprecation/warnings.rb
index 34f468f..b015669 100644
--- a/lib/chef/deprecation/warnings.rb
+++ b/lib/chef/deprecation/warnings.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,10 +25,9 @@ class Chef
           m = instance_method(name)
           define_method(name) do |*args|
             message = []
-            message << "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 12."
-            message << "Please update your cookbooks accordingly. Accessed from:"
-            caller[0..3].each {|l| message << l}
-            Chef::Log.deprecation message
+            message << "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 13."
+            message << "Please update your cookbooks accordingly."
+            Chef.log_deprecation(message)
             super(*args)
           end
         end
diff --git a/lib/chef/digester.rb b/lib/chef/digester.rb
index 75c4e76..6e4588a 100644
--- a/lib/chef/digester.rb
+++ b/lib/chef/digester.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'openssl'
-require 'singleton'
+require "openssl"
+require "singleton"
 
 class Chef
   class Digester
@@ -38,7 +38,11 @@ class Chef
     end
 
     def generate_checksum(file)
-      checksum_file(file, OpenSSL::Digest::SHA256.new)
+      if file.is_a?(StringIO)
+        checksum_io(file, OpenSSL::Digest::SHA256.new)
+      else
+        checksum_file(file, OpenSSL::Digest::SHA256.new)
+      end
     end
 
     def self.generate_md5_checksum_for_file(*args)
@@ -56,7 +60,7 @@ class Chef
     private
 
     def checksum_file(file, digest)
-      File.open(file, 'rb') { |f| checksum_io(f, digest) }
+      File.open(file, "rb") { |f| checksum_io(f, digest) }
     end
 
     def checksum_io(io, digest)
diff --git a/lib/chef/dsl.rb b/lib/chef/dsl.rb
index 7717d99..1fa0099 100644
--- a/lib/chef/dsl.rb
+++ b/lib/chef/dsl.rb
@@ -1,6 +1,6 @@
-require 'chef/dsl/recipe'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/dsl/include_recipe'
-require 'chef/dsl/include_attribute'
-require 'chef/dsl/registry_helper'
+require "chef/dsl/recipe"
+require "chef/dsl/platform_introspection"
+require "chef/dsl/data_query"
+require "chef/dsl/include_recipe"
+require "chef/dsl/include_attribute"
+require "chef/dsl/registry_helper"
diff --git a/lib/chef/dsl/audit.rb b/lib/chef/dsl/audit.rb
index d1bf09b..98271dc 100644
--- a/lib/chef/dsl/audit.rb
+++ b/lib/chef/dsl/audit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
+require "chef/exceptions"
 
 class Chef
   module DSL
@@ -40,7 +40,7 @@ class Chef
             cookbook_name: cookbook_name,
             cookbook_version: self.run_context.cookbook_collection[cookbook_name].version,
             recipe_name: self.recipe_name,
-            line_number: block.source_location[1]
+            line_number: block.source_location[1],
         }
 
         run_context.audits[name] = Struct.new(:args, :block, :metadata).new(args, block, metadata)
diff --git a/lib/chef/dsl/chef_provisioning.rb b/lib/chef/dsl/chef_provisioning.rb
new file mode 100644
index 0000000..a91d297
--- /dev/null
+++ b/lib/chef/dsl/chef_provisioning.rb
@@ -0,0 +1,57 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module DSL
+    # Lazy activation for the chef-provisioning gem. Specifically, we set up methods for
+    # each resource and DSL method in chef-provisioning which, when invoked, will
+    # require 'chef-provisioning' (which will define the actual method) and then call the
+    # method chef-provisioning defined.
+    module ChefProvisioning
+      %w{
+        add_machine_options
+        current_image_options
+        current_machine_options
+        load_balancer
+        machine_batch
+        machine_execute
+        machine_file
+        machine_image
+        machine
+        with_driver
+        with_image_options
+        with_machine_options
+      }.each do |method_name|
+        eval(<<-EOM, binding, __FILE__, __LINE__ + 1)
+          def #{method_name}(*args, &block)
+            Chef::DSL::ChefProvisioning.load_chef_provisioning
+            self.#{method_name}(*args, &block)
+          end
+        EOM
+      end
+
+      def self.load_chef_provisioning
+        # Remove all chef-provisioning methods; they will be added back in by chef-provisioning
+        public_instance_methods(false).each do |method_name|
+          remove_method(method_name)
+        end
+        require "chef/provisioning"
+      end
+    end
+  end
+end
diff --git a/lib/chef/dsl/cheffish.rb b/lib/chef/dsl/cheffish.rb
new file mode 100644
index 0000000..de052bb
--- /dev/null
+++ b/lib/chef/dsl/cheffish.rb
@@ -0,0 +1,64 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module DSL
+    # Lazy activation for the cheffish gem. Specifically, we set up methods for
+    # each resource and DSL method in cheffish which, when invoked, will
+    # require 'cheffish' (which will define the actual method) and then call the
+    # method cheffish defined.
+    module Cheffish
+      %w{
+        chef_acl
+        chef_client
+        chef_container
+        chef_data_bag
+        chef_environment
+        chef_group
+        chef_mirror
+        chef_node
+        chef_organization
+        chef_role
+        chef_user
+        private_key
+        public_key
+        with_chef_data_bag
+        with_chef_environment
+        with_chef_data_bag_item_encryption
+        with_chef_server
+        with_chef_local_server
+        get_private_key
+      }.each do |method_name|
+        eval(<<-EOM, binding, __FILE__, __LINE__ + 1)
+          def #{method_name}(*args, &block)
+            Chef::DSL::Cheffish.load_cheffish
+            self.#{method_name}(*args, &block)
+          end
+        EOM
+      end
+
+      def self.load_cheffish
+        # Remove all cheffish methods; they will be added back in by cheffish
+        public_instance_methods(false).each do |method_name|
+          remove_method(method_name)
+        end
+        require "cheffish"
+      end
+    end
+  end
+end
diff --git a/lib/chef/dsl/data_query.rb b/lib/chef/dsl/data_query.rb
index e367842..b966885 100644
--- a/lib/chef/dsl/data_query.rb
+++ b/lib/chef/dsl/data_query.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/search/query'
-require 'chef/data_bag'
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "chef/search/query"
+require "chef/data_bag"
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/check_encrypted"
 
 class Chef
   module DSL
@@ -55,7 +55,7 @@ class Chef
         raise
       end
 
-      def data_bag_item(bag, item, secret=nil)
+      def data_bag_item(bag, item, secret = nil)
         DataBag.validate_name!(bag.to_s)
         DataBagItem.validate_id!(item)
 
@@ -73,7 +73,7 @@ class Chef
             raise
           end
         end
-        
+
         item
       rescue Exception
         Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}")
@@ -86,4 +86,4 @@ end
 
 # **DEPRECATED**
 # This used to be part of chef/mixin/language. Load the file to activate the deprecation code.
-require 'chef/mixin/language'
+require "chef/mixin/language"
diff --git a/lib/chef/dsl/declare_resource.rb b/lib/chef/dsl/declare_resource.rb
new file mode 100644
index 0000000..2e7dc93
--- /dev/null
+++ b/lib/chef/dsl/declare_resource.rb
@@ -0,0 +1,108 @@
+#--
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/exceptions"
+
+class Chef
+  module DSL
+    module DeclareResource
+
+      #
+      # Instantiates a resource (via #build_resource), then adds it to the
+      # resource collection. Note that resource classes are looked up directly,
+      # so this will create the resource you intended even if the method name
+      # corresponding to that resource has been overridden.
+      #
+      # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+      # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+      # @param created_at [String] The caller of the resource.  Use `caller[0]`
+      #   to get the caller of your function.  Defaults to the caller of this
+      #   function.
+      # @param resource_attrs_block A block that lets you set attributes of the
+      #   resource (it is instance_eval'd on the resource instance).
+      #
+      # @return [Chef::Resource] The new resource.
+      #
+      # @example
+      #   declare_resource(:file, '/x/y.txy', caller[0]) do
+      #     action :delete
+      #   end
+      #   # Equivalent to
+      #   file '/x/y.txt' do
+      #     action :delete
+      #   end
+      #
+      def declare_resource(type, name, created_at = nil, run_context: self.run_context, create_if_missing: false, &resource_attrs_block)
+        created_at ||= caller[0]
+
+        if create_if_missing
+          begin
+            resource = run_context.resource_collection.find(type => name)
+            return resource
+          rescue Chef::Exceptions::ResourceNotFound
+          end
+        end
+
+        resource = build_resource(type, name, created_at, &resource_attrs_block)
+
+        run_context.resource_collection.insert(resource, resource_type: type, instance_name: name)
+        resource
+      end
+
+      #
+      # Instantiate a resource of the given +type+ with the given +name+ and
+      # attributes as given in the +resource_attrs_block+.
+      #
+      # The resource is NOT added to the resource collection.
+      #
+      # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
+      # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
+      # @param created_at [String] The caller of the resource.  Use `caller[0]`
+      #   to get the caller of your function.  Defaults to the caller of this
+      #   function.
+      # @param resource_attrs_block A block that lets you set attributes of the
+      #   resource (it is instance_eval'd on the resource instance).
+      #
+      # @return [Chef::Resource] The new resource.
+      #
+      # @example
+      #   build_resource(:file, '/x/y.txy', caller[0]) do
+      #     action :delete
+      #   end
+      #
+      def build_resource(type, name, created_at = nil, run_context: self.run_context, &resource_attrs_block)
+        created_at ||= caller[0]
+        Thread.exclusive do
+          require "chef/resource_builder" unless defined?(Chef::ResourceBuilder)
+        end
+
+        Chef::ResourceBuilder.new(
+          type:                type,
+          name:                name,
+          created_at:          created_at,
+          params:              @params,
+          run_context:         run_context,
+          cookbook_name:       cookbook_name,
+          recipe_name:         recipe_name,
+          enclosing_provider:  self.is_a?(Chef::Provider) ? self : nil,
+        ).build(&resource_attrs_block)
+      end
+    end
+  end
+end
diff --git a/lib/chef/dsl/definitions.rb b/lib/chef/dsl/definitions.rb
new file mode 100644
index 0000000..60b1cf6
--- /dev/null
+++ b/lib/chef/dsl/definitions.rb
@@ -0,0 +1,43 @@
+class Chef
+  module DSL
+    #
+    # Module containing a method for each declared definition
+    #
+    # Depends on declare_resource(name, created_at, &block)
+    #
+    # @api private
+    #
+    module Definitions
+      def self.add_definition(dsl_name)
+        module_eval <<-EOM, __FILE__, __LINE__ + 1
+          def #{dsl_name}(*args, &block)
+            evaluate_resource_definition(#{dsl_name.inspect}, *args, &block)
+          end
+        EOM
+      end
+
+      # @api private
+      def has_resource_definition?(name)
+        run_context.definitions.has_key?(name)
+      end
+
+      # Processes the arguments and block as a resource definition.
+      #
+      # @api private
+      def evaluate_resource_definition(definition_name, *args, &block)
+        # This dupes the high level object, but we still need to dup the params
+        new_def = run_context.definitions[definition_name].dup
+
+        new_def.params = new_def.params.dup
+        new_def.node = run_context.node
+        # This sets up the parameter overrides
+        new_def.instance_eval(&block) if block
+
+        new_recipe = Chef::Recipe.new(cookbook_name, recipe_name, run_context)
+        new_recipe.params = new_def.params
+        new_recipe.params[:name] = args[0]
+        new_recipe.instance_eval(&new_def.recipe)
+      end
+    end
+  end
+end
diff --git a/lib/chef/dsl/include_attribute.rb b/lib/chef/dsl/include_attribute.rb
index 3a95ce7..6d27fef 100644
--- a/lib/chef/dsl/include_attribute.rb
+++ b/lib/chef/dsl/include_attribute.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/log'
+require "chef/log"
 
 class Chef
   module DSL
@@ -58,6 +58,4 @@ end
 
 # **DEPRECATED**
 # This used to be part of chef/mixin/language_include_attribute. Load the file to activate the deprecation code.
-require 'chef/mixin/language_include_attribute'
-
-
+require "chef/mixin/language_include_attribute"
diff --git a/lib/chef/dsl/include_recipe.rb b/lib/chef/dsl/include_recipe.rb
index 5ea1075..9abd7d1 100644
--- a/lib/chef/dsl/include_recipe.rb
+++ b/lib/chef/dsl/include_recipe.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/log'
+require "chef/log"
 
 class Chef
   module DSL
@@ -41,4 +41,4 @@ end
 
 # **DEPRECATED**
 # This used to be part of chef/mixin/language_include_recipe. Load the file to activate the deprecation code.
-require 'chef/mixin/language_include_recipe'
+require "chef/mixin/language_include_recipe"
diff --git a/lib/chef/dsl/platform_introspection.rb b/lib/chef/dsl/platform_introspection.rb
index 2a52010..276a03a 100644
--- a/lib/chef/dsl/platform_introspection.rb
+++ b/lib/chef/dsl/platform_introspection.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,12 +45,12 @@ class Chef
         #   :default => default_value
         def initialize(platform_hash)
           @values = {}
-          platform_hash.each { |platforms, value| set(platforms, value)}
+          platform_hash.each { |platforms, value| set(platforms, value) }
         end
 
         def value_for_node(node)
           platform, version = node[:platform].to_s, node[:platform_version].to_s
-          # Check if we match a version constraint via Chef::VersionConstraint and Chef::Version::Platform
+          # Check if we match a version constraint via Chef::VersionConstraint::Platform and Chef::Version::Platform
           matched_value = match_versions(node)
           if @values.key?(platform) && @values[platform].key?(version)
             @values[platform][version]
@@ -76,11 +76,11 @@ class Chef
             keys = @values[platform].keys
             keys.each do |k|
               begin
-                if Chef::VersionConstraint.new(k).include?(node_version)
+                if Chef::VersionConstraint::Platform.new(k).include?(node_version)
                   key_matches << k
                 end
               rescue Chef::Exceptions::InvalidVersionConstraint => e
-                Chef::Log.debug "Caught InvalidVersionConstraint. This means that a key in value_for_platform cannot be interpreted as a Chef::VersionConstraint."
+                Chef::Log.debug "Caught InvalidVersionConstraint. This means that a key in value_for_platform cannot be interpreted as a Chef::VersionConstraint::Platform."
                 Chef::Log.debug(e)
               end
             end
@@ -106,11 +106,11 @@ class Chef
         end
 
         def set(platforms, value)
-          if platforms.to_s == 'default'
+          if platforms.to_s == "default"
             @values["default"] = value
           else
             assert_valid_platform_values!(platforms, value)
-            Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)}
+            Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value) }
             value
           end
         end
@@ -134,8 +134,6 @@ class Chef
         end
       end
 
-
-
       # Given a hash similar to the one we use for Platforms, select a value from the hash.  Supports
       # per platform defaults, along with a single base default. Arrays may be passed as hash keys and
       # will be expanded.
@@ -168,8 +166,6 @@ class Chef
         has_platform
       end
 
-
-
      # Implementation class for determining platform family dependent values
       class PlatformFamilyDependentValue
 
@@ -193,7 +189,7 @@ class Chef
         def initialize(platform_family_hash)
           @values = {}
           @values["default"] = nil
-          platform_family_hash.each { |platform_families, value| set(platform_families, value)}
+          platform_family_hash.each { |platform_families, value| set(platform_families, value) }
         end
 
         def value_for_node(node)
@@ -212,7 +208,7 @@ class Chef
         private
 
         def set(platform_family, value)
-          if platform_family.to_s == 'default'
+          if platform_family.to_s == "default"
             @values["default"] = value
           else
             Array(platform_family).each { |family| @values[family.to_s] = value }
@@ -221,7 +217,6 @@ class Chef
         end
       end
 
-
       # Given a hash mapping platform families to values, select a value from the hash. Supports a single
       # base default if platform family is not in the map. Arrays may be passed as hash keys and will be
       # expanded
@@ -256,5 +251,4 @@ end
 
 # **DEPRECATED**
 # This used to be part of chef/mixin/language. Load the file to activate the deprecation code.
-require 'chef/mixin/language'
-
+require "chef/mixin/language"
diff --git a/lib/chef/dsl/powershell.rb b/lib/chef/dsl/powershell.rb
index a17971c..1a900af 100644
--- a/lib/chef/dsl/powershell.rb
+++ b/lib/chef/dsl/powershell.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/util/powershell/ps_credential'
+require "chef/util/powershell/ps_credential"
 
 class Chef
   module DSL
     module Powershell
-      def ps_credential(username='placeholder', password)
+      def ps_credential(username = "placeholder", password)
         Chef::Util::Powershell::PSCredential.new(username, password)
       end
     end
diff --git a/lib/chef/dsl/reboot_pending.rb b/lib/chef/dsl/reboot_pending.rb
index 7af67e9..e8982d2 100644
--- a/lib/chef/dsl/reboot_pending.rb
+++ b/lib/chef/dsl/reboot_pending.rb
@@ -1,6 +1,6 @@
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Author:: Seth Chisamore <schisamo at opscode.com>
-# Copyright:: Copyright (c) 2011,2014, Chef Software, Inc.
+# Author:: Seth Chisamore <schisamo at chef.io>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/registry_helper'
+require "chef/dsl/platform_introspection"
+require "chef/dsl/registry_helper"
 
 class Chef
   module DSL
@@ -29,7 +29,6 @@ class Chef
       # Returns true if the system needs a reboot or is expected to reboot
       # Note that we will silently miss any other platform-specific reboot notices besides Windows+Ubuntu.
       def reboot_pending?
-
         # don't break when used as a mixin in contexts without #node (e.g. specs).
         if self.respond_to?(:node, true) && node.run_context.reboot_requested?
           true
@@ -38,23 +37,24 @@ class Chef
           # due to a file being in use (usually a temporary file and a system file)
           # \??\c:\temp\test.sys!\??\c:\winnt\system32\test.sys
           # http://technet.microsoft.com/en-us/library/cc960241.aspx
-          registry_value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }) ||
+          registry_value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => "PendingFileRenameOperations" }) ||
 
           # RebootRequired key contains Update IDs with a value of 1 if they require a reboot.
           # The existence of RebootRequired alone is sufficient on my Windows 8.1 workstation in Windows Update
-          registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') ||
+            registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired') ||
 
           # Vista + Server 2008 and newer may have reboots pending from CBS
-          registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired') ||
+            registry_key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending') ||
 
           # The mere existence of the UpdateExeVolatile key should indicate a pending restart for certain updates
           # http://support.microsoft.com/kb/832475
-          (registry_key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile') &&
-                !registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0].nil? &&
-                [1,2,3].include?(registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0][:data]))
+            Chef::Platform.windows_server_2003? &&
+              (registry_key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile') &&
+              !registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0].nil? &&
+              [1, 2, 3].include?(registry_get_values('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').select { |v| v[:name] == "Flags" }[0][:data]))
         elsif platform?("ubuntu")
           # This should work for Debian as well if update-notifier-common happens to be installed. We need an API for that.
-          File.exists?('/var/run/reboot-required')
+          File.exists?("/var/run/reboot-required")
         else
           false
         end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index c22f053..6d254df 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, 2009-2015 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,12 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/convert_to_class_name'
-require 'chef/exceptions'
-require 'chef/resource_builder'
-require 'chef/mixin/shell_out'
+require "chef/exceptions"
+require "chef/mixin/shell_out"
+require "chef/mixin/powershell_out"
+require "chef/dsl/resources"
+require "chef/dsl/definitions"
+require "chef/dsl/declare_resource"
 
 class Chef
   module DSL
@@ -31,118 +33,11 @@ class Chef
     module Recipe
 
       include Chef::Mixin::ShellOut
-      include Chef::Mixin::ConvertToClassName
+      include Chef::Mixin::PowershellOut
 
-      def method_missing(method_symbol, *args, &block)
-        # If we have a definition that matches, we want to use that instead.  This should
-        # let you do some really crazy over-riding of "native" types, if you really want
-        # to.
-        if has_resource_definition?(method_symbol)
-          evaluate_resource_definition(method_symbol, *args, &block)
-        elsif have_resource_class_for?(method_symbol)
-          # Otherwise, we're rocking the regular resource call route.
-          declare_resource(method_symbol, args[0], caller[0], &block)
-        else
-          begin
-            super
-          rescue NoMethodError
-            raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
-          rescue NameError
-            raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
-          end
-        end
-      end
-
-      def has_resource_definition?(name)
-        run_context.definitions.has_key?(name)
-      end
-
-      # Processes the arguments and block as a resource definition.
-      def evaluate_resource_definition(definition_name, *args, &block)
-
-        # This dupes the high level object, but we still need to dup the params
-        new_def = run_context.definitions[definition_name].dup
-
-        new_def.params = new_def.params.dup
-        new_def.node = run_context.node
-        # This sets up the parameter overrides
-        new_def.instance_eval(&block) if block
-
-        new_recipe = Chef::Recipe.new(cookbook_name, recipe_name, run_context)
-        new_recipe.params = new_def.params
-        new_recipe.params[:name] = args[0]
-        new_recipe.instance_eval(&new_def.recipe)
-      end
-
-      #
-      # Instantiates a resource (via #build_resource), then adds it to the
-      # resource collection. Note that resource classes are looked up directly,
-      # so this will create the resource you intended even if the method name
-      # corresponding to that resource has been overridden.
-      #
-      # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
-      # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
-      # @param created_at [String] The caller of the resource.  Use `caller[0]`
-      #   to get the caller of your function.  Defaults to the caller of this
-      #   function.
-      # @param resource_attrs_block A block that lets you set attributes of the
-      #   resource (it is instance_eval'd on the resource instance).
-      #
-      # @return [Chef::Resource] The new resource.
-      #
-      # @example
-      #   declare_resource(:file, '/x/y.txy', caller[0]) do
-      #     action :delete
-      #   end
-      #   # Equivalent to
-      #   file '/x/y.txt' do
-      #     action :delete
-      #   end
-      #
-      def declare_resource(type, name, created_at=nil, &resource_attrs_block)
-        created_at ||= caller[0]
-
-        resource = build_resource(type, name, created_at, &resource_attrs_block)
-
-        run_context.resource_collection.insert(resource, resource_type: type, instance_name: name)
-        resource
-      end
-
-      #
-      # Instantiate a resource of the given +type+ with the given +name+ and
-      # attributes as given in the +resource_attrs_block+.
-      #
-      # The resource is NOT added to the resource collection.
-      #
-      # @param type [Symbol] The type of resource (e.g. `:file` or `:package`)
-      # @param name [String] The name of the resource (e.g. '/x/y.txt' or 'apache2')
-      # @param created_at [String] The caller of the resource.  Use `caller[0]`
-      #   to get the caller of your function.  Defaults to the caller of this
-      #   function.
-      # @param resource_attrs_block A block that lets you set attributes of the
-      #   resource (it is instance_eval'd on the resource instance).
-      #
-      # @return [Chef::Resource] The new resource.
-      #
-      # @example
-      #   build_resource(:file, '/x/y.txy', caller[0]) do
-      #     action :delete
-      #   end
-      #
-      def build_resource(type, name, created_at=nil, &resource_attrs_block)
-        created_at ||= caller[0]
-
-        Chef::ResourceBuilder.new(
-          type:                type,
-          name:                name,
-          created_at:          created_at,
-          params:              @params,
-          run_context:         run_context,
-          cookbook_name:       cookbook_name,
-          recipe_name:         recipe_name,
-          enclosing_provider:  self.is_a?(Chef::Provider) ? self :  nil
-        ).build(&resource_attrs_block)
-      end
+      include Chef::DSL::Resources
+      include Chef::DSL::Definitions
+      include Chef::DSL::DeclareResource
 
       def resource_class_for(snake_case_name)
         Chef::Resource.resource_for_node(snake_case_name, run_context.node)
@@ -156,9 +51,9 @@ class Chef
 
       def describe_self_for_error
         if respond_to?(:name)
-          %Q[`#{self.class.name} "#{name}"']
+          %Q{`#{self.class} "#{name}"'}
         elsif respond_to?(:recipe_name)
-          %Q[`#{self.class.name} "#{recipe_name}"']
+          %Q{`#{self.class} "#{recipe_name}"'}
         else
           to_s
         end
@@ -168,14 +63,72 @@ class Chef
         raise Chef::Exceptions::ResourceNotFound, "exec was called, but you probably meant to use an execute resource.  If not, please call Kernel#exec explicitly.  The exec block called was \"#{args}\""
       end
 
+      # DEPRECATED:
+      # method_missing must live for backcompat purposes until Chef 13.
+      def method_missing(method_symbol, *args, &block)
+        #
+        # If there is already DSL for this, someone must have called
+        # method_missing manually. Not a fan. Not. A. Fan.
+        #
+        if respond_to?(method_symbol)
+          Chef.log_deprecation("Calling method_missing(#{method_symbol.inspect}) directly is deprecated in Chef 12 and will be removed in Chef 13. Use public_send() or send() instead.")
+          return send(method_symbol, *args, &block)
+        end
+
+        #
+        # If a definition exists, then Chef::DSL::Definitions.add_definition was
+        # never called.  DEPRECATED.
+        #
+        if run_context.definitions.has_key?(method_symbol.to_sym)
+          Chef.log_deprecation("Definition #{method_symbol} (#{run_context.definitions[method_symbol.to_sym]}) was added to the run_context without calling Chef::DSL::Definitions.add_definition(#{method_symbol.to_sym.inspect}).  This will become required in Chef 13.")
+          Chef::DSL::Definitions.add_definition(method_symbol)
+          return send(method_symbol, *args, &block)
+        end
+
+        #
+        # See if the resource exists anyway.  If the user had set
+        # Chef::Resource::Blah = <resource>, a deprecation warning will be
+        # emitted and the DSL method 'blah' will be added to the DSL.
+        #
+        resource_class = Chef::ResourceResolver.resolve(method_symbol, node: run_context ? run_context.node : nil)
+        if resource_class
+          Chef::DSL::Resources.add_resource_dsl(method_symbol)
+          return send(method_symbol, *args, &block)
+        end
+
+        begin
+          super
+        rescue NoMethodError
+          raise NoMethodError, "No resource or method named `#{method_symbol}' for #{describe_self_for_error}"
+        rescue NameError
+          raise NameError, "No resource, method, or local variable named `#{method_symbol}' for #{describe_self_for_error}"
+        end
+      end
+
+      module FullDSL
+        require "chef/dsl/data_query"
+        require "chef/dsl/platform_introspection"
+        require "chef/dsl/include_recipe"
+        require "chef/dsl/registry_helper"
+        require "chef/dsl/reboot_pending"
+        require "chef/dsl/audit"
+        require "chef/dsl/powershell"
+        include Chef::DSL::DataQuery
+        include Chef::DSL::PlatformIntrospection
+        include Chef::DSL::IncludeRecipe
+        include Chef::DSL::Recipe
+        include Chef::DSL::RegistryHelper
+        include Chef::DSL::RebootPending
+        include Chef::DSL::Audit
+        include Chef::DSL::Powershell
+      end
     end
   end
 end
 
-# We require this at the BOTTOM of this file to avoid circular requires (it is used
-# at runtime but not load time)
-require 'chef/resource'
+# Avoid circular references for things that are only used in instance methods
+require "chef/resource"
 
 # **DEPRECATED**
 # This used to be part of chef/mixin/recipe_definition_dsl_core. Load the file to activate the deprecation code.
-require 'chef/mixin/recipe_definition_dsl_core'
+require "chef/mixin/recipe_definition_dsl_core"
diff --git a/lib/chef/dsl/registry_helper.rb b/lib/chef/dsl/registry_helper.rb
index 4dcd2f1..63da635 100644
--- a/lib/chef/dsl/registry_helper.rb
+++ b/lib/chef/dsl/registry_helper.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,22 +33,27 @@ class Chef
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.key_exists?(key_path)
       end
+
       def registry_get_values(key_path, architecture = :machine)
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.get_values(key_path)
       end
+
       def registry_has_subkeys?(key_path, architecture = :machine)
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.has_subkeys?(key_path)
       end
+
       def registry_get_subkeys(key_path, architecture = :machine)
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.get_subkeys(key_path)
       end
+
       def registry_value_exists?(key_path, value, architecture = :machine)
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.value_exists?(key_path, value)
       end
+
       def registry_data_exists?(key_path, value, architecture = :machine)
         registry = Chef::Win32::Registry.new(run_context, architecture)
         registry.data_exists?(key_path, value)
@@ -56,4 +61,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/dsl/resources.rb b/lib/chef/dsl/resources.rb
new file mode 100644
index 0000000..7bbfeb2
--- /dev/null
+++ b/lib/chef/dsl/resources.rb
@@ -0,0 +1,58 @@
+#
+# Author:: John Keiser <jkeiser at chef.io>
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/dsl/cheffish"
+require "chef/dsl/chef_provisioning"
+
+class Chef
+  module DSL
+    #
+    # Module containing a method for each globally declared Resource
+    #
+    # Depends on declare_resource(name, created_at, &block)
+    #
+    # @api private
+    module Resources
+      # Include the lazy loaders for cheffish and chef-provisioning, so that the
+      # resource DSL is there but the gems aren't activated yet.
+      include Chef::DSL::Cheffish
+      include Chef::DSL::ChefProvisioning
+
+      def self.add_resource_dsl(dsl_name)
+        begin
+          module_eval(<<-EOM, __FILE__, __LINE__ + 1)
+            def #{dsl_name}(*args, &block)
+              Chef.log_deprecation("Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (\#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: \#{args}") if args.size > 1
+              declare_resource(#{dsl_name.inspect}, args[0], caller[0], &block)
+            end
+          EOM
+        rescue SyntaxError
+          # Handle the case where dsl_name has spaces, etc.
+          define_method(dsl_name.to_sym) do |*args, &block|
+            Chef.log_deprecation("Cannot create resource #{dsl_name} with more than one argument. All arguments except the name (#{args[0].inspect}) will be ignored. This will cause an error in Chef 13. Arguments: #{args}") if args.size > 1
+            declare_resource(dsl_name, args[0], caller[0], &block)
+          end
+        end
+      end
+
+      def self.remove_resource_dsl(dsl_name)
+        remove_method(dsl_name)
+      rescue NameError
+      end
+    end
+  end
+end
diff --git a/lib/chef/encrypted_data_bag_item.rb b/lib/chef/encrypted_data_bag_item.rb
index 120eb2a..e696199 100644
--- a/lib/chef/encrypted_data_bag_item.rb
+++ b/lib/chef/encrypted_data_bag_item.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item/decryptor'
-require 'chef/encrypted_data_bag_item/encryptor'
-require 'open-uri'
+require "chef/config"
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item/decryptor"
+require "chef/encrypted_data_bag_item/encryptor"
+require "open-uri"
 
 # An EncryptedDataBagItem represents a read-only data bag item where
 # all values, except for the value associated with the id key, have
@@ -47,8 +47,8 @@ require 'open-uri'
 # such nodes in the infrastructure.
 #
 class Chef::EncryptedDataBagItem
-  ALGORITHM = 'aes-256-cbc'
-  AEAD_ALGORITHM = 'aes-256-gcm'
+  ALGORITHM = "aes-256-cbc"
+  AEAD_ALGORITHM = "aes-256-gcm"
 
   #
   # === Synopsis
@@ -125,7 +125,7 @@ class Chef::EncryptedDataBagItem
     self.new(raw_hash, secret)
   end
 
-  def self.load_secret(path=nil)
+  def self.load_secret(path = nil)
     path ||= Chef::Config[:encrypted_data_bag_secret]
     if !path
       raise ArgumentError, "No secret specified and no secret found at #{Chef::Config.platform_specific_path('/etc/chef/encrypted_data_bag_secret')}"
diff --git a/lib/chef/encrypted_data_bag_item/assertions.rb b/lib/chef/encrypted_data_bag_item/assertions.rb
index ab93f46..8162a9a 100644
--- a/lib/chef/encrypted_data_bag_item/assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/assertions.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/unsupported_cipher'
+require "chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/unsupported_cipher"
 
 class Chef::EncryptedDataBagItem
 
@@ -30,7 +30,7 @@ class Chef::EncryptedDataBagItem
       unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
         raise UnacceptableEncryptedDataBagItemFormat,
           "The encrypted data bag item has format version `#{format_version}', " +
-          "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
+            "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
       end
     end
 
diff --git a/lib/chef/encrypted_data_bag_item/check_encrypted.rb b/lib/chef/encrypted_data_bag_item/check_encrypted.rb
index b7cb584..cc37819 100644
--- a/lib/chef/encrypted_data_bag_item/check_encrypted.rb
+++ b/lib/chef/encrypted_data_bag_item/check_encrypted.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2010-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/encrypted_data_bag_item/encryptor'
+require "chef/encrypted_data_bag_item/encryptor"
 
 class Chef::EncryptedDataBagItem
   # Common code for checking if a data bag appears encrypted
diff --git a/lib/chef/encrypted_data_bag_item/decryption_failure.rb b/lib/chef/encrypted_data_bag_item/decryption_failure.rb
index 47d263f..9d2d998 100644
--- a/lib/chef/encrypted_data_bag_item/decryption_failure.rb
+++ b/lib/chef/encrypted_data_bag_item/decryption_failure.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/decryptor.rb b/lib/chef/encrypted_data_bag_item/decryptor.rb
index 86b99cc..a002a98 100644
--- a/lib/chef/encrypted_data_bag_item/decryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/decryptor.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'yaml'
-require 'chef/json_compat'
-require 'openssl'
-require 'base64'
-require 'digest/sha2'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/decryption_failure'
-require 'chef/encrypted_data_bag_item/assertions'
+require "yaml"
+require "chef/json_compat"
+require "openssl"
+require "base64"
+require "digest/sha2"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/decryption_failure"
+require "chef/encrypted_data_bag_item/assertions"
 
 class Chef::EncryptedDataBagItem
 
@@ -92,7 +92,8 @@ class Chef::EncryptedDataBagItem
           plaintext = openssl_decryptor.update(encrypted_bytes)
           plaintext << openssl_decryptor.final
         rescue OpenSSL::Cipher::CipherError => e
-          raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect"
+          # if the key length is less than 150 characters, and it contains slashes, we think it may be a path.
+          raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect. #{ @key.length < 255 and @key.include?('/') ? 'You may need to use --secret-file rather than --secret.' : '' }"
         end
       end
 
@@ -142,7 +143,8 @@ class Chef::EncryptedDataBagItem
           plaintext = openssl_decryptor.update(encrypted_bytes)
           plaintext << openssl_decryptor.final
         rescue OpenSSL::Cipher::CipherError => e
-          raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect"
+          # if the key length is less than 150 characters, and it contains slashes, we think it may be a path.
+          raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect. #{ @key.length < 255 and @key.include?('/') ? 'You may need to use --secret-file rather than --secret.' : '' }"
         end
       end
 
@@ -214,7 +216,7 @@ class Chef::EncryptedDataBagItem
         @openssl_decryptor ||= begin
           d = super
           d.auth_tag = auth_tag
-          d.auth_data = ''
+          d.auth_data = ""
           d
         end
       end
diff --git a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
index 9a54396..e45c342 100644
--- a/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
+++ b/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/encryption_failure.rb b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
index 380e9bc..142d898 100644
--- a/lib/chef/encrypted_data_bag_item/encryption_failure.rb
+++ b/lib/chef/encrypted_data_bag_item/encryption_failure.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/encryptor.rb b/lib/chef/encrypted_data_bag_item/encryptor.rb
index 034413c..8d34033 100644
--- a/lib/chef/encrypted_data_bag_item/encryptor.rb
+++ b/lib/chef/encrypted_data_bag_item/encryptor.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'base64'
-require 'digest/sha2'
-require 'openssl'
-require 'ffi_yajl'
-require 'chef/encrypted_data_bag_item'
-require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
-require 'chef/encrypted_data_bag_item/encryption_failure'
-require 'chef/encrypted_data_bag_item/assertions'
+require "base64"
+require "digest/sha2"
+require "openssl"
+require "ffi_yajl"
+require "chef/encrypted_data_bag_item"
+require "chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format"
+require "chef/encrypted_data_bag_item/encryption_failure"
+require "chef/encrypted_data_bag_item/assertions"
 
 class Chef::EncryptedDataBagItem
 
@@ -35,7 +35,7 @@ class Chef::EncryptedDataBagItem
     # for the desired encrypted data bag format version.
     #
     # +Chef::Config[:data_bag_encrypt_version]+ determines which version is used.
-    def self.new(value, secret, iv=nil)
+    def self.new(value, secret, iv = nil)
       format_version = Chef::Config[:data_bag_encrypt_version]
       case format_version
       when 1
@@ -65,7 +65,7 @@ class Chef::EncryptedDataBagItem
       # * iv: The optional +iv+ parameter is intended for testing use only. When
       # *not* supplied, Encryptor will use OpenSSL to generate a secure random
       # IV, which is what you want.
-      def initialize(plaintext_data, key, iv=nil)
+      def initialize(plaintext_data, key, iv = nil)
         @plaintext_data = plaintext_data
         @key = key
         @iv = iv && Base64.decode64(iv)
@@ -83,7 +83,7 @@ class Chef::EncryptedDataBagItem
           "encrypted_data" => encrypted_data,
           "iv" => Base64.encode64(iv),
           "version" => 1,
-          "cipher" => algorithm
+          "cipher" => algorithm,
         }
       end
 
@@ -127,7 +127,7 @@ class Chef::EncryptedDataBagItem
       end
 
       def self.encryptor_keys
-        %w( encrypted_data iv version cipher )
+        %w{ encrypted_data iv version cipher }
       end
     end
 
@@ -141,7 +141,7 @@ class Chef::EncryptedDataBagItem
           "hmac" => hmac,
           "iv" => Base64.encode64(iv),
           "version" => 2,
-          "cipher" => algorithm
+          "cipher" => algorithm,
         }
       end
 
@@ -155,14 +155,14 @@ class Chef::EncryptedDataBagItem
       end
 
       def self.encryptor_keys
-        super + %w( hmac )
+        super + %w{ hmac }
       end
     end
 
     class Version3Encryptor < Version1Encryptor
       include Chef::EncryptedDataBagItem::Assertions
 
-      def initialize(plaintext_data, key, iv=nil)
+      def initialize(plaintext_data, key, iv = nil)
         super
         assert_aead_requirements_met!(algorithm)
         @auth_tag = nil
@@ -176,7 +176,7 @@ class Chef::EncryptedDataBagItem
           "iv" => Base64.encode64(iv),
           "auth_tag" => Base64.encode64(auth_tag),
           "version" => 3,
-          "cipher" => algorithm
+          "cipher" => algorithm,
         }
       end
 
@@ -201,7 +201,7 @@ class Chef::EncryptedDataBagItem
       def openssl_encryptor
         @openssl_encryptor ||= begin
           encryptor = super
-          encryptor.auth_data = ''
+          encryptor.auth_data = ""
           encryptor
         end
       end
@@ -216,7 +216,7 @@ class Chef::EncryptedDataBagItem
       end
 
       def self.encryptor_keys
-        super + %w( auth_tag )
+        super + %w{ auth_tag }
       end
 
     end
diff --git a/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb b/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
index 2f3b07c..362954b 100644
--- a/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
+++ b/lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb b/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
index 1df5cd5..6f1221b 100644
--- a/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
+++ b/lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb b/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
index e7cf087..ea46463 100644
--- a/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
+++ b/lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/environment.rb b/lib/chef/environment.rb
index 7d4b410..aa6d756 100644
--- a/lib/chef/environment.rb
+++ b/lib/chef/environment.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
 # Author:: John Keiser (<jkeiser at ospcode.com>)
 # Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,12 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/mash'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/version_constraint'
+require "chef/config"
+require "chef/mash"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/version_constraint"
+require "chef/server_api"
 
 class Chef
   class Environment
@@ -38,8 +39,8 @@ class Chef
     COMBINED_COOKBOOK_CONSTRAINT = /(.+)(?:[\s]+)((?:#{Chef::VersionConstraint::OPS.join('|')})(?:[\s]+).+)$/.freeze
 
     def initialize(chef_server_rest: nil)
-      @name = ''
-      @description = ''
+      @name = ""
+      @description = ""
       @default_attributes = Mash.new
       @override_attributes = Mash.new
       @cookbook_versions = Hash.new
@@ -47,14 +48,14 @@ class Chef
     end
 
     def chef_server_rest
-      @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def self.chef_server_rest
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
-    def name(arg=nil)
+    def name(arg = nil)
       set_or_return(
         :name,
         arg,
@@ -62,19 +63,19 @@ class Chef
       )
     end
 
-    def description(arg=nil)
+    def description(arg = nil)
       set_or_return(
         :description,
         arg,
-        :kind_of => String
+        :kind_of => String,
       )
     end
 
-    def default_attributes(arg=nil)
+    def default_attributes(arg = nil)
       set_or_return(
         :default_attributes,
         arg,
-        :kind_of => Hash
+        :kind_of => Hash,
       )
     end
 
@@ -82,11 +83,11 @@ class Chef
       default_attributes(attrs)
     end
 
-    def override_attributes(arg=nil)
+    def override_attributes(arg = nil)
       set_or_return(
         :override_attributes,
         arg,
-        :kind_of => Hash
+        :kind_of => Hash,
       )
     end
 
@@ -94,7 +95,7 @@ class Chef
       override_attributes(attrs)
     end
 
-    def cookbook_versions(arg=nil)
+    def cookbook_versions(arg = nil)
       set_or_return(
         :cookbook_versions,
         arg,
@@ -102,19 +103,19 @@ class Chef
           :kind_of => Hash,
           :callbacks => {
             "should be a valid set of cookbook version requirements" => lambda { |cv| Chef::Environment.validate_cookbook_versions(cv) }
-          }
-        }
+          },
+        },
       )
     end
 
     def cookbook(cookbook, version)
       validate({
         :version => version
-      },{
+      }, {
         :version => {
           :callbacks => { "should be a valid version requirement" => lambda { |v| Chef::Environment.validate_cookbook_version(v) } }
         }
-      })
+      },)
       @cookbook_versions[cookbook] = version
     end
 
@@ -126,7 +127,7 @@ class Chef
         "json_class" => self.class.name,
         "chef_type" => "environment",
         "default_attributes" => @default_attributes,
-        "override_attributes" => @override_attributes
+        "override_attributes" => @override_attributes,
       }
       result
     end
@@ -216,6 +217,11 @@ class Chef
     end
 
     def self.json_create(o)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Environment#from_hash")
+      from_hash(o)
+    end
+
+    def self.from_hash(o)
       environment = new
       environment.name(o["name"])
       environment.description(o["description"])
@@ -225,7 +231,7 @@ class Chef
       environment
     end
 
-    def self.list(inflate=false)
+    def self.list(inflate = false)
       if inflate
         response = Hash.new
         Chef::Search::Query.new.search(:environment) do |e|
@@ -233,7 +239,7 @@ class Chef
         end
         response
       else
-        chef_server_rest.get_rest("environments")
+        chef_server_rest.get("environments")
       end
     end
 
@@ -241,7 +247,7 @@ class Chef
       if Chef::Config[:solo]
         load_from_file(name)
       else
-        chef_server_rest.get_rest("environments/#{name}")
+        self.from_hash(chef_server_rest.get("environments/#{name}"))
       end
     end
 
@@ -255,7 +261,8 @@ class Chef
 
       if File.exists?(js_file)
         # from_json returns object.class => json_class in the JSON.
-        Chef::JSONCompat.from_json(IO.read(js_file))
+        hash = Chef::JSONCompat.parse(IO.read(js_file))
+        from_hash(hash)
       elsif File.exists?(rb_file)
         environment = Chef::Environment.new
         environment.name(name)
@@ -267,26 +274,26 @@ class Chef
     end
 
     def destroy
-      chef_server_rest.delete_rest("environments/#{@name}")
+      chef_server_rest.delete("environments/#{@name}")
     end
 
     def save
       begin
-        chef_server_rest.put_rest("environments/#{@name}", self)
+        chef_server_rest.put("environments/#{@name}", self)
       rescue Net::HTTPServerException => e
         raise e unless e.response.code == "404"
-        chef_server_rest.post_rest("environments", self)
+        chef_server_rest.post("environments", self)
       end
       self
     end
 
     def create
-      chef_server_rest.post_rest("environments", self)
+      chef_server_rest.post("environments", self)
       self
     end
 
     def self.load_filtered_recipe_list(environment)
-      chef_server_rest.get_rest("environments/#{environment}/recipes")
+      chef_server_rest.get("environments/#{environment}/recipes")
     end
 
     def to_s
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb
index 7274105..a6a1871 100644
--- a/lib/chef/event_dispatch/base.rb
+++ b/lib/chef/event_dispatch/base.rb
@@ -47,14 +47,19 @@ class Chef
       def ohai_completed(node)
       end
 
-      # Already have a client key, assuming this node has registered.
+      # Announce that we're not going to register the client. Generally because
+      # we already have the private key, or because we're deliberately not using
+      # a key.
       def skipping_registration(node_name, config)
       end
 
-      # About to attempt to register as +node_name+
+      # About to attempt to create a private key registered to the server with
+      # client +node_name+.
       def registration_start(node_name, config)
       end
 
+      # Successfully created the private key and registered this client with the
+      # server.
       def registration_completed
       end
 
@@ -82,6 +87,11 @@ class Chef
       def node_load_completed(node, expanded_run_list, config)
       end
 
+      # Called after the Policyfile was loaded. This event only occurs when
+      # chef is in policyfile mode.
+      def policyfile_loaded(policy)
+      end
+
       # Called before the cookbook collection is fetched from the server.
       def cookbook_resolution_start(expanded_run_list)
       end
@@ -113,8 +123,8 @@ class Chef
       def cookbook_sync_start(cookbook_count)
       end
 
-      # Called when cookbook +cookbook_name+ has been sync'd
-      def synchronized_cookbook(cookbook_name)
+      # Called when cookbook +cookbook+ has been sync'd
+      def synchronized_cookbook(cookbook_name, cookbook)
       end
 
       # Called when an individual file in a cookbook has been updated
@@ -239,13 +249,13 @@ class Chef
       end
 
       # Called when audit phase successfully finishes
-      def audit_phase_complete
+      def audit_phase_complete(audit_output)
       end
 
       # Called if there is an uncaught exception during the audit phase.  The audit runner should
       # be catching and handling errors from the examples, so this is only uncaught errors (like
       # bugs in our handling code)
-      def audit_phase_failed(exception)
+      def audit_phase_failed(exception, audit_output)
       end
 
       # Signifies the start of a `control_group` block with a defined name
@@ -264,26 +274,37 @@ class Chef
       # def notifications_resolved
       # end
 
-      # Called before action is executed on a resource.
-      def resource_action_start(resource, action, notification_type=nil, notifier=nil)
-      end
-
-      # Called when a resource fails, but will retry.
-      def resource_failed_retriable(resource, action, retry_count, exception)
-      end
+      #
+      # Resource events and ordering:
+      #
+      # 1. Start the action
+      #    - resource_action_start
+      # 2. Check the guard
+      #    - resource_skipped: (goto 7) if only_if/not_if say to skip
+      # 3. Load the current resource
+      #    - resource_current_state_loaded
+      #    - resource_current_state_load_bypassed (if not why-run safe)
+      # 4. Check if why-run safe
+      #    - resource_bypassed: (goto 7) if not why-run safe
+      # 5. During processing:
+      #    - resource_update_applied: For each actual change (many per action)
+      # 6. Processing complete status:
+      #    - resource_failed if the resource threw an exception while running
+      #    - resource_failed_retriable: (goto 3) if resource failed and will be retried
+      #    - resource_updated if the resource was updated (resource_update_applied will have been called)
+      #    - resource_up_to_date if the resource was up to date (no resource_update_applied)
+      # 7. Processing complete:
+      #    - resource_completed
+      #
 
-      # Called when a resource fails and will not be retried.
-      def resource_failed(resource, action, exception)
+      # Called before action is executed on a resource.
+      def resource_action_start(resource, action, notification_type = nil, notifier = nil)
       end
 
       # Called when a resource action has been skipped b/c of a conditional
       def resource_skipped(resource, action, conditional)
       end
 
-      # Called when a resource action has been completed
-      def resource_completed(resource)
-      end
-
       # Called after #load_current_resource has run.
       def resource_current_state_loaded(resource, action, current_resource)
       end
@@ -297,21 +318,33 @@ class Chef
       def resource_bypassed(resource, action, current_resource)
       end
 
-      # Called when a resource has no converge actions, e.g., it was already correct.
-      def resource_up_to_date(resource, action)
-      end
-
       # Called when a change has been made to a resource. May be called multiple
       # times per resource, e.g., a file may have its content updated, and then
       # its permissions updated.
       def resource_update_applied(resource, action, update)
       end
 
+      # Called when a resource fails, but will retry.
+      def resource_failed_retriable(resource, action, retry_count, exception)
+      end
+
+      # Called when a resource fails and will not be retried.
+      def resource_failed(resource, action, exception)
+      end
+
       # Called after a resource has been completely converged, but only if
       # modifications were made.
       def resource_updated(resource, action)
       end
 
+      # Called when a resource has no converge actions, e.g., it was already correct.
+      def resource_up_to_date(resource, action)
+      end
+
+      # Called when a resource action has been completed
+      def resource_completed(resource)
+      end
+
       # A stream has opened.
       def stream_opened(stream, options = {})
       end
@@ -347,8 +380,12 @@ class Chef
       def whyrun_assumption(action, resource, message)
       end
 
-      ## TODO: deprecation warning. this way we can queue them up and present
-      #  them all at once.
+      # Emit a message about something being deprecated.
+      def deprecation(message, location = caller(2..2)[0])
+      end
+
+      def run_list_expanded(run_list_expansion)
+      end
 
       # An uncategorized message. This supports the case that a user needs to
       # pass output that doesn't fit into one of the callbacks above. Note that
diff --git a/lib/chef/event_dispatch/dispatcher.rb b/lib/chef/event_dispatch/dispatcher.rb
index 9f43f14..69419a3 100644
--- a/lib/chef/event_dispatch/dispatcher.rb
+++ b/lib/chef/event_dispatch/dispatcher.rb
@@ -1,4 +1,4 @@
-require 'chef/event_dispatch/base'
+require "chef/event_dispatch/base"
 
 class Chef
   module EventDispatch
@@ -9,6 +9,8 @@ class Chef
     # the registered subscribers.
     class Dispatcher < Base
 
+      attr_reader :subscribers
+
       def initialize(*subscribers)
         @subscribers = subscribers
       end
@@ -18,23 +20,43 @@ class Chef
         @subscribers << subscriber
       end
 
+      # Check to see if we are dispatching to a formatter
+      def formatter?
+        @subscribers.any? { |s| s.respond_to?(:is_formatter?) && s.is_formatter? }
+      end
+
       ####
       # All messages are unconditionally forwarded to all subscribers, so just
       # define the forwarding in one go:
       #
 
-      # Define a method that will be forwarded to all
-      def self.def_forwarding_method(method_name)
-        define_method(method_name) do |*args|
-          @subscribers.each { |s| s.send(method_name, *args) }
+      def call_subscribers(method_name, *args)
+        @subscribers.each do |s|
+          # Skip new/unsupported event names.
+          next if !s.respond_to?(method_name)
+          mth = s.method(method_name)
+          # Trim arguments to match what the subscriber expects to allow
+          # adding new arguments without breaking compat.
+          if mth.arity < args.size && mth.arity >= 0
+            mth.call(*args.take(mth.arity))
+          else
+            mth.call(*args)
+          end
         end
       end
 
       (Base.instance_methods - Object.instance_methods).each do |method_name|
-        def_forwarding_method(method_name)
+        class_eval <<-EOM
+          def #{method_name}(*args)
+            call_subscribers(#{method_name.inspect}, *args)
+          end
+        EOM
       end
 
+      # Special case deprecation, since it needs to know its caller
+      def deprecation(message, location = caller(2..2)[0])
+        call_subscribers(:deprecation, message, location)
+      end
     end
   end
 end
-
diff --git a/lib/chef/event_dispatch/dsl.rb b/lib/chef/event_dispatch/dsl.rb
new file mode 100644
index 0000000..999d536
--- /dev/null
+++ b/lib/chef/event_dispatch/dsl.rb
@@ -0,0 +1,65 @@
+#
+# Author:: Ranjib Dey (<ranjib at linux.com>)
+# Copyright:: Copyright 2015-2016, Ranjib Dey
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "chef/event_dispatch/base"
+require "chef/exceptions"
+require "chef/config"
+
+class Chef
+  module EventDispatch
+    class DSL
+      attr_reader :handler
+
+      def initialize(name)
+        klass = Class.new(Chef::EventDispatch::Base) do
+          attr_reader :name
+        end
+        @handler = klass.new
+        @handler.instance_variable_set(:@name, name)
+
+        # Use event.register API to add anonymous handler if Chef.run_context
+        # and associated event dispatcher is set, else fallback to
+        # Chef::Config[:event_handlers]
+        if Chef.run_context && Chef.run_context.events
+          Chef::Log.debug("Registering handler '#{name}' using events api")
+          Chef.run_context.events.register(handler)
+        else
+          Chef::Log.debug("Registering handler '#{name}' using global config")
+          Chef::Config[:event_handlers] << handler
+        end
+      end
+
+      # Adds a new event handler derived from base handler
+      # with user defined block against a chef event
+      #
+      # @return [Chef::EventDispatch::Base] a base handler object
+      def on(event_type, &block)
+        validate!(event_type)
+        handler.define_singleton_method(event_type) do |*args|
+          instance_exec(*args, &block)
+        end
+      end
+
+      private
+
+      def validate!(event_type)
+        all_event_types = (Chef::EventDispatch::Base.instance_methods - Object.instance_methods)
+        raise Chef::Exceptions::InvalidEventType, "Invalid event type: #{event_type}" unless all_event_types.include?(event_type)
+      end
+    end
+  end
+end
diff --git a/lib/chef/event_dispatch/events_output_stream.rb b/lib/chef/event_dispatch/events_output_stream.rb
index 8de9b0f..d9c2164 100644
--- a/lib/chef/event_dispatch/events_output_stream.rb
+++ b/lib/chef/event_dispatch/events_output_stream.rb
@@ -21,6 +21,14 @@ class Chef
         events.stream_output(self, str, options)
       end
 
+      def <<(str)
+        events.stream_output(self, str, options)
+      end
+
+      def write(str)
+        events.stream_output(self, str, options)
+      end
+
       def close
         events.stream_closed(self, options)
       end
diff --git a/lib/chef/event_loggers/base.rb b/lib/chef/event_loggers/base.rb
index 1f676dd..c34ed22 100644
--- a/lib/chef/event_loggers/base.rb
+++ b/lib/chef/event_loggers/base.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Jay Mundrawala (<jdm at getchef.com>)
+# Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/event_dispatch/base'
+require "chef/event_dispatch/base"
 
 class Chef
   module EventLoggers
diff --git a/lib/chef/event_loggers/windows_eventlog.rb b/lib/chef/event_loggers/windows_eventlog.rb
index 37dcdc8..1d16b66 100644
--- a/lib/chef/event_loggers/windows_eventlog.rb
+++ b/lib/chef/event_loggers/windows_eventlog.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Jay Mundrawala (<jdm at getchef.com>)
+# Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,19 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/event_loggers/base'
-require 'chef/platform/query_helpers'
-
-if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
-  if defined? Windows::Constants
-    [:INFINITE, :WAIT_FAILED, :FORMAT_MESSAGE_IGNORE_INSERTS, :ERROR_INSUFFICIENT_BUFFER].each do |c|
-      # These are redefined in 'win32/eventlog'
-      Windows::Constants.send(:remove_const, c) if Windows::Constants.const_defined? c
-    end
-  end
-
-  require 'win32/eventlog'
-end
+require "chef/event_loggers/base"
+require "chef/platform/query_helpers"
+require "chef/win32/eventlog"
 
 class Chef
   module EventLoggers
@@ -45,14 +35,14 @@ class Chef
       LOG_CATEGORY_ID = 11001
 
       # Since we must install the event logger, this is not really configurable
-      SOURCE = 'Chef'
+      SOURCE = "Chef"
 
       def self.available?
         return Chef::Platform::windows?
       end
 
       def initialize
-        @eventlog = ::Win32::EventLog::open('Application')
+        @eventlog = ::Win32::EventLog::open("Application")
       end
 
       def run_start(version)
@@ -60,7 +50,7 @@ class Chef
           :event_type => ::Win32::EventLog::INFO_TYPE,
           :source => SOURCE,
           :event_id => RUN_START_EVENT_ID,
-          :data => [version]
+          :data => [version],
         )
       end
 
@@ -70,7 +60,7 @@ class Chef
           :event_type => ::Win32::EventLog::INFO_TYPE,
           :source => SOURCE,
           :event_id => RUN_STARTED_EVENT_ID,
-          :data => [run_status.run_id]
+          :data => [run_status.run_id],
         )
       end
 
@@ -79,7 +69,7 @@ class Chef
           :event_type => ::Win32::EventLog::INFO_TYPE,
           :source => SOURCE,
           :event_id => RUN_COMPLETED_EVENT_ID,
-          :data => [@run_status.run_id, @run_status.elapsed_time.to_s]
+          :data => [@run_status.run_id, @run_status.elapsed_time.to_s],
         )
       end
 
@@ -102,7 +92,7 @@ class Chef
           :event_id => RUN_FAILED_EVENT_ID,
           :data => data + [e.class.name,
                            e.message,
-                           e.backtrace.join("\n")]
+                           e.backtrace.join("\n")],
         )
       end
 
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index eea6a2f..6afcc9c 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
 # Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+require "chef-config/exceptions"
+
 class Chef
   # == Chef::Exceptions
   # Chef's custom exceptions are all contained within the Chef::Exceptions
   # namespace.
   class Exceptions
 
+    ConfigurationError = ChefConfig::ConfigurationError
+
     # Backcompat with Chef::ShellOut code:
-    require 'mixlib/shellout/exceptions'
+    require "mixlib/shellout/exceptions"
 
     def self.const_missing(const_name)
       if const_name == :ShellCommandFailed
         Chef::Log.warn("Chef::Exceptions::ShellCommandFailed is deprecated, use Mixlib::ShellOut::ShellCommandFailed")
-        called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << "  #{trace_line}\n" }
+        called_from = caller[0..3].inject("Called from:\n") { |msg, trace_line| msg << "  #{trace_line}\n" }
         Chef::Log.warn(called_from)
         Mixlib::ShellOut::ShellCommandFailed
       else
@@ -67,12 +71,24 @@ class Chef
     class RoleNotFound < RuntimeError; end
     class DuplicateRole < RuntimeError; end
     class ValidationFailed < ArgumentError; end
+    class CannotValidateStaticallyError < ArgumentError; end
     class InvalidPrivateKey < ArgumentError; end
-    class ConfigurationError < ArgumentError; end
+    class MissingKeyAttribute < ArgumentError; end
+    class KeyCommandInputError < ArgumentError; end
+    class BootstrapCommandInputError < ArgumentError
+      def initialize
+        super "You cannot pass both --json-attributes and --json-attribute-file. Please pass one or none."
+      end
+    end
+    class InvalidKeyArgument < ArgumentError; end
+    class InvalidKeyAttribute < ArgumentError; end
+    class InvalidUserAttribute < ArgumentError; end
+    class InvalidClientAttribute < ArgumentError; end
     class RedirectLimitExceeded < RuntimeError; end
     class AmbiguousRunlistSpecification < ArgumentError; end
     class CookbookFrozen < ArgumentError; end
     class CookbookNotFound < RuntimeError; end
+    class OnlyApiVersion0SupportedForAction < RuntimeError; end
     # Cookbook loader used to raise an argument error when cookbook not found.
     # for back compat, need to raise an error that inherits from ArgumentError
     class CookbookNotFoundInRepo < ArgumentError; end
@@ -90,7 +106,14 @@ class Chef
     class ConflictingMembersInGroup < ArgumentError; end
     class InvalidResourceReference < RuntimeError; end
     class ResourceNotFound < RuntimeError; end
+    class ProviderNotFound < RuntimeError; end
+    NoProviderAvailable = ProviderNotFound
     class VerificationNotFound < RuntimeError; end
+    class InvalidEventType < ArgumentError; end
+    class MultipleIdentityError < RuntimeError; end
+    # Used in Resource::ActionClass#load_current_resource to denote that
+    # the resource doesn't actually exist (for example, the file does not exist)
+    class CurrentValueDoesNotExist < RuntimeError; end
 
     # Can't find a Resource of this type that is valid on this platform.
     class NoSuchResourceType < NameError
@@ -99,6 +122,8 @@ class Chef
       end
     end
 
+    class InvalidPolicybuilderCall < ArgumentError; end
+
     class InvalidResourceSpecification < ArgumentError; end
     class SolrConnectionError < RuntimeError; end
     class IllegalChecksumRevert < RuntimeError; end
@@ -112,6 +137,7 @@ class Chef
     class EnclosingDirectoryDoesNotExist < ArgumentError; end
     # Errors originating from calls to the Win32 API
     class Win32APIError < RuntimeError; end
+
     # Thrown when Win32 API layer binds to non-existent Win32 function.  Occurs
     # when older versions of Windows don't support newer Win32 API functions.
     class Win32APIFunctionNotImplemented < NotImplementedError; end
@@ -128,6 +154,8 @@ class Chef
     class LCMParser < RuntimeError; end
 
     class CannotDetermineHomebrewOwner < Package; end
+    class CannotDetermineWindowsInstallerType < Package; end
+    class NoWindowsPackageSource < Package; end
 
     # Can not create staging file during file deployment
     class FileContentStagingError < RuntimeError
@@ -177,7 +205,7 @@ class Chef
     class ImmutableAttributeModification < NoMethodError
       def initialize
         super "Node attributes are read-only when you do not specify which precedence level to set. " +
-          %Q(To set an attribute use code like `node.default["key"] = "value"')
+          %q{To set an attribute use code like `node.default["key"] = "value"'}
       end
     end
 
@@ -211,8 +239,6 @@ class Chef
 
     class ChildConvergeError < RuntimeError; end
 
-    class NoProviderAvailable < RuntimeError; end
-
     class DeprecatedFeatureError < RuntimeError;
       def initalize(message)
         super("#{message} (raising error due to treat_deprecation_warnings_as_errors being set)")
@@ -224,7 +250,7 @@ class Chef
 
       attr_reader :expansion
 
-      def initialize(message_or_expansion=NULL)
+      def initialize(message_or_expansion = NULL)
         @expansion = nil
         case message_or_expansion
         when NULL
@@ -233,7 +259,7 @@ class Chef
           super
         when RunList::RunListExpansion
           @expansion = message_or_expansion
-          missing_roles = @expansion.errors.join(', ')
+          missing_roles = @expansion.errors.join(", ")
           super("The expanded run list includes nonexistent roles: #{missing_roles}")
         end
       end
@@ -303,7 +329,7 @@ class Chef
           result = {
             "message" => message,
             "non_existent_cookbooks" => non_existent_cookbooks,
-            "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions
+            "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions,
           }
           Chef::JSONCompat.to_json(result, *a)
         end
@@ -338,7 +364,7 @@ class Chef
             "message" => message,
             "unsatisfiable_run_list_item" => run_list_item,
             "non_existent_cookbooks" => non_existent_cookbooks,
-            "most_constrained_cookbooks" => most_constrained_cookbooks
+            "most_constrained_cookbooks" => most_constrained_cookbooks,
           }
           Chef::JSONCompat.to_json(result, *a)
         end
@@ -356,7 +382,10 @@ class Chef
     # length declared in the http response.
     class ContentLengthMismatch < RuntimeError
       def initialize(response_length, content_length)
-        super "Response body length #{response_length} does not match HTTP Content-Length header #{content_length}."
+        super <<-EOF
+Response body length #{response_length} does not match HTTP Content-Length header #{content_length}.
+This error is most often caused by network issues (proxies, etc) outside of chef-client.
+        EOF
       end
     end
 
@@ -420,7 +449,7 @@ class Chef
     class RunFailedWrappingError < RuntimeError
       attr_reader :wrapped_errors
       def initialize(*errors)
-        errors = errors.select {|e| !e.nil?}
+        errors = errors.select { |e| !e.nil? }
         output = "Found #{errors.size} errors, they are stored in the backtrace"
         @wrapped_errors = errors
         super output
@@ -428,10 +457,10 @@ class Chef
 
       def fill_backtrace
         backtrace = []
-        wrapped_errors.each_with_index do |e,i|
-          backtrace << "#{i+1}) #{e.class} -  #{e.message}"
+        wrapped_errors.each_with_index do |e, i|
+          backtrace << "#{i + 1}) #{e.class} -  #{e.message}"
           backtrace += e.backtrace if e.backtrace
-          backtrace << ""
+          backtrace << "" unless i == wrapped_errors.length - 1
         end
         set_backtrace(backtrace)
       end
@@ -443,12 +472,26 @@ class Chef
       end
     end
 
+    class CookbookChefVersionMismatch < RuntimeError
+      def initialize(chef_version, cookbook_name, cookbook_version, *constraints)
+        constraint_str = constraints.map { |c| c.requirement.as_list.to_s }.join(", ")
+        super "Cookbook '#{cookbook_name}' version '#{cookbook_version}' depends on chef version #{constraint_str}, but the running chef version is #{chef_version}"
+      end
+    end
+
+    class CookbookOhaiVersionMismatch < RuntimeError
+      def initialize(ohai_version, cookbook_name, cookbook_version, *constraints)
+        constraint_str = constraints.map { |c| c.requirement.as_list.to_s }.join(", ")
+        super "Cookbook '#{cookbook_name}' version '#{cookbook_version}' depends on ohai version #{constraint_str}, but the running ohai version is #{ohai_version}"
+      end
+    end
+
     class MultipleDscResourcesFound < RuntimeError
       attr_reader :resources_found
       def initialize(resources_found)
         @resources_found = resources_found
         matches_info = @resources_found.each do |r|
-          if r['Module'].nil?
+          if r["Module"].nil?
             "Resource #{r['Name']} was found in #{r['Module']['Name']}"
           else
             "Resource #{r['Name']} is a binary resource"
diff --git a/lib/chef/file_access_control.rb b/lib/chef/file_access_control.rb
index cc7fa8f..50a1ea2 100644
--- a/lib/chef/file_access_control.rb
+++ b/lib/chef/file_access_control.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/log'
+require "chef/log"
 
 class Chef
 
@@ -27,10 +27,10 @@ class Chef
   class FileAccessControl
 
     if RUBY_PLATFORM =~ /mswin|mingw|windows/
-      require 'chef/file_access_control/windows'
+      require "chef/file_access_control/windows"
       include FileAccessControl::Windows
     else
-      require 'chef/file_access_control/unix'
+      require "chef/file_access_control/unix"
       include FileAccessControl::Unix
     end
 
diff --git a/lib/chef/file_access_control/unix.rb b/lib/chef/file_access_control/unix.rb
index 472f30b..eec9c62 100644
--- a/lib/chef/file_access_control/unix.rb
+++ b/lib/chef/file_access_control/unix.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 # limitations under the License.
 #
 
-require 'chef/log'
+require "chef/log"
 
 class Chef
   class FileAccessControl
@@ -79,18 +79,18 @@ class Chef
       def should_update_owner?
         if target_uid.nil?
           # the user has not specified a permission on the new resource, so we never manage it with FAC
-          Chef::Log.debug("found target_uid == nil, so no owner was specified on resource, not managing owner")
+          Chef::Log.debug("Found target_uid == nil, so no owner was specified on resource, not managing owner")
           return false
         elsif current_uid.nil?
           # the user has specified a permission, and we are creating a file, so always enforce permissions
-          Chef::Log.debug("found current_uid == nil, so we are creating a new file, updating owner")
+          Chef::Log.debug("Found current_uid == nil, so we are creating a new file, updating owner")
           return true
         elsif target_uid != current_uid
           # the user has specified a permission, and it does not match the file, so fix the permission
-          Chef::Log.debug("found target_uid != current_uid, updating owner")
+          Chef::Log.debug("Found target_uid != current_uid, updating owner")
           return true
         else
-          Chef::Log.debug("found target_uid == current_uid, not updating owner")
+          Chef::Log.debug("Found target_uid == current_uid, not updating owner")
           # the user has specified a permission, but it matches the file, so behave idempotently
           return false
         end
@@ -138,18 +138,18 @@ class Chef
       def should_update_group?
         if target_gid.nil?
           # the user has not specified a permission on the new resource, so we never manage it with FAC
-          Chef::Log.debug("found target_gid == nil, so no group was specified on resource, not managing group")
+          Chef::Log.debug("Found target_gid == nil, so no group was specified on resource, not managing group")
           return false
         elsif current_gid.nil?
           # the user has specified a permission, and we are creating a file, so always enforce permissions
-          Chef::Log.debug("found current_gid == nil, so we are creating a new file, updating group")
+          Chef::Log.debug("Found current_gid == nil, so we are creating a new file, updating group")
           return true
         elsif target_gid != current_gid
           # the user has specified a permission, and it does not match the file, so fix the permission
-          Chef::Log.debug("found target_gid != current_gid, updating group")
+          Chef::Log.debug("Found target_gid != current_gid, updating group")
           return true
         else
-          Chef::Log.debug("found target_gid == current_gid, not updating group")
+          Chef::Log.debug("Found target_gid == current_gid, not updating group")
           # the user has specified a permission, but it matches the file, so behave idempotently
           return false
         end
@@ -187,18 +187,20 @@ class Chef
       def should_update_mode?
         if target_mode.nil?
           # the user has not specified a permission on the new resource, so we never manage it with FAC
-          Chef::Log.debug("found target_mode == nil, so no mode was specified on resource, not managing mode")
+          Chef::Log.debug("Found target_mode == nil, so no mode was specified on resource, not managing mode")
           return false
         elsif current_mode.nil?
           # the user has specified a permission, and we are creating a file, so always enforce permissions
-          Chef::Log.debug("found current_mode == nil, so we are creating a new file, updating mode")
+          Chef::Log.debug("Found current_mode == nil, so we are creating a new file, updating mode")
           return true
         elsif target_mode != current_mode
           # the user has specified a permission, and it does not match the file, so fix the permission
-          Chef::Log.debug("found target_mode != current_mode, updating mode")
+          Chef::Log.debug("Found target_mode != current_mode, updating mode")
+          return true
+        elsif suid_bit_set? and (should_update_group? or should_update_owner?)
           return true
         else
-          Chef::Log.debug("found target_mode == current_mode, not updating mode")
+          Chef::Log.debug("Found target_mode == current_mode, not updating mode")
           # the user has specified a permission, but it matches the file, so behave idempotently
           return false
         end
@@ -280,6 +282,9 @@ class Chef
         return nil
       end
 
+      def suid_bit_set?
+        return target_mode & 04000 > 0
+      end
     end
   end
 end
diff --git a/lib/chef/file_access_control/windows.rb b/lib/chef/file_access_control/windows.rb
index 1781a6f..7f27ef8 100644
--- a/lib/chef/file_access_control/windows.rb
+++ b/lib/chef/file_access_control/windows.rb
@@ -1,7 +1,7 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/file'
+require "chef/win32/security"
+require "chef/win32/file"
 
 class Chef
   class FileAccessControl
diff --git a/lib/chef/file_cache.rb b/lib/chef/file_cache.rb
index c2f77bd..cb8bf9b 100644
--- a/lib/chef/file_cache.rb
+++ b/lib/chef/file_cache.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/mixin/params_validate'
-require 'chef/mixin/create_path'
-require 'chef/exceptions'
-require 'chef/json_compat'
-require 'fileutils'
-require 'chef/util/path_helper'
+require "chef/mixin/params_validate"
+require "chef/mixin/create_path"
+require "chef/exceptions"
+require "chef/json_compat"
+require "fileutils"
+require "chef/util/path_helper"
 
 class Chef
   class FileCache
@@ -39,16 +39,16 @@ class Chef
       #
       # === Returns
       # true
-      def store(path, contents, perm=0640)
+      def store(path, contents, perm = 0640)
         validate(
           {
             :path => path,
-            :contents => contents
+            :contents => contents,
           },
           {
             :path => { :kind_of => String },
             :contents => { :kind_of => String },
-          }
+          },
         )
 
         file_path_array = File.split(path)
@@ -69,12 +69,12 @@ class Chef
         validate(
           {
             :file => file,
-            :path => path
+            :path => path,
           },
           {
             :file => { :kind_of => String },
             :path => { :kind_of => String },
-          }
+          },
         )
 
         file_path_array = File.split(path)
@@ -82,7 +82,7 @@ class Chef
         if File.exists?(file) && File.writable?(file)
           FileUtils.mv(
             file,
-            File.join(create_cache_path(File.join(file_path_array), true), file_name)
+            File.join(create_cache_path(File.join(file_path_array), true), file_name),
           )
         else
           raise RuntimeError, "Cannot move #{file} to #{path}!"
@@ -102,14 +102,14 @@ class Chef
       #
       # === Raises
       # Chef::Exceptions::FileNotFound:: If it cannot find the file in the cache
-      def load(path, read=true)
+      def load(path, read = true)
         validate(
           {
             :path => path
           },
           {
             :path => { :kind_of => String }
-          }
+          },
         )
         cache_path = create_cache_path(path, false)
         raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exists?(cache_path)
@@ -134,8 +134,8 @@ class Chef
             :path => path
           },
           {
-            :path => { :kind_of => String },
-          }
+            :path => { :kind_of => String }
+          },
         )
         cache_path = create_cache_path(path, false)
         if File.exists?(cache_path)
@@ -181,8 +181,8 @@ class Chef
             :path => path
           },
           {
-            :path => { :kind_of => String },
-          }
+            :path => { :kind_of => String }
+          },
         )
         full_path = create_cache_path(path, false)
         if File.exists?(full_path)
@@ -201,7 +201,7 @@ class Chef
       #
       # === Returns
       # String:: The fully expanded path
-      def create_cache_path(path, create_if_missing=true)
+      def create_cache_path(path, create_if_missing = true)
         cache_dir = File.expand_path(File.join(file_cache_path, path))
         if create_if_missing
           create_path(cache_dir)
diff --git a/lib/chef/file_content_management/content_base.rb b/lib/chef/file_content_management/content_base.rb
index 985e222..6080e37 100644
--- a/lib/chef/file_content_management/content_base.rb
+++ b/lib/chef/file_content_management/content_base.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/file_content_management/deploy.rb b/lib/chef/file_content_management/deploy.rb
index 35ea3c6..1e3ae55 100644
--- a/lib/chef/file_content_management/deploy.rb
+++ b/lib/chef/file_content_management/deploy.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/file_content_management/deploy/cp'
-require 'chef/file_content_management/deploy/mv_unix'
+require "chef/file_content_management/deploy/cp"
+require "chef/file_content_management/deploy/mv_unix"
 if Chef::Platform.windows?
-  require 'chef/file_content_management/deploy/mv_windows'
+  require "chef/file_content_management/deploy/mv_windows"
 end
 
 class Chef
@@ -35,4 +35,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/file_content_management/deploy/cp.rb b/lib/chef/file_content_management/deploy/cp.rb
index c6b1d6c..14dde85 100644
--- a/lib/chef/file_content_management/deploy/cp.rb
+++ b/lib/chef/file_content_management/deploy/cp.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,12 +34,12 @@ class Chef
       #
       class Cp
         def create(file)
-          Chef::Log.debug("touching #{file} to create it")
+          Chef::Log.debug("Touching #{file} to create it")
           FileUtils.touch(file)
         end
 
         def deploy(src, dst)
-          Chef::Log.debug("copying temporary file #{src} into place at #{dst}")
+          Chef::Log.debug("Copying temporary file #{src} into place at #{dst}")
           FileUtils.cp(src, dst)
         end
       end
diff --git a/lib/chef/file_content_management/deploy/mv_unix.rb b/lib/chef/file_content_management/deploy/mv_unix.rb
index 758c594..3805b3b 100644
--- a/lib/chef/file_content_management/deploy/mv_unix.rb
+++ b/lib/chef/file_content_management/deploy/mv_unix.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,19 +30,19 @@ class Chef
         def create(file)
           # this is very simple, but it ensures that ownership and file modes take
           # good defaults, in particular mode needs to obey umask on create
-          Chef::Log.debug("touching #{file} to create it")
+          Chef::Log.debug("Touching #{file} to create it")
           FileUtils.touch(file)
         end
 
         def deploy(src, dst)
           # we are only responsible for content so restore the dst files perms
-          Chef::Log.debug("reading modes from #{dst} file")
+          Chef::Log.debug("Reading modes from #{dst} file")
           stat = ::File.stat(dst)
           mode = stat.mode & 07777
           uid  = stat.uid
           gid  = stat.gid
 
-          Chef::Log.debug("applying mode = #{mode.to_s(8)}, uid = #{uid}, gid = #{gid} to #{src}")
+          Chef::Log.debug("Applying mode = #{mode.to_s(8)}, uid = #{uid}, gid = #{gid} to #{src}")
 
           # i own the inode, so should be able to at least chmod it
           ::File.chmod(mode, src)
@@ -67,11 +67,10 @@ class Chef
             Chef::Log.warn("Could not set gid = #{gid} on #{src}, file modes not preserved")
           end
 
-          Chef::Log.debug("moving temporary file #{src} into place at #{dst}")
+          Chef::Log.debug("Moving temporary file #{src} into place at #{dst}")
           FileUtils.mv(src, dst)
         end
       end
     end
   end
 end
-
diff --git a/lib/chef/file_content_management/deploy/mv_windows.rb b/lib/chef/file_content_management/deploy/mv_windows.rb
index 7504123..0e6e6cd 100644
--- a/lib/chef/file_content_management/deploy/mv_windows.rb
+++ b/lib/chef/file_content_management/deploy/mv_windows.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,9 +21,9 @@
 # ACL information on the dst file.
 #
 
-require 'chef/platform/query_helpers'
+require "chef/platform/query_helpers"
 if Chef::Platform.windows?
-  require 'chef/win32/security'
+  require "chef/win32/security"
 end
 
 class Chef
@@ -35,7 +35,7 @@ class Chef
         ACL = Security::ACL
 
         def create(file)
-          Chef::Log.debug("touching #{file} to create it")
+          Chef::Log.debug("Touching #{file} to create it")
           FileUtils.touch(file)
         end
 
@@ -63,12 +63,22 @@ class Chef
             raise Chef::Exceptions::WindowsNotAdmin, "can not get the security information for '#{dst}' due to missing Administrator privileges."
           end
 
-          if dst_sd.dacl_present?
-            apply_dacl = ACL.create(dst_sd.dacl.select { |ace| !ace.inherited? })
+          dacl_present = dst_sd.dacl_present?
+          if dacl_present
+            if dst_sd.dacl.nil?
+              apply_dacl = nil
+            else
+              apply_dacl = ACL.create(dst_sd.dacl.select { |ace| !ace.inherited? })
+            end
           end
 
-          if dst_sd.sacl_present?
-            apply_sacl = ACL.create(dst_sd.sacl.select { |ace| !ace.inherited? })
+          sacl_present = dst_sd.sacl_present?
+          if sacl_present
+            if dst_sd.sacl.nil?
+              apply_sacl = nil
+            else
+              apply_sacl = ACL.create(dst_sd.sacl.select { |ace| !ace.inherited? })
+            end
           end
 
           #
@@ -84,12 +94,10 @@ class Chef
           dst_so = Security::SecurableObject.new(dst)
           dst_so.group = dst_sd.group
           dst_so.owner = dst_sd.owner
-          dst_so.set_dacl(apply_dacl, dst_sd.dacl_inherits?) if dst_sd.dacl_present?
-          dst_so.set_sacl(apply_sacl, dst_sd.sacl_inherits?) if dst_sd.sacl_present?
-
+          dst_so.set_dacl(apply_dacl, dst_sd.dacl_inherits?) if dacl_present
+          dst_so.set_sacl(apply_sacl, dst_sd.sacl_inherits?) if sacl_present
         end
       end
     end
   end
 end
-
diff --git a/lib/chef/file_content_management/tempfile.rb b/lib/chef/file_content_management/tempfile.rb
index 2dde0ce..dbe8a30 100644
--- a/lib/chef/file_content_management/tempfile.rb
+++ b/lib/chef/file_content_management/tempfile.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,7 +49,7 @@ class Chef
           end
         end
 
-        raise Chef::Exceptions::FileContentStagingError(errors) if tf.nil?
+        raise Chef::Exceptions::FileContentStagingError, errors if tf.nil?
 
         # We always process the tempfile in binmode so that we
         # preserve the line endings of the content.
@@ -64,7 +64,7 @@ class Chef
       #
       def tempfile_basename
         basename = ::File.basename(@new_resource.name)
-        basename.insert 0, "." unless Chef::Platform.windows?  # dotfile if we're not on windows
+        basename.insert 0, "." unless Chef::Platform.windows? # dotfile if we're not on windows
         basename
       end
 
diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb
index c901068..b2a8c80 100644
--- a/lib/chef/formatters/base.rb
+++ b/lib/chef/formatters/base.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Tyler Cloke (<tyler at opscode.com>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
 #
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'chef/event_dispatch/base'
-require 'chef/formatters/error_inspectors'
-require 'chef/formatters/error_descriptor'
-require 'chef/formatters/error_mapper'
-require 'chef/formatters/indentable_output_stream'
+require "chef/event_dispatch/base"
+require "chef/formatters/error_inspectors"
+require "chef/formatters/error_descriptor"
+require "chef/formatters/error_mapper"
+require "chef/formatters/indentable_output_stream"
 
 class Chef
 
@@ -212,8 +212,14 @@ class Chef
         file_load_failed(path, exception)
       end
 
-    end
+      def deprecation(message, location = caller(2..2)[0])
+        Chef::Log.deprecation("#{message} at #{location}")
+      end
 
+      def is_formatter?
+        true
+      end
+    end
 
     # == NullFormatter
     # Formatter that doesn't actually produce any output. You can use this to
@@ -222,6 +228,9 @@ class Chef
 
       cli_name(:null)
 
+      def is_formatter?
+        false
+      end
     end
 
   end
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index 7144d00..5462241 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -1,11 +1,11 @@
-require 'chef/formatters/base'
-require 'chef/config'
+require "chef/formatters/base"
+require "chef/config"
 
 class Chef
   module Formatters
-    #--
-    # TODO: not sold on the name, but the output is similar to what rspec calls
-    # "specdoc"
+
+    # Formatter similar to RSpec's documentation formatter. Uses indentation to
+    # show context.
     class Doc < Formatters::Base
 
       attr_reader :start_time, :end_time, :successful_audits, :failed_audits
@@ -22,18 +22,32 @@ class Chef
         @failed_audits = 0
         @start_time = Time.now
         @end_time = @start_time
+        @skipped_resources = 0
       end
 
       def elapsed_time
         end_time - start_time
       end
 
+      def pretty_elapsed_time
+        time = elapsed_time
+        if time < 60 then
+          message = Time.at(time).utc.strftime("%S seconds")
+        elsif time < 3600 then
+          message = Time.at(time).utc.strftime("%M minutes %S seconds")
+        else
+          message = Time.at(time).utc.strftime("%H hours %M minutes %S seconds")
+        end
+        message
+      end
+
       def run_start(version)
         puts_line "Starting Chef Client, version #{version}"
+        puts_line "OpenSSL FIPS 140 mode enabled" if Chef::Config[:fips]
       end
 
       def total_resources
-        @up_to_date_resources + @updated_resources
+        @up_to_date_resources + @updated_resources + @skipped_resources
       end
 
       def total_audits
@@ -42,10 +56,30 @@ class Chef
 
       def run_completed(node)
         @end_time = Time.now
+        # Print out deprecations.
+        if !deprecations.empty?
+          puts_line ""
+          puts_line "Deprecated features used!"
+          deprecations.each do |message, locations|
+            if locations.size == 1
+              puts_line "  #{message} at #{locations.size} location:"
+            else
+              puts_line "  #{message} at #{locations.size} locations:"
+            end
+            locations.each do |location|
+              prefix = "    - "
+              Array(location).each do |line|
+                puts_line "#{prefix}#{line}"
+                prefix = "      "
+              end
+            end
+          end
+          puts_line ""
+        end
         if Chef::Config[:why_run]
           puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources would have been updated"
         else
-          puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{elapsed_time} seconds"
+          puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{pretty_elapsed_time}"
           if total_audits > 0
             puts_line "  #{successful_audits}/#{total_audits} controls succeeded"
           end
@@ -57,7 +91,7 @@ class Chef
         if Chef::Config[:why_run]
           puts_line "Chef Client failed. #{@updated_resources} resources would have been updated"
         else
-          puts_line "Chef Client failed. #{@updated_resources} resources updated in #{elapsed_time} seconds"
+          puts_line "Chef Client failed. #{@updated_resources} resources updated in #{pretty_elapsed_time}"
           if total_audits > 0
             puts_line "  #{successful_audits} controls succeeded"
           end
@@ -93,6 +127,10 @@ class Chef
       def node_load_completed(node, expanded_run_list, config)
       end
 
+      def policyfile_loaded(policy)
+        puts_line "Using policy '#{policy["name"]}' at revision '#{policy["revision_id"]}'"
+      end
+
       # Called before the cookbook collection is fetched from the server.
       def cookbook_resolution_start(expanded_run_list)
         puts_line "resolving cookbooks for run list: #{expanded_run_list.inspect}"
@@ -128,9 +166,9 @@ class Chef
         indent
       end
 
-      # Called when cookbook +cookbook_name+ has been sync'd
-      def synchronized_cookbook(cookbook_name)
-        puts_line "- #{cookbook_name}"
+      # Called when cookbook +cookbook+ has been sync'd
+      def synchronized_cookbook(cookbook_name, cookbook)
+        puts_line "- #{cookbook.name} (#{cookbook.version})"
       end
 
       # Called when an individual file in a cookbook has been updated
@@ -175,17 +213,21 @@ class Chef
         puts_line "Starting audit phase"
       end
 
-      def audit_phase_complete
+      def audit_phase_complete(audit_output)
+        puts_line audit_output
         puts_line "Auditing complete"
       end
 
-      def audit_phase_failed(error)
+      def audit_phase_failed(error, audit_output)
+        puts_line audit_output
         puts_line ""
         puts_line "Audit phase exception:"
         indent
         puts_line "#{error.message}"
-        error.backtrace.each do |l|
-          puts_line l
+        if error.backtrace
+          error.backtrace.each do |l|
+            puts_line l
+          end
         end
       end
 
@@ -198,7 +240,7 @@ class Chef
       end
 
       # Called before action is executed on a resource.
-      def resource_action_start(resource, action, notification_type=nil, notifier=nil)
+      def resource_action_start(resource, action, notification_type = nil, notifier = nil)
         if resource.cookbook_name && resource.recipe_name
           resource_recipe = "#{resource.cookbook_name}::#{resource.recipe_name}"
         else
@@ -228,6 +270,7 @@ class Chef
 
       # Called when a resource action has been skipped b/c of a conditional
       def resource_skipped(resource, action, conditional)
+        @skipped_resources += 1
         # TODO: more info about conditional
         puts " (skipped due to #{conditional.short_description})", :stream => resource
         unindent
@@ -239,7 +282,7 @@ class Chef
 
       # Called when a resource has no converge actions, e.g., it was already correct.
       def resource_up_to_date(resource, action)
-        @up_to_date_resources+= 1
+        @up_to_date_resources += 1
         puts " (up to date)", :stream => resource
         unindent
       end
@@ -250,7 +293,6 @@ class Chef
       end
 
       def output_record(line)
-
       end
 
       # Called when a change has been made to a resource. May be called multiple
@@ -292,7 +334,7 @@ class Chef
 
       # Called before handlers run
       def handlers_start(handler_count)
-        puts ''
+        puts ""
         puts "Running handlers:"
         indent
       end
@@ -326,6 +368,16 @@ class Chef
         end
       end
 
+      def deprecation(message, location = caller(2..2)[0])
+        if Chef::Config[:treat_deprecation_warnings_as_errors]
+          super
+        end
+
+        # Save deprecations to the screen until the end
+        deprecations[message] ||= Set.new
+        deprecations[message] << location
+      end
+
       def indent
         indent_by(2)
       end
@@ -333,6 +385,12 @@ class Chef
       def unindent
         indent_by(-2)
       end
+
+      protected
+
+      def deprecations
+        @deprecations ||= {}
+      end
     end
   end
 end
diff --git a/lib/chef/formatters/error_descriptor.rb b/lib/chef/formatters/error_descriptor.rb
index c2e656f..0f14e6e 100644
--- a/lib/chef/formatters/error_descriptor.rb
+++ b/lib/chef/formatters/error_descriptor.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Tyler Cloke (<tyler at opscode.com>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
 #
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,7 @@ class Chef
       end
 
       def section(heading, text)
-        @sections << {heading => (text or "")}
+        @sections << { heading => (text or "") }
       end
 
       def display(out)
@@ -48,8 +48,8 @@ class Chef
 
       def for_json()
         {
-          'title' => @title,
-          'sections' => @sections
+          "title" => @title,
+          "sections" => @sections,
         }
       end
 
diff --git a/lib/chef/formatters/error_inspectors.rb b/lib/chef/formatters/error_inspectors.rb
index 4184573..9221ecd 100644
--- a/lib/chef/formatters/error_inspectors.rb
+++ b/lib/chef/formatters/error_inspectors.rb
@@ -1,9 +1,9 @@
-require 'chef/formatters/error_inspectors/node_load_error_inspector'
+require "chef/formatters/error_inspectors/node_load_error_inspector"
 require "chef/formatters/error_inspectors/registration_error_inspector"
-require 'chef/formatters/error_inspectors/compile_error_inspector'
-require 'chef/formatters/error_inspectors/resource_failure_inspector'
-require 'chef/formatters/error_inspectors/run_list_expansion_error_inspector'
-require 'chef/formatters/error_inspectors/cookbook_resolve_error_inspector'
+require "chef/formatters/error_inspectors/compile_error_inspector"
+require "chef/formatters/error_inspectors/resource_failure_inspector"
+require "chef/formatters/error_inspectors/run_list_expansion_error_inspector"
+require "chef/formatters/error_inspectors/cookbook_resolve_error_inspector"
 require "chef/formatters/error_inspectors/cookbook_sync_error_inspector"
 
 class Chef
diff --git a/lib/chef/formatters/error_inspectors/api_error_formatting.rb b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
index 652d478..2415d0f 100644
--- a/lib/chef/formatters/error_inspectors/api_error_formatting.rb
+++ b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
 # limitations under the License.
 #
 
+require "chef/http/authenticator"
+
 class Chef
   module Formatters
 
@@ -24,30 +26,66 @@ class Chef
       NETWORK_ERROR_CLASSES = [Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError]
 
       def describe_network_errors(error_description)
-        error_description.section("Networking Error:",<<-E)
+        error_description.section("Networking Error:", <<-E)
 #{exception.message}
 
 Your chef_server_url may be misconfigured, or the network could be down.
 E
-        error_description.section("Relevant Config Settings:",<<-E)
+        error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url  "#{server_url}"
 E
       end
 
+      def describe_eof_error(error_description)
+        error_description.section("Authentication Error:", <<-E)
+Received an EOF on transport socket.  This almost always indicates a network
+error external to chef-client.  Some causes include:
+
+  - Blocking ICMP Dest Unreachable (breaking Path MTU Discovery)
+  - IPsec or VPN tunnelling / TCP Encapsulation MTU issues
+  - Jumbo frames configured only on one side (breaking Path MTU)
+  - Jumbo frames configured on a LAN that does not support them
+  - Proxies or Load Balancers breaking large POSTs
+  - Broken TCP offload in network drivers/hardware
+
+Try sending large pings to the destination:
+
+   windows:  ping server.example.com -f -l 9999
+   unix:  ping server.example.com -s 9999
+
+Try sending large POSTs to the destination (any HTTP code returned is success):
+
+   e.g.:  curl http://server.example.com/`printf '%*s' 9999 '' | tr ' ' 'a'`
+
+Try disabling TCP Offload Engines (TOE) in your ethernet drivers.
+
+  windows:
+    Disable-NetAdapterChecksumOffload * -TcpIPv4 -UdpIPv4 -IpIPv4 -NoRestart
+    Disable-NetAdapterLso * -IPv4 -NoRestart
+    Set-NetAdapterAdvancedProperty * -DisplayName "Large Receive Offload (IPv4)" -DisplayValue Disabled –NoRestart
+    Restart-NetAdapter *
+  unix(bash):
+    for i in rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash; do /sbin/ethtool -K eth0 $i off; done
+
+In some cases the underlying virtualization layer (Xen, VMware, KVM, Hyper-V, etc) may have
+broken virtual networking code.
+        E
+      end
+
       def describe_401_error(error_description)
         if clock_skew?
-          error_description.section("Authentication Error:",<<-E)
+          error_description.section("Authentication Error:", <<-E)
 Failed to authenticate to the chef server (http 401).
 The request failed because your clock has drifted by more than 15 minutes.
 Syncing your clock to an NTP Time source should resolve the issue.
 E
         else
-          error_description.section("Authentication Error:",<<-E)
+          error_description.section("Authentication Error:", <<-E)
 Failed to authenticate to the chef server (http 401).
 E
 
           error_description.section("Server Response:", format_rest_error)
-          error_description.section("Relevant Config Settings:",<<-E)
+          error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url   "#{server_url}"
 node_name         "#{username}"
 client_key        "#{api_key}"
@@ -59,25 +97,42 @@ E
       end
 
       def describe_400_error(error_description)
-        error_description.section("Invalid Request Data:",<<-E)
+        error_description.section("Invalid Request Data:", <<-E)
 The data in your request was invalid (HTTP 400).
 E
-        error_description.section("Server Response:",format_rest_error)
+        error_description.section("Server Response:", format_rest_error)
+      end
+
+      def describe_406_error(error_description, response)
+        if response["x-ops-server-api-version"]
+          version_header = Chef::JSONCompat.from_json(response["x-ops-server-api-version"])
+          client_api_version = version_header["request_version"]
+          min_server_version = version_header["min_version"]
+          max_server_version = version_header["max_version"]
+
+          error_description.section("Incompatible server API version:", <<-E)
+This version of the API that this Chef request specified is not supported by the Chef server you sent this request to.
+The server supports a min API version of #{min_server_version} and a max API version of #{max_server_version}.
+Chef just made a request with an API version of #{client_api_version}.
+Please either update your Chef client or server to be a compatible set.
+E
+        else
+          describe_http_error(error_description)
+        end
       end
 
       def describe_500_error(error_description)
-        error_description.section("Unknown Server Error:",<<-E)
+        error_description.section("Unknown Server Error:", <<-E)
 The server had a fatal error attempting to load the node data.
 E
         error_description.section("Server Response:", format_rest_error)
       end
 
       def describe_503_error(error_description)
-        error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+        error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
         error_description.section("Server Response:", format_rest_error)
       end
 
-
       # Fallback for unexpected/uncommon http errors
       def describe_http_error(error_description)
         error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -86,7 +141,7 @@ E
       # Parses JSON from the error response sent by Chef Server and returns the
       # error message
       def format_rest_error
-        Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ')
+        Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join("; ")
       rescue Exception
         safe_format_rest_error
       end
diff --git a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
index 93328ad..d5ed69a 100644
--- a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,19 +30,52 @@ class Chef
 
         def initialize(path, exception)
           @path, @exception = path, exception
+          @backtrace_lines_in_cookbooks = nil
+          @file_lines = nil
+          @culprit_backtrace_entry = nil
+          @culprit_line = nil
         end
 
         def add_explanation(error_description)
-          case exception
-          when Chef::Exceptions::RecipeNotFound
-            error_description.section(exception.class.name, exception.message)
-          else
-            error_description.section(exception.class.name, exception.message)
+          error_description.section(exception.class.name, exception.message)
 
-            traceback = filtered_bt.map {|line| "  #{line}"}.join("\n")
+          if found_error_in_cookbooks?
+            traceback = filtered_bt.map { |line| "  #{line}" }.join("\n")
             error_description.section("Cookbook Trace:", traceback)
             error_description.section("Relevant File Content:", context)
           end
+
+          if exception_message_modifying_frozen?
+            msg = <<-MESSAGE
+            Ruby objects are often frozen to prevent further modifications
+            when they would negatively impact the process (e.g. values inside
+            Ruby's ENV class) or to prevent polluting other objects when default
+            values are passed by reference to many instances of an object (e.g.
+            the empty Array as a Chef resource default, passed by reference
+            to every instance of the resource).
+
+            Chef uses Object#freeze to ensure the default values of properties
+            inside Chef resources are not modified, so that when a new instance
+            of a Chef resource is created, and Object#dup copies values by
+            reference, the new resource is not receiving a default value that
+            has been by a previous instance of that resource.
+
+            Instead of modifying an object that contains a default value for all
+            instances of a Chef resource, create a new object and assign it to
+            the resource's parameter, e.g.:
+
+            fruit_basket = resource(:fruit_basket, 'default')
+
+            # BAD: modifies 'contents' object for all new fruit_basket instances
+            fruit_basket.contents << 'apple'
+
+            # GOOD: allocates new array only owned by this fruit_basket instance
+            fruit_basket.contents %w(apple)
+
+            MESSAGE
+
+            error_description.section("Additional information:", msg.gsub(/^ {6}/, ""))
+          end
         end
 
         def context
@@ -74,29 +107,44 @@ class Chef
 
         def culprit_backtrace_entry
           @culprit_backtrace_entry ||= begin
-             bt_entry = filtered_bt.first
-             Chef::Log.debug("backtrace entry for compile error: '#{bt_entry}'")
-             bt_entry
+            bt_entry = filtered_bt.first
+            Chef::Log.debug("Backtrace entry for compile error: '#{bt_entry}'")
+            bt_entry
           end
         end
 
         def culprit_line
           @culprit_line ||= begin
-            line_number = culprit_backtrace_entry[/^(?:.\:)?[^:]+:([\d]+)/,1].to_i
+            line_number = culprit_backtrace_entry[/^(?:.\:)?[^:]+:([\d]+)/, 1].to_i
             Chef::Log.debug("Line number of compile error: '#{line_number}'")
             line_number
           end
         end
 
         def culprit_file
-          @culprit_file ||= culprit_backtrace_entry[/^((?:.\:)?[^:]+):([\d]+)/,1]
+          @culprit_file ||= culprit_backtrace_entry[/^((?:.\:)?[^:]+):([\d]+)/, 1]
         end
 
         def filtered_bt
-          filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/ }
-          r = exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }}
-          Chef::Log.debug("filtered backtrace of compile error: #{r.join(",")}")
-          return r.count > 0 ? r : exception.backtrace
+          backtrace_lines_in_cookbooks.count > 0 ? backtrace_lines_in_cookbooks : exception.backtrace
+        end
+
+        def found_error_in_cookbooks?
+          !backtrace_lines_in_cookbooks.empty?
+        end
+
+        def backtrace_lines_in_cookbooks
+          @backtrace_lines_in_cookbooks ||=
+            begin
+              filters = Array(Chef::Config.cookbook_path).map { |p| /^#{Regexp.escape(p)}/i }
+              r = exception.backtrace.select { |line| filters.any? { |filter| line =~ filter } }
+              Chef::Log.debug("Filtered backtrace of compile error: #{r.join(",")}")
+              r
+            end
+        end
+
+        def exception_message_modifying_frozen?
+          exception.message.include?("can't modify frozen")
         end
 
       end
diff --git a/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb b/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
index aa5eb84..eb1aa62 100644
--- a/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
 
 class Chef
   module Formatters
@@ -37,10 +37,12 @@ class Chef
           case exception
           when Net::HTTPServerException, Net::HTTPFatalError
             humanize_http_exception(error_description)
+          when EOFError
+            describe_eof_error(error_description)
           when *NETWORK_ERROR_CLASSES
             describe_network_errors(error_description)
           else
-            error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+            error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
           end
         end
 
@@ -54,7 +56,7 @@ class Chef
             # TODO: we're rescuing errors from Node.find_or_create
             # * could be no write on nodes container
             # * could be no read on the node
-            error_description.section("Authorization Error",<<-E)
+            error_description.section("Authorization Error", <<-E)
 This client is not authorized to read some of the information required to
 access its cookbooks (HTTP 403).
 
@@ -72,6 +74,8 @@ E
             describe_500_error(error_description)
           when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
             describe_503_error(error_description)
+          when Net::HTTPNotAcceptable
+            describe_406_error(error_description, response)
           else
             describe_http_error(error_description)
           end
@@ -124,7 +128,7 @@ EOM
         end
 
         def expanded_run_list_ul
-          @expanded_run_list.map {|i| "* #{i}"}.join("\n")
+          @expanded_run_list.map { |i| "* #{i}" }.join("\n")
         end
 
         # In my tests, the error from the server is double JSON encoded, but we
@@ -158,9 +162,7 @@ EOM
           maybe_json_string
         end
 
-
       end
     end
   end
 end
-
diff --git a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
index 0cb849a..3bd9b41 100644
--- a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
 
 class Chef
   module Formatters
@@ -41,12 +41,14 @@ class Chef
 
         def add_explanation(error_description)
           case exception
-          when *NETWORK_ERROR_CLASSES
-            describe_network_errors(error_description)
           when Net::HTTPServerException, Net::HTTPFatalError
             humanize_http_exception(error_description)
+          when EOFError
+            describe_eof_error(error_description)
+          when *NETWORK_ERROR_CLASSES
+            describe_network_errors(error_description)
           else
-            error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+            error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
           end
         end
 
@@ -67,6 +69,8 @@ class Chef
             describe_500_error(error_description)
           when Net::HTTPBadGateway, Net::HTTPServiceUnavailable, Net::HTTPGatewayTimeOut
             describe_503_error(error_description)
+          when Net::HTTPNotAcceptable
+            describe_406_error(error_description, response)
           else
             describe_http_error(error_description)
           end
diff --git a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
index e257ee3..c52dad4 100644
--- a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
 
 class Chef
   module Formatters
     module ErrorInspectors
 
-
       # == APIErrorInspector
       # Wraps exceptions caused by API calls to the server.
       class NodeLoadErrorInspector
@@ -43,18 +42,20 @@ class Chef
           case exception
           when Net::HTTPServerException, Net::HTTPFatalError
             humanize_http_exception(error_description)
-          when *NETWORK_ERROR_CLASSES
-            describe_network_errors(error_description)
           when Chef::Exceptions::PrivateKeyMissing
-            error_description.section("Private Key Not Found:",<<-E)
+            error_description.section("Private Key Not Found:", <<-E)
 Your private key could not be loaded. If the key file exists, ensure that it is
 readable by chef-client.
 E
-            error_description.section("Relevant Config Settings:",<<-E)
+            error_description.section("Relevant Config Settings:", <<-E)
 client_key        "#{api_key}"
 E
+          when EOFError
+            describe_eof_error(error_description)
+          when *NETWORK_ERROR_CLASSES
+            describe_network_errors(error_description)
           else
-            error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+            error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
           end
         end
 
@@ -68,12 +69,12 @@ E
             # TODO: we're rescuing errors from Node.find_or_create
             # * could be no write on nodes container
             # * could be no read on the node
-            error_description.section("Authorization Error",<<-E)
+            error_description.section("Authorization Error", <<-E)
 Your client is not authorized to load the node data (HTTP 403).
 E
             error_description.section("Server Response:", format_rest_error)
 
-            error_description.section("Possible Causes:",<<-E)
+            error_description.section("Possible Causes:", <<-E)
 * Your client (#{username}) may have misconfigured authorization permissions.
 E
           when Net::HTTPBadRequest
@@ -84,6 +85,8 @@ E
             describe_500_error(error_description)
           when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
             describe_503_error(error_description)
+          when Net::HTTPNotAcceptable
+            describe_406_error(error_description, response)
           else
             describe_http_error(error_description)
           end
@@ -94,10 +97,10 @@ E
         # one, e.g., PUT http://wrong.url/nodes/node-name becomes a GET after a
         # redirect.
         def describe_404_error(error_description)
-          error_description.section("Resource Not Found:",<<-E)
+          error_description.section("Resource Not Found:", <<-E)
 The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect.
 E
-          error_description.section("Relevant Config Settings:",<<-E)
+          error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url "#{server_url}"
 E
         end
diff --git a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
index f31b348..c7c1454 100644
--- a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
@@ -9,6 +9,8 @@ class Chef
       # TODO: Lots of duplication with the node_load_error_inspector, just
       # slightly tweaked to talk about validation keys instead of other keys.
       class RegistrationErrorInspector
+        include APIErrorFormatting
+
         attr_reader :exception
         attr_reader :node_name
         attr_reader :config
@@ -24,27 +26,29 @@ class Chef
           when Net::HTTPServerException, Net::HTTPFatalError
             humanize_http_exception(error_description)
           when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError
-            error_description.section("Network Error:",<<-E)
+            error_description.section("Network Error:", <<-E)
 There was a network error connecting to the Chef Server:
 #{exception.message}
 E
-            error_description.section("Relevant Config Settings:",<<-E)
+            error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url  "#{server_url}"
 
 If your chef_server_url is correct, your network could be down.
 E
           when Chef::Exceptions::PrivateKeyMissing
-            error_description.section("Private Key Not Found:",<<-E)
+            error_description.section("Private Key Not Found:", <<-E)
 Your private key could not be loaded. If the key file exists, ensure that it is
 readable by chef-client.
 E
-            error_description.section("Relevant Config Settings:",<<-E)
+            error_description.section("Relevant Config Settings:", <<-E)
 validation_key "#{api_key}"
 E
           when Chef::Exceptions::InvalidRedirect
-            error_description.section("Invalid Redirect:",<<-E)
+            error_description.section("Invalid Redirect:", <<-E)
 Change your server location in client.rb to the server's FQDN to avoid unwanted redirections.
 E
+          when EOFError
+            describe_eof_error(error_description)
           else
             "#{exception.class.name}: #{exception.message}"
           end
@@ -55,18 +59,18 @@ E
           case response
           when Net::HTTPUnauthorized
             if clock_skew?
-              error_description.section("Authentication Error:",<<-E)
+              error_description.section("Authentication Error:", <<-E)
 Failed to authenticate to the chef server (http 401).
 The request failed because your clock has drifted by more than 15 minutes.
 Syncing your clock to an NTP Time source should resolve the issue.
 E
             else
-              error_description.section("Authentication Error:",<<-E)
+              error_description.section("Authentication Error:", <<-E)
 Failed to authenticate to the chef server (http 401).
 E
 
               error_description.section("Server Response:", format_rest_error)
-              error_description.section("Relevant Config Settings:",<<-E)
+              error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url         "#{server_url}"
 validation_client_name  "#{username}"
 validation_key          "#{api_key}"
@@ -75,32 +79,34 @@ If these settings are correct, your validation_key may be invalid.
 E
             end
           when Net::HTTPForbidden
-            error_description.section("Authorization Error:",<<-E)
+            error_description.section("Authorization Error:", <<-E)
 Your validation client is not authorized to create the client for this node (HTTP 403).
 E
-            error_description.section("Possible Causes:",<<-E)
+            error_description.section("Possible Causes:", <<-E)
 * There may already be a client named "#{config[:node_name]}"
 * Your validation client (#{username}) may have misconfigured authorization permissions.
 E
           when Net::HTTPBadRequest
-            error_description.section("Invalid Request Data:",<<-E)
+            error_description.section("Invalid Request Data:", <<-E)
 The data in your request was invalid (HTTP 400).
 E
-            error_description.section("Server Response:",format_rest_error)
+            error_description.section("Server Response:", format_rest_error)
           when Net::HTTPNotFound
-            error_description.section("Resource Not Found:",<<-E)
+            error_description.section("Resource Not Found:", <<-E)
 The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect.
 E
-            error_description.section("Relevant Config Settings:",<<-E)
+            error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url "#{server_url}"
 E
+          when Net::HTTPNotAcceptable
+            describe_406_error(error_description, response)
           when Net::HTTPInternalServerError
-            error_description.section("Unknown Server Error:",<<-E)
+            error_description.section("Unknown Server Error:", <<-E)
 The server had a fatal error attempting to load the node data.
 E
             error_description.section("Server Response:", format_rest_error)
           when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
-            error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+            error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
             error_description.section("Server Response:", format_rest_error)
           else
             error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -130,7 +136,7 @@ E
         #--
         # TODO: this code belongs in Chef::REST
         def format_rest_error
-          Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ')
+          Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join("; ")
         rescue Exception
           exception.response.body
         end
diff --git a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
index 48572d9..f593628 100644
--- a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,7 +52,7 @@ class Chef
           end
 
           if Chef::Platform.windows?
-            require 'chef/win32/security'
+            require "chef/win32/security"
 
             if !Chef::ReservedNames::Win32::Security.has_admin_privileges?
               error_description.section("Missing Windows Admin Privileges", "chef-client doesn't have administrator privileges. This can be a possible reason for the resource failure.")
@@ -63,13 +63,12 @@ class Chef
         def recipe_snippet
           return nil if dynamic_resource?
           @snippet ||= begin
-            if file = resource.source_line[/^(([\w]:)?[^:]+):([\d]+)/,1] and line = resource.source_line[/^#{file}:([\d]+)/,1].to_i
+            if file = parse_source and line = parse_line(file)
               return nil unless ::File.exists?(file)
               lines = IO.readlines(file)
 
               relevant_lines = ["# In #{file}\n\n"]
 
-
               current_line = line - 1
               current_line = 0 if current_line < 0
               nesting = 0
@@ -99,8 +98,8 @@ class Chef
         end
 
         def filtered_bt
-          filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/ }
-          exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }}
+          filters = Array(Chef::Config.cookbook_path).map { |p| /^#{Regexp.escape(p)}/ }
+          exception.backtrace.select { |line| filters.any? { |filter| line =~ filter } }
         end
 
         private
@@ -111,6 +110,14 @@ class Chef
           line_nr_string + line
         end
 
+        def parse_source
+          resource.source_line[/^(([\w]:)?[^:]+):([\d]+)/, 1]
+        end
+
+        def parse_line(source)
+          resource.source_line[/^#{Regexp.escape(source)}:([\d]+)/, 1].to_i
+        end
+
       end
     end
   end
diff --git a/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb b/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
index ac19a98..e94b347 100644
--- a/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/formatters/error_inspectors/api_error_formatting'
+require "chef/formatters/error_inspectors/api_error_formatting"
 
 class Chef
   module Formatters
@@ -36,7 +36,7 @@ class Chef
         def add_explanation(error_description)
           case exception
           when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError
-            error_description.section("Networking Error:",<<-E)
+            error_description.section("Networking Error:", <<-E)
 #{exception.message}
 
 Your chef_server_url may be misconfigured, or the network could be down.
@@ -45,14 +45,16 @@ E
             humanize_http_exception(error_description)
           when Chef::Exceptions::MissingRole
             describe_missing_role(error_description)
+          when EOFError
+            describe_eof_error(error_description)
           else
-            error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}")
+            error_description.section("Unexpected Error:", "#{exception.class.name}: #{exception.message}")
           end
         end
 
         def describe_missing_role(error_description)
           error_description.section("Missing Role(s) in Run List:", missing_roles_explained)
-          original_run_list = node.run_list.map {|item| "* #{item}"}.join("\n")
+          original_run_list = node.run_list.map { |item| "* #{item}" }.join("\n")
           error_description.section("Original Run List", original_run_list)
         end
 
@@ -74,12 +76,12 @@ E
           response = exception.response
           case response
           when Net::HTTPUnauthorized
-            error_description.section("Authentication Error:",<<-E)
+            error_description.section("Authentication Error:", <<-E)
 Failed to authenticate to the chef server (http 401).
 E
 
             error_description.section("Server Response:", format_rest_error)
-            error_description.section("Relevant Config Settings:",<<-E)
+            error_description.section("Relevant Config Settings:", <<-E)
 chef_server_url   "#{server_url}"
 node_name         "#{username}"
 client_key        "#{api_key}"
@@ -90,21 +92,23 @@ E
             # TODO: we're rescuing errors from Node.find_or_create
             # * could be no write on nodes container
             # * could be no read on the node
-            error_description.section("Authorization Error",<<-E)
+            error_description.section("Authorization Error", <<-E)
 Your client is not authorized to load one or more of your roles (HTTP 403).
 E
             error_description.section("Server Response:", format_rest_error)
 
-            error_description.section("Possible Causes:",<<-E)
+            error_description.section("Possible Causes:", <<-E)
 * Your client (#{username}) may have misconfigured authorization permissions.
 E
+          when Net::HTTPNotAcceptable
+            describe_406_error(error_description, response)
           when Net::HTTPInternalServerError
-            error_description.section("Unknown Server Error:",<<-E)
+            error_description.section("Unknown Server Error:", <<-E)
 The server had a fatal error attempting to load a role.
 E
             error_description.section("Server Response:", format_rest_error)
           when Net::HTTPBadGateway, Net::HTTPServiceUnavailable
-            error_description.section("Server Unavailable","The Chef Server is temporarily unavailable")
+            error_description.section("Server Unavailable", "The Chef Server is temporarily unavailable")
             error_description.section("Server Response:", format_rest_error)
           else
             error_description.section("Unexpected API Request Failure:", format_rest_error)
@@ -115,4 +119,3 @@ E
     end
   end
 end
-
diff --git a/lib/chef/formatters/error_mapper.rb b/lib/chef/formatters/error_mapper.rb
index 2140c63..4786a20 100644
--- a/lib/chef/formatters/error_mapper.rb
+++ b/lib/chef/formatters/error_mapper.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/formatters/indentable_output_stream.rb b/lib/chef/formatters/indentable_output_stream.rb
index 1beb286..e5e84e0 100644
--- a/lib/chef/formatters/indentable_output_stream.rb
+++ b/lib/chef/formatters/indentable_output_stream.rb
@@ -19,7 +19,7 @@ class Chef
 
       def highline
         @highline ||= begin
-          require 'highline'
+          require "highline"
           HighLine.new
         end
       end
@@ -50,6 +50,11 @@ class Chef
         print(string, from_args(args, :start_line => true, :end_line => true))
       end
 
+      # Print a raw chunk
+      def <<(obj)
+        print(obj)
+      end
+
       # Print a string.
       #
       # == Arguments
@@ -105,7 +110,7 @@ class Chef
       def print_string(string, options)
         if string.empty?
           if options[:end_line]
-            print_line('', options)
+            print_line("", options)
           end
         else
           string.lines.each do |line|
@@ -131,7 +136,7 @@ class Chef
 
       def move_to_next_line
         if @line_started
-          @out.puts ''
+          @out.puts ""
           @line_started = false
         end
       end
@@ -146,11 +151,11 @@ class Chef
             if @current_stream != options[:stream]
               @out.print "#{(' ' * indent)}[#{options[:name]}] "
             else
-              @out.print ' ' * (indent + 3 + options[:name].size)
+              @out.print " " * (indent + 3 + options[:name].size)
             end
           else
             # Otherwise, just print indents.
-            @out.print ' ' * indent
+            @out.print " " * indent
           end
 
           if @current_stream != options[:stream]
diff --git a/lib/chef/formatters/minimal.rb b/lib/chef/formatters/minimal.rb
index a189cc6..c8fc504 100644
--- a/lib/chef/formatters/minimal.rb
+++ b/lib/chef/formatters/minimal.rb
@@ -1,10 +1,9 @@
-require 'chef/formatters/base'
+require "chef/formatters/base"
 
 class Chef
 
   module Formatters
 
-
     # == Formatters::Minimal
     # Shows the progress of the chef run by printing single characters, and
     # displays a summary of updates at the conclusion of the run. For events
@@ -20,16 +19,16 @@ class Chef
       attr_reader :updated_resources
       attr_reader :updates_by_resource
 
-
       def initialize(out, err)
         super
         @updated_resources = []
-        @updates_by_resource = Hash.new {|h, k| h[k] = []}
+        @updates_by_resource = Hash.new { |h, k| h[k] = [] }
       end
 
       # Called at the very start of a Chef Run
       def run_start(version)
-        puts "Starting Chef Client, version #{version}"
+        puts_line "Starting Chef Client, version #{version}"
+        puts_line "OpenSSL FIPS 140 mode enabled" if Chef::Config[:fips]
       end
 
       # Called at the end of the Chef run.
@@ -109,8 +108,8 @@ class Chef
         puts "Synchronizing cookbooks"
       end
 
-      # Called when cookbook +cookbook_name+ has been sync'd
-      def synchronized_cookbook(cookbook_name)
+      # Called when cookbook +cookbook+ has been sync'd
+      def synchronized_cookbook(cookbook_name, cookbook)
         print "."
       end
 
@@ -130,7 +129,7 @@ class Chef
 
       # Called after a file in a cookbook is loaded.
       def file_loaded(path)
-        print '.'
+        print "."
       end
 
       def file_load_failed(path, exception)
@@ -157,7 +156,7 @@ class Chef
           puts "\n"
           puts "resources updated this run:"
           updated_resources.each do |resource|
-            puts "* #{resource.to_s}"
+            puts "* #{resource}"
             updates_by_resource[resource.name].flatten.each do |update|
               puts "  - #{update}"
             end
@@ -167,7 +166,7 @@ class Chef
       end
 
       # Called before action is executed on a resource.
-      def resource_action_start(resource, action, notification_type=nil, notifier=nil)
+      def resource_action_start(resource, action, notification_type = nil, notifier = nil)
       end
 
       # Called when a resource fails, but will retry.
@@ -232,4 +231,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/guard_interpreter.rb b/lib/chef/guard_interpreter.rb
index b968f27..e11201e 100644
--- a/lib/chef/guard_interpreter.rb
+++ b/lib/chef/guard_interpreter.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Steven Danna (<steve at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/guard_interpreter/default_guard_interpreter'
-require 'chef/guard_interpreter/resource_guard_interpreter'
+require "chef/guard_interpreter/default_guard_interpreter"
+require "chef/guard_interpreter/resource_guard_interpreter"
 
 class Chef
   class GuardInterpreter
diff --git a/lib/chef/guard_interpreter/default_guard_interpreter.rb b/lib/chef/guard_interpreter/default_guard_interpreter.rb
index df91c2b..449ca9a 100644
--- a/lib/chef/guard_interpreter/default_guard_interpreter.rb
+++ b/lib/chef/guard_interpreter/default_guard_interpreter.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
 # limitations under the License.
 #
 
+require "chef/mixin/shell_out"
+
 class Chef
   class GuardInterpreter
     class DefaultGuardInterpreter
@@ -39,4 +41,3 @@ class Chef
     end
   end
 end
-      
diff --git a/lib/chef/guard_interpreter/resource_guard_interpreter.rb b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
index 1e2a534..c219614 100644
--- a/lib/chef/guard_interpreter/resource_guard_interpreter.rb
+++ b/lib/chef/guard_interpreter/resource_guard_interpreter.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/guard_interpreter'
+require "chef/guard_interpreter"
 
 class Chef
   class GuardInterpreter
@@ -42,9 +42,9 @@ class Chef
         # We need to make sure we check for Script first because any resource
         # that can get to here is an Execute resource.
         if @resource.is_a? Chef::Resource::Script
-          block_attributes = @command_opts.merge({:code => @command})
+          block_attributes = @command_opts.merge({ :code => @command })
         else
-          block_attributes = @command_opts.merge({:command => @command})
+          block_attributes = @command_opts.merge({ :command => @command })
         end
 
         # Handles cases like powershell_script where default
@@ -62,13 +62,16 @@ class Chef
 
       protected
 
-      def evaluate_action(action=nil, &block)
+      def evaluate_action(action = nil, &block)
         @resource.instance_eval(&block)
 
         run_action = action || @resource.action
 
         begin
-          @resource.run_action(run_action)
+          # Coerce to an array to be safe. This could happen with a legacy
+          # resource or something overriding the default_action code in a
+          # subclass.
+          Array(run_action).each { |action_to_run| @resource.run_action(action_to_run) }
           resource_updated = @resource.updated
         rescue Mixlib::ShellOut::ShellCommandFailed
           resource_updated = nil
@@ -85,16 +88,19 @@ class Chef
         resource_class = Chef::Resource.resource_for_node(parent_resource.guard_interpreter, parent_resource.node)
 
         if resource_class.nil?
-          raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter.to_s} unknown for this platform"
+          raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter} unknown for this platform"
         end
 
         if ! resource_class.ancestors.include?(Chef::Resource::Execute)
           raise ArgumentError, "Specified guard interpreter class #{resource_class} must be a kind of Chef::Resource::Execute resource"
         end
 
+        # Duplicate the node below because the new RunContext
+        # overwrites the state of Node instances passed to it.
+        # See https://github.com/chef/chef/issues/3485.
         empty_events = Chef::EventDispatch::Dispatcher.new
-        anonymous_run_context = Chef::RunContext.new(parent_resource.node, {}, empty_events)
-        interpreter_resource = resource_class.new('Guard resource', anonymous_run_context)
+        anonymous_run_context = Chef::RunContext.new(parent_resource.node.dup, {}, empty_events)
+        interpreter_resource = resource_class.new("Guard resource", anonymous_run_context)
         interpreter_resource.is_guard_interpreter = true
 
         interpreter_resource
diff --git a/lib/chef/handler.rb b/lib/chef/handler.rb
index c4b729e..b720a11 100644
--- a/lib/chef/handler.rb
+++ b/lib/chef/handler.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/client'
-require 'forwardable'
+require "chef/client"
+require "forwardable"
 
 class Chef
   # == Chef::Handler
diff --git a/lib/chef/handler/error_report.rb b/lib/chef/handler/error_report.rb
index 8bf6764..e84a817 100644
--- a/lib/chef/handler/error_report.rb
+++ b/lib/chef/handler/error_report.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/handler'
-require 'chef/resource/directory'
+require "chef/handler"
+require "chef/resource/directory"
 
 class Chef
   class Handler
diff --git a/lib/chef/handler/json_file.rb b/lib/chef/handler/json_file.rb
index 405c917..9ba3d70 100644
--- a/lib/chef/handler/json_file.rb
+++ b/lib/chef/handler/json_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/handler'
-require 'chef/resource/directory'
+require "chef/handler"
+require "chef/resource/directory"
 
 class Chef
   class Handler
@@ -25,7 +25,7 @@ class Chef
 
       attr_reader :config
 
-      def initialize(config={})
+      def initialize(config = {})
         @config = config
         @config[:path] ||= "/var/chef/reports"
         @config
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 16a826a..0060fb0 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -1,11 +1,11 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, 2013-2015 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,15 +21,14 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'net/https'
-require 'uri'
-require 'chef/http/basic_client'
-require 'chef/http/socketless_chef_zero_client'
-require 'chef/monkey_patches/net_http'
-require 'chef/config'
-require 'chef/platform/query_helpers'
-require 'chef/exceptions'
+require "tempfile"
+require "net/https"
+require "uri"
+require "chef/http/basic_client"
+require "chef/monkey_patches/net_http"
+require "chef/config"
+require "chef/platform/query_helpers"
+require "chef/exceptions"
 
 class Chef
 
@@ -62,7 +61,6 @@ class Chef
 
     end
 
-
     def self.middlewares
       @middlewares ||= []
     end
@@ -75,18 +73,20 @@ class Chef
     attr_reader :sign_on_redirect
     attr_reader :redirect_limit
 
+    attr_reader :options
     attr_reader :middlewares
 
     # Create a HTTP client object. The supplied +url+ is used as the base for
     # all subsequent requests. For example, when initialized with a base url
     # http://localhost:4000, a call to +get+ with 'nodes' will make an
     # HTTP GET request to http://localhost:4000/nodes
-    def initialize(url, options={})
+    def initialize(url, options = {})
       @url = url
       @default_headers = options[:headers] || {}
       @sign_on_redirect = true
       @redirects_followed = 0
       @redirect_limit = 10
+      @options = options
 
       @middlewares = []
       self.class.middlewares.each do |middleware_class|
@@ -98,7 +98,7 @@ class Chef
     #
     # === Parameters
     # path:: path part of the request URL
-    def head(path, headers={})
+    def head(path, headers = {})
       request(:HEAD, path, headers)
     end
 
@@ -106,7 +106,7 @@ class Chef
     #
     # === Parameters
     # path:: The path to GET
-    def get(path, headers={})
+    def get(path, headers = {})
       request(:GET, path, headers)
     end
 
@@ -114,7 +114,7 @@ class Chef
     #
     # === Parameters
     # path:: path part of the request URL
-    def put(path, json, headers={})
+    def put(path, json, headers = {})
       request(:PUT, path, headers, json)
     end
 
@@ -122,7 +122,7 @@ class Chef
     #
     # === Parameters
     # path:: path part of the request URL
-    def post(path, json, headers={})
+    def post(path, json, headers = {})
       request(:POST, path, headers, json)
     end
 
@@ -130,13 +130,13 @@ class Chef
     #
     # === Parameters
     # path:: path part of the request URL
-    def delete(path, headers={})
+    def delete(path, headers = {})
       request(:DELETE, path, headers)
     end
 
     # Makes an HTTP request to +path+ with the given +method+, +headers+, and
     # +data+ (if applicable).
-    def request(method, path, headers={}, data=false)
+    def request(method, path, headers = {}, data = false)
       url = create_url(path)
       method, url, headers, data = apply_request_middleware(method, url, headers, data)
 
@@ -159,7 +159,7 @@ class Chef
     #
     # If no block is given, the tempfile is returned, which means it's up to
     # you to unlink the tempfile when you're done with it.
-    def streaming_request(path, headers={}, &block)
+    def streaming_request(path, headers = {}, &block)
       url = create_url(path)
       response, rest_request, return_value = nil, nil, nil
       tempfile = nil
@@ -195,9 +195,17 @@ class Chef
       raise
     end
 
-    def http_client(base_url=nil)
+    def http_client(base_url = nil)
       base_url ||= url
       if chef_zero_uri?(base_url)
+        # PERFORMANCE CRITICAL: *MUST* lazy require here otherwise we load up webrick
+        # via chef-zero and that hits DNS (at *require* time) which may timeout,
+        # when for most knife/chef-client work we never need/want this loaded.
+        Thread.exclusive {
+          unless defined?(SocketlessChefZeroClient)
+            require "chef/http/socketless_chef_zero_client"
+          end
+        }
         SocketlessChefZeroClient.new(base_url)
       else
         BasicClient.new(base_url, :ssl_policy => Chef::HTTP::APISSLPolicy)
@@ -216,7 +224,7 @@ class Chef
         # The regular expressions used here are to make sure '@url' does not have
         # any trailing slashes and 'path' does not have any leading slashes. This
         # way they are always joined correctly using just one slash.
-        URI.parse(@url.gsub(%r{/+$}, '') + '/' + path.gsub(%r{^/+}, ''))
+        URI.parse(@url.gsub(%r{/+$}, "") + "/" + path.gsub(%r{^/+}, ""))
       end
     end
 
@@ -263,7 +271,7 @@ class Chef
         if block_given?
           request, response = client.request(method, url, body, headers, &response_handler)
         else
-          request, response = client.request(method, url, body, headers) {|r| r.read_body }
+          request, response = client.request(method, url, body, headers) { |r| r.read_body }
           return_value = response.read_body
         end
         @last_response = response
@@ -275,7 +283,7 @@ class Chef
         elsif redirect_location = redirected_to(response)
           if [:GET, :HEAD].include?(method)
             follow_redirect do
-              send_http_request(method, url+redirect_location, headers, body, &response_handler)
+              send_http_request(method, url + redirect_location, headers, body, &response_handler)
             end
           else
             raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
@@ -286,7 +294,6 @@ class Chef
       end
     end
 
-
     # Wraps an HTTP request with retry logic.
     # === Arguments
     # url:: URL of the request, used for error messages
@@ -299,7 +306,7 @@ class Chef
           # handle HTTP 50X Error
           if response.kind_of?(Net::HTTPServerError) && !Chef::Config.local_mode
             if http_retry_count - http_attempts + 1 > 0
-              sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts)
+              sleep_time = 1 + (2**http_attempts) + rand(2**http_attempts)
               Chef::Log.error("Server returned error #{response.code} for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s")
               sleep(sleep_time)
               redo
@@ -307,7 +314,7 @@ class Chef
           end
           return [response, request, return_value]
         end
-      rescue SocketError, Errno::ETIMEDOUT => e
+      rescue SocketError, Errno::ETIMEDOUT, Errno::ECONNRESET => e
         if http_retry_count - http_attempts + 1 > 0
           Chef::Log.error("Error connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
           sleep(http_retry_delay)
@@ -329,6 +336,13 @@ class Chef
           retry
         end
         raise Timeout::Error, "Timeout connecting to #{url}, giving up"
+      rescue OpenSSL::SSL::SSLError => e
+        if (http_retry_count - http_attempts + 1 > 0) && !e.message.include?("certificate verify failed")
+          Chef::Log.error("SSL Error connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
+          sleep(http_retry_delay)
+          retry
+        end
+        raise OpenSSL::SSL::SSLError, "SSL Error connecting to #{url} - #{e.message}"
       end
     end
 
@@ -365,12 +379,12 @@ class Chef
       return nil  unless response.kind_of?(Net::HTTPRedirection)
       # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this
       return nil  if response.kind_of?(Net::HTTPNotModified)
-      response['location']
+      response["location"]
     end
 
-    def build_headers(method, url, headers={}, json_body=false)
+    def build_headers(method, url, headers = {}, json_body = false)
       headers                 = @default_headers.merge(headers)
-      headers['Content-Length'] = json_body.bytesize.to_s if json_body
+      headers["Content-Length"] = json_body.bytesize.to_s if json_body
       headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers]
       headers
     end
@@ -380,7 +394,7 @@ class Chef
       if Chef::Platform.windows?
         tf.binmode # required for binary files on Windows platforms
       end
-      Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}")
+      Chef::Log.debug("Streaming download from #{url} to tempfile #{tf.path}")
       # Stolen from http://www.ruby-forum.com/topic/166423
       # Kudos to _why!
 
@@ -396,7 +410,6 @@ class Chef
       raise
     end
 
-
     public
 
     ############################################################################
diff --git a/lib/chef/http/auth_credentials.rb b/lib/chef/http/auth_credentials.rb
index bd73524..d5dbff3 100644
--- a/lib/chef/http/auth_credentials.rb
+++ b/lib/chef/http/auth_credentials.rb
@@ -1,11 +1,11 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,15 +20,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/log'
-require 'mixlib/authentication/signedheaderauth'
+require "chef/log"
+require "mixlib/authentication/signedheaderauth"
 
 class Chef
   class HTTP
     class AuthCredentials
       attr_reader :client_name, :key
 
-      def initialize(client_name=nil, key=nil)
+      def initialize(client_name = nil, key = nil)
         @client_name, @key = client_name, key
       end
 
@@ -36,7 +36,7 @@ class Chef
         !!key
       end
 
-      def signature_headers(request_params={})
+      def signature_headers(request_params = {})
         raise ArgumentError, "Cannot sign the request without a client name, check that :node_name is assigned" if client_name.nil?
         Chef::Log.debug("Signing the request as #{client_name}")
 
@@ -48,8 +48,8 @@ class Chef
         host = request_params.delete(:host) || "localhost"
 
         sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(request_params)
-        signed =  sign_obj.sign(key).merge({:host => host})
-        signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo}
+        signed = sign_obj.sign(key).merge({ :host => host })
+        signed.inject({}) { |memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo }
       end
 
     end
diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb
index 4255f18..970c19c 100644
--- a/lib/chef/http/authenticator.rb
+++ b/lib/chef/http/authenticator.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/http/auth_credentials'
-require 'chef/exceptions'
-require 'openssl'
+require "chef/http/auth_credentials"
+require "chef/exceptions"
+require "openssl"
 
 class Chef
   class HTTP
     class Authenticator
 
+      DEFAULT_SERVER_API_VERSION = "1"
+
       attr_reader :signing_key_filename
       attr_reader :raw_key
       attr_reader :attr_names
@@ -31,16 +33,22 @@ class Chef
 
       attr_accessor :sign_request
 
-      def initialize(opts={})
+      def initialize(opts = {})
         @raw_key = nil
         @sign_request = true
         @signing_key_filename = opts[:signing_key_filename]
         @key = load_signing_key(opts[:signing_key_filename], opts[:raw_key])
         @auth_credentials = AuthCredentials.new(opts[:client_name], @key)
+        if opts[:api_version]
+          @api_version = opts[:api_version]
+        else
+          @api_version = DEFAULT_SERVER_API_VERSION
+        end
       end
 
-      def handle_request(method, url, headers={}, data=false)
-        headers.merge!(authentication_headers(method, url, data)) if sign_requests?
+      def handle_request(method, url, headers = {}, data = false)
+        headers.merge!({ "X-Ops-Server-API-Version" => @api_version })
+        headers.merge!(authentication_headers(method, url, data, headers)) if sign_requests?
         [method, url, headers, data]
       end
 
@@ -82,12 +90,17 @@ class Chef
         raise Chef::Exceptions::InvalidPrivateKey, msg
       end
 
-      def authentication_headers(method, url, json_body=nil)
-        request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"}
+      def authentication_headers(method, url, json_body = nil, headers = nil)
+        request_params = {
+          :http_method => method,
+          :path => url.path,
+          :body => json_body,
+          :host => "#{url.host}:#{url.port}",
+          :headers => headers,
+        }
         request_params[:body] ||= ""
         auth_credentials.signature_headers(request_params)
       end
-
     end
   end
 end
diff --git a/lib/chef/http/basic_client.rb b/lib/chef/http/basic_client.rb
index 076d152..9428858 100644
--- a/lib/chef/http/basic_client.rb
+++ b/lib/chef/http/basic_client.rb
@@ -1,11 +1,11 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'uri'
-require 'net/http'
-require 'chef/http/ssl_policies'
-require 'chef/http/http_request'
+require "uri"
+require "net/http"
+require "chef/http/ssl_policies"
+require "chef/http/http_request"
 
 class Chef
   class HTTP
@@ -40,7 +40,7 @@ class Chef
       # url:: An URI for the remote server.
       # === Options:
       # ssl_policy:: The SSL Policy to use, defaults to DefaultSSLPolicy
-      def initialize(url, opts={})
+      def initialize(url, opts = {})
         @url = url
         @ssl_policy = opts[:ssl_policy] || DefaultSSLPolicy
         @http_client = build_http_client
@@ -54,7 +54,7 @@ class Chef
         @url.port
       end
 
-      def request(method, url, req_body, base_headers={})
+      def request(method, url, req_body, base_headers = {})
         http_request = HTTPRequest.new(method, url, req_body, base_headers).http_request
         Chef::Log.debug("Initiating #{method} to #{url}")
         Chef::Log.debug("---- HTTP Request Header Data: ----")
@@ -72,7 +72,7 @@ class Chef
           Chef::Log.debug("---- End HTTP Status/Header Data ----")
 
           # For non-400's, log the request and response bodies
-          if !response.code || !response.code.start_with?('2')
+          if !response.code || !response.code.start_with?("2")
             if response.body
               Chef::Log.debug("---- HTTP Response Body ----")
               Chef::Log.debug(response.body)
@@ -101,13 +101,17 @@ class Chef
                 env["#{url.scheme.upcase}_PROXY"] || env["#{url.scheme}_proxy"]
 
         # Check if the proxy string contains a scheme. If not, add the url's scheme to the
-        # proxy before parsing. The regex /^.*:\/\// matches, for example, http://.
-        proxy = if proxy.match(/^.*:\/\//)
-          URI.parse(proxy)
-        else
-          URI.parse("#{url.scheme}://#{proxy}")
-        end if String === proxy
-        no_proxy = Chef::Config[:no_proxy] || env['NO_PROXY'] || env['no_proxy']
+        # proxy before parsing. The regex /^.*:\/\// matches, for example, http://. Reusing proxy
+        # here since we are really just trying to get the string built correctly.
+        if String === proxy && !proxy.strip.empty?
+          if proxy.match(/^.*:\/\//)
+            proxy = URI.parse(proxy.strip)
+          else
+            proxy = URI.parse("#{url.scheme}://#{proxy.strip}")
+          end
+        end
+
+        no_proxy = Chef::Config[:no_proxy] || env["NO_PROXY"] || env["no_proxy"]
         excludes = no_proxy.to_s.split(/\s*,\s*/).compact
         excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
         return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
@@ -147,12 +151,12 @@ class Chef
 
       def http_proxy_user(http_proxy)
         http_proxy.user || Chef::Config["#{url.scheme}_proxy_user"] ||
-        env["#{url.scheme.upcase}_PROXY_USER"] || env["#{url.scheme}_proxy_user"]
+          env["#{url.scheme.upcase}_PROXY_USER"] || env["#{url.scheme}_proxy_user"]
       end
 
       def http_proxy_pass(http_proxy)
         http_proxy.password || Chef::Config["#{url.scheme}_proxy_pass"] ||
-        env["#{url.scheme.upcase}_PROXY_PASS"] || env["#{url.scheme}_proxy_pass"]
+          env["#{url.scheme.upcase}_PROXY_PASS"] || env["#{url.scheme}_proxy_pass"]
       end
 
       def configure_ssl(http_client)
diff --git a/lib/chef/http/cookie_jar.rb b/lib/chef/http/cookie_jar.rb
index 418fb1d..4908fde 100644
--- a/lib/chef/http/cookie_jar.rb
+++ b/lib/chef/http/cookie_jar.rb
@@ -1,11 +1,11 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'singleton'
+require "singleton"
 
 class Chef
   class HTTP
diff --git a/lib/chef/http/cookie_manager.rb b/lib/chef/http/cookie_manager.rb
index e9cb7aa..18824a8 100644
--- a/lib/chef/http/cookie_manager.rb
+++ b/lib/chef/http/cookie_manager.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/http/cookie_jar'
+require "chef/http/cookie_jar"
 
 class Chef
   class HTTP
@@ -27,21 +27,21 @@ class Chef
     # it, so it's included with Chef::REST
     class CookieManager
 
-      def initialize(options={})
+      def initialize(options = {})
         @cookies = CookieJar.instance
       end
 
-      def handle_request(method, url, headers={}, data=false)
+      def handle_request(method, url, headers = {}, data = false)
         @host, @port = url.host, url.port
         if @cookies.has_key?("#{@host}:#{@port}")
-          headers['Cookie'] = @cookies["#{@host}:#{@port}"]
+          headers["Cookie"] = @cookies["#{@host}:#{@port}"]
         end
         [method, url, headers, data]
       end
 
       def handle_response(http_response, rest_request, return_value)
-        if http_response['set-cookie']
-          @cookies["#{@host}:#{@port}"] = http_response['set-cookie']
+        if http_response["set-cookie"]
+          @cookies["#{@host}:#{@port}"] = http_response["set-cookie"]
         end
         [http_response, rest_request, return_value]
       end
diff --git a/lib/chef/http/decompressor.rb b/lib/chef/http/decompressor.rb
index e1d776d..1bba4cc 100644
--- a/lib/chef/http/decompressor.rb
+++ b/lib/chef/http/decompressor.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'zlib'
-require 'chef/http/http_request'
+require "zlib"
+require "chef/http/http_request"
 
 class Chef
   class HTTP
@@ -50,12 +50,12 @@ class Chef
       DEFLATE           = "deflate".freeze
       IDENTITY          = "identity".freeze
 
-      def initialize(opts={})
+      def initialize(opts = {})
         @disable_gzip = false
         handle_options(opts)
       end
 
-      def handle_request(method, url, headers={}, data=false)
+      def handle_request(method, url, headers = {}, data = false)
         headers[HTTPRequest::ACCEPT_ENCODING] = HTTPRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
         [method, url, headers, data]
       end
@@ -79,10 +79,10 @@ class Chef
         else
           case response[CONTENT_ENCODING]
           when GZIP
-            Chef::Log.debug "decompressing gzip response"
+            Chef::Log.debug "Decompressing gzip response"
             Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body)
           when DEFLATE
-            Chef::Log.debug "decompressing deflate response"
+            Chef::Log.debug "Decompressing deflate response"
             Zlib::Inflate.inflate(response.body)
           else
             response.body
@@ -114,7 +114,6 @@ class Chef
         end
       end
 
-
       # gzip is disabled using the disable_gzip => true option in the
       # constructor. When gzip is disabled, no 'Accept-Encoding' header will be
       # set, and the response will not be decompressed, no matter what the
@@ -132,13 +131,12 @@ class Chef
       def handle_options(opts)
         opts.each do |name, value|
           case name.to_s
-          when 'disable_gzip'
+          when "disable_gzip"
             @disable_gzip = value
           end
         end
       end
 
-
     end
   end
 end
diff --git a/lib/chef/http/http_request.rb b/lib/chef/http/http_request.rb
index 7582f44..a1ef9b9 100644
--- a/lib/chef/http/http_request.rb
+++ b/lib/chef/http/http_request.rb
@@ -1,11 +1,11 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, 2010-2016 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,19 +20,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'uri'
-require 'net/http'
+require "uri"
+require "net/http"
 
 # To load faster, we only want ohai's version string.
 # However, in ohai before 0.6.0, the version is defined
 # in ohai, not ohai/version
 begin
-  require 'ohai/version' #used in user agent string.
+  require "ohai/version" #used in user agent string.
 rescue LoadError
-  require 'ohai'
+  require "ohai"
 end
 
-require 'chef/version'
+require "chef/version"
 
 class Chef
   class HTTP
@@ -40,7 +40,7 @@ class Chef
 
       engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
 
-      UA_COMMON = "/#{::Chef::VERSION} (#{engine}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; ohai-#{Ohai::VERSION}; #{RUBY_PLATFORM}; +http://opscode.com)"
+      UA_COMMON = "/#{::Chef::VERSION} (#{engine}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; ohai-#{Ohai::VERSION}; #{RUBY_PLATFORM}; +https://chef.io)"
       DEFAULT_UA = "Chef Client" << UA_COMMON
 
       USER_AGENT = "User-Agent".freeze
@@ -60,7 +60,7 @@ class Chef
 
       HOST_LOWER = "host".freeze
 
-      URI_SCHEME_DEFAULT_PORT = { 'http'  => 80, 'https' => 443 }.freeze
+      URI_SCHEME_DEFAULT_PORT = { "http"  => 80, "https" => 443 }.freeze
 
       def self.user_agent=(ua)
         @user_agent = ua
@@ -72,7 +72,7 @@ class Chef
 
       attr_reader :method, :url, :headers, :http_client, :http_request
 
-      def initialize(method, url, req_body, base_headers={})
+      def initialize(method, url, req_body, base_headers = {})
         @method, @url = method, url
         @request_body = nil
         build_headers(base_headers)
@@ -125,9 +125,9 @@ class Chef
       rescue NoMethodError => e
         # http://redmine.ruby-lang.org/issues/show/2708
         # http://redmine.ruby-lang.org/issues/show/2758
-        if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/
+        if e.to_s =~ /#{Regexp.escape(%q{undefined method `closed?' for nil:NilClass})}/
           Chef::Log.debug("Rescued error in http connect, re-raising as Errno::ECONNREFUSED to hide bug in net/http")
-          Chef::Log.debug("#{e.class.name}: #{e.to_s}")
+          Chef::Log.debug("#{e.class.name}: #{e}")
           Chef::Log.debug(e.backtrace.join("\n"))
           raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{url.scheme}://#{host}:#{port}"
         else
@@ -139,36 +139,35 @@ class Chef
         @headers = headers.dup
         # No response compression unless we asked for it explicitly:
         @headers[HTTPRequest::ACCEPT_ENCODING] ||= "identity"
-        @headers['X-Chef-Version'] = ::Chef::VERSION
+        @headers["X-Chef-Version"] = ::Chef::VERSION
 
         # Only include port in Host header when it is not the default port
         # for the url scheme (80;443) - Fixes CHEF-5355
         host_header = uri_safe_host.dup
         host_header << ":#{port}" unless URI_SCHEME_DEFAULT_PORT[@url.scheme] == port.to_i
-        @headers['Host'] = host_header unless @headers.keys.any? {|k| k.downcase.to_s == HOST_LOWER }
+        @headers["Host"] = host_header unless @headers.keys.any? { |k| k.downcase.to_s == HOST_LOWER }
 
         @headers
       end
 
-
-      def configure_http_request(request_body=nil)
+      def configure_http_request(request_body = nil)
         req_path = "#{path}"
         req_path << "?#{query}" if query
 
         @http_request = case method.to_s.downcase
-        when GET
-          Net::HTTP::Get.new(req_path, headers)
-        when POST
-          Net::HTTP::Post.new(req_path, headers)
-        when PUT
-          Net::HTTP::Put.new(req_path, headers)
-        when DELETE
-          Net::HTTP::Delete.new(req_path, headers)
-        when HEAD
-          Net::HTTP::Head.new(req_path, headers)
-        else
-          raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method"
-        end
+                        when GET
+                          Net::HTTP::Get.new(req_path, headers)
+                        when POST
+                          Net::HTTP::Post.new(req_path, headers)
+                        when PUT
+                          Net::HTTP::Put.new(req_path, headers)
+                        when DELETE
+                          Net::HTTP::Delete.new(req_path, headers)
+                        when HEAD
+                          Net::HTTP::Head.new(req_path, headers)
+                        else
+                          raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method"
+                        end
 
         @http_request.body = request_body if (request_body && @http_request.request_body_permitted?)
         # Optionally handle HTTP Basic Authentication
diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb
index 23ccc3a..eaee96d 100644
--- a/lib/chef/http/json_input.rb
+++ b/lib/chef/http/json_input.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
+require "chef/json_compat"
 
 class Chef
   class HTTP
@@ -25,14 +25,19 @@ class Chef
     # Middleware that takes json input and turns it into raw text
     class JSONInput
 
-      def initialize(opts={})
+      attr_accessor :opts
+
+      def initialize(opts = {})
+        @opts = opts
       end
 
-      def handle_request(method, url, headers={}, data=false)
+      def handle_request(method, url, headers = {}, data = false)
         if data && should_encode_as_json?(headers)
-          headers.delete_if { |key, _value| key.downcase == 'content-type' }
-          headers["Content-Type"] = 'application/json'
-          data = Chef::JSONCompat.to_json(data)
+          headers.delete_if { |key, _value| key.downcase == "content-type" }
+          headers["Content-Type"] = "application/json"
+          json_opts = {}
+          json_opts[:validate_utf8] = opts[:validate_utf8] if opts.has_key?(:validate_utf8)
+          data = Chef::JSONCompat.to_json(data, json_opts)
           # Force encoding to binary to fix SSL related EOFErrors
           # cf. http://tickets.opscode.com/browse/CHEF-2363
           # http://redmine.ruby-lang.org/issues/5233
@@ -59,7 +64,7 @@ class Chef
         # ruby/Net::HTTP don't enforce capitalized headers (it normalizes them
         # for you before sending the request), so we have to account for all
         # the variations we might find
-        requested_content_type = headers.find {|k, v| k.downcase == "content-type" }
+        requested_content_type = headers.find { |k, v| k.downcase == "content-type" }
         requested_content_type.nil? || requested_content_type.last.include?("json")
       end
 
diff --git a/lib/chef/http/json_output.rb b/lib/chef/http/json_output.rb
index 069eb6a..6053c38 100644
--- a/lib/chef/http/json_output.rb
+++ b/lib/chef/http/json_output.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
-require 'chef/log'
+require "chef/json_compat"
+require "chef/log"
 
 class Chef
   class HTTP
@@ -29,16 +29,16 @@ class Chef
       attr_accessor :raw_output
       attr_accessor :inflate_json_class
 
-      def initialize(opts={})
+      def initialize(opts = {})
         @raw_output = opts[:raw_output]
         @inflate_json_class = opts[:inflate_json_class]
       end
 
-      def handle_request(method, url, headers={}, data=false)
+      def handle_request(method, url, headers = {}, data = false)
         # Ideally this should always set Accept to application/json, but
         # Chef::REST is sometimes used to make non-JSON requests, so it sets
         # Accept to the desired value before middlewares get called.
-        headers['Accept'] ||= 'application/json'
+        headers["Accept"] ||= "application/json"
         [method, url, headers, data]
       end
 
@@ -46,7 +46,7 @@ class Chef
         # temporary hack, skip processing if return_value is false
         # needed to keep conditional get stuff working correctly.
         return [http_response, rest_request, return_value] if return_value == false
-        if http_response['content-type'] =~ /json/
+        if http_response["content-type"] =~ /json/
           if http_response.body.nil?
             return_value = nil
           elsif raw_output
diff --git a/lib/chef/http/json_to_model_output.rb b/lib/chef/http/json_to_model_output.rb
index 9bc90a5..12ca1a9 100644
--- a/lib/chef/http/json_to_model_output.rb
+++ b/lib/chef/http/json_to_model_output.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/http/json_output'
+require "chef/http/json_output"
 
 class Chef
   class HTTP
@@ -25,7 +25,7 @@ class Chef
     # possible, and converts it into an appropriate model object if it contains
     # a `json_class` key.
     class JSONToModelOutput < JSONOutput
-      def initialize(opts={})
+      def initialize(opts = {})
         opts[:inflate_json_class] = true if !opts.has_key?(:inflate_json_class)
         super
       end
diff --git a/lib/chef/http/remote_request_id.rb b/lib/chef/http/remote_request_id.rb
index 6bec5db..ef8a18a 100644
--- a/lib/chef/http/remote_request_id.rb
+++ b/lib/chef/http/remote_request_id.rb
@@ -1,5 +1,5 @@
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013, 2014 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,17 +15,17 @@
 # limitations under the License.
 #
 
-require 'chef/request_id'
+require "chef/request_id"
 
 class Chef
   class HTTP
     class RemoteRequestID
 
-      def initialize(opts={})
+      def initialize(opts = {})
       end
 
-      def handle_request(method, url, headers={}, data=false)
-        headers.merge!({'X-REMOTE-REQUEST-ID' => Chef::RequestID.instance.request_id})
+      def handle_request(method, url, headers = {}, data = false)
+        headers.merge!({ "X-REMOTE-REQUEST-ID" => Chef::RequestID.instance.request_id })
         [method, url, headers, data]
       end
 
diff --git a/lib/chef/http/simple.rb b/lib/chef/http/simple.rb
index 8519554..bdbc31c 100644
--- a/lib/chef/http/simple.rb
+++ b/lib/chef/http/simple.rb
@@ -1,8 +1,26 @@
-require 'chef/http'
-require 'chef/http/authenticator'
-require 'chef/http/decompressor'
-require 'chef/http/cookie_manager'
-require 'chef/http/validate_content_length'
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
 
 class Chef
   class HTTP
diff --git a/lib/chef/http/simple_json.rb b/lib/chef/http/simple_json.rb
new file mode 100644
index 0000000..7357d85
--- /dev/null
+++ b/lib/chef/http/simple_json.rb
@@ -0,0 +1,43 @@
+#
+# Author:: Thom May (<thom at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
+
+class Chef
+  class HTTP
+
+    class SimpleJSON < HTTP
+
+      use JSONInput
+      use JSONOutput
+      use CookieManager
+      use Decompressor
+      use RemoteRequestID
+
+      # ValidateContentLength should come after Decompressor
+      # because the order of middlewares is reversed when handling
+      # responses.
+      use ValidateContentLength
+
+    end
+  end
+end
diff --git a/lib/chef/http/socketless_chef_zero_client.rb b/lib/chef/http/socketless_chef_zero_client.rb
index 8f5543a..c859090 100644
--- a/lib/chef/http/socketless_chef_zero_client.rb
+++ b/lib/chef/http/socketless_chef_zero_client.rb
@@ -1,6 +1,6 @@
 #--
 # Author:: Daniel DeLeo (<dan at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,7 @@
 # fakeweb is distributed under the MIT license, which is copied below:
 # ---
 #
-# Copyright 2006-2010 Blaine Cook, Chris Kampmeier, and other contributors
+# Copyright 2006-2016, Blaine Cook, Chris Kampmeier, and other contributors
 #
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
@@ -43,7 +43,7 @@
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-require 'chef_zero/server'
+require "chef_zero/server"
 
 class Chef
   class HTTP
@@ -81,59 +81,59 @@ class Chef
       #
       # HTTP status codes and descriptions
       STATUS_MESSAGE = {
-        100 => 'Continue',
-        101 => 'Switching Protocols',
-        200 => 'OK',
-        201 => 'Created',
-        202 => 'Accepted',
-        203 => 'Non-Authoritative Information',
-        204 => 'No Content',
-        205 => 'Reset Content',
-        206 => 'Partial Content',
-        207 => 'Multi-Status',
-        300 => 'Multiple Choices',
-        301 => 'Moved Permanently',
-        302 => 'Found',
-        303 => 'See Other',
-        304 => 'Not Modified',
-        305 => 'Use Proxy',
-        307 => 'Temporary Redirect',
-        400 => 'Bad Request',
-        401 => 'Unauthorized',
-        402 => 'Payment Required',
-        403 => 'Forbidden',
-        404 => 'Not Found',
-        405 => 'Method Not Allowed',
-        406 => 'Not Acceptable',
-        407 => 'Proxy Authentication Required',
-        408 => 'Request Timeout',
-        409 => 'Conflict',
-        410 => 'Gone',
-        411 => 'Length Required',
-        412 => 'Precondition Failed',
-        413 => 'Request Entity Too Large',
-        414 => 'Request-URI Too Large',
-        415 => 'Unsupported Media Type',
-        416 => 'Request Range Not Satisfiable',
-        417 => 'Expectation Failed',
-        422 => 'Unprocessable Entity',
-        423 => 'Locked',
-        424 => 'Failed Dependency',
-        426 => 'Upgrade Required',
-        428 => 'Precondition Required',
-        429 => 'Too Many Requests',
-        431 => 'Request Header Fields Too Large',
-        500 => 'Internal Server Error',
-        501 => 'Not Implemented',
-        502 => 'Bad Gateway',
-        503 => 'Service Unavailable',
-        504 => 'Gateway Timeout',
-        505 => 'HTTP Version Not Supported',
-        507 => 'Insufficient Storage',
-        511 => 'Network Authentication Required',
+        100 => "Continue",
+        101 => "Switching Protocols",
+        200 => "OK",
+        201 => "Created",
+        202 => "Accepted",
+        203 => "Non-Authoritative Information",
+        204 => "No Content",
+        205 => "Reset Content",
+        206 => "Partial Content",
+        207 => "Multi-Status",
+        300 => "Multiple Choices",
+        301 => "Moved Permanently",
+        302 => "Found",
+        303 => "See Other",
+        304 => "Not Modified",
+        305 => "Use Proxy",
+        307 => "Temporary Redirect",
+        400 => "Bad Request",
+        401 => "Unauthorized",
+        402 => "Payment Required",
+        403 => "Forbidden",
+        404 => "Not Found",
+        405 => "Method Not Allowed",
+        406 => "Not Acceptable",
+        407 => "Proxy Authentication Required",
+        408 => "Request Timeout",
+        409 => "Conflict",
+        410 => "Gone",
+        411 => "Length Required",
+        412 => "Precondition Failed",
+        413 => "Request Entity Too Large",
+        414 => "Request-URI Too Large",
+        415 => "Unsupported Media Type",
+        416 => "Request Range Not Satisfiable",
+        417 => "Expectation Failed",
+        422 => "Unprocessable Entity",
+        423 => "Locked",
+        424 => "Failed Dependency",
+        426 => "Upgrade Required",
+        428 => "Precondition Required",
+        429 => "Too Many Requests",
+        431 => "Request Header Fields Too Large",
+        500 => "Internal Server Error",
+        501 => "Not Implemented",
+        502 => "Bad Gateway",
+        503 => "Service Unavailable",
+        504 => "Gateway Timeout",
+        505 => "HTTP Version Not Supported",
+        507 => "Insufficient Storage",
+        511 => "Network Authentication Required",
       }
 
-      STATUS_MESSAGE.values.each {|v| v.freeze }
+      STATUS_MESSAGE.values.each { |v| v.freeze }
       STATUS_MESSAGE.freeze
 
       def initialize(base_url)
@@ -175,7 +175,7 @@ class Chef
       end
 
       def to_net_http(code, headers, chunked_body)
-        body = chunked_body.join('')
+        body = chunked_body.join("")
         msg = STATUS_MESSAGE[code] or raise "Cannot determine HTTP status message for code #{code}"
         response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg)
         response.instance_variable_set(:@body, body)
@@ -195,12 +195,11 @@ class Chef
       private
 
       def headers_extracted_from_options
-        options.reject {|name, _| KNOWN_OPTIONS.include?(name) }.map { |name, value|
+        options.reject { |name, _| KNOWN_OPTIONS.include?(name) }.map { |name, value|
           [name.to_s.split("_").map { |segment| segment.capitalize }.join("-"), value]
         }
       end
 
-
     end
 
   end
diff --git a/lib/chef/http/ssl_policies.rb b/lib/chef/http/ssl_policies.rb
index 9c180c1..f49fca0 100644
--- a/lib/chef/http/ssl_policies.rb
+++ b/lib/chef/http/ssl_policies.rb
@@ -1,11 +1,11 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@
 # limitations under the License.
 #
 
-require 'openssl'
-require 'chef/util/path_helper'
+require "openssl"
+require "chef/util/path_helper"
 
 class Chef
   class HTTP
@@ -110,7 +110,7 @@ class Chef
       def add_trusted_cert(cert)
         http_client.cert_store.add_cert(cert)
       rescue OpenSSL::X509::StoreError => e
-        raise e unless e.message == 'cert already in hash table'
+        raise e unless e.message == "cert already in hash table"
       end
 
     end
diff --git a/lib/chef/http/validate_content_length.rb b/lib/chef/http/validate_content_length.rb
index 076194e..33b6d5a 100644
--- a/lib/chef/http/validate_content_length.rb
+++ b/lib/chef/http/validate_content_length.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2013 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'pp'
-require 'chef/log'
+require "pp"
+require "chef/log"
 
 class Chef
   class HTTP
@@ -41,10 +41,10 @@ class Chef
         end
       end
 
-      def initialize(opts={})
+      def initialize(opts = {})
       end
 
-      def handle_request(method, url, headers={}, data=false)
+      def handle_request(method, url, headers = {}, data = false)
         [method, url, headers, data]
       end
 
@@ -73,18 +73,18 @@ class Chef
       private
 
       def response_content_length(response)
-        return nil if response['content-length'].nil?
-        if response['content-length'].is_a?(Array)
-          response['content-length'].first.to_i
+        return nil if response["content-length"].nil?
+        if response["content-length"].is_a?(Array)
+          response["content-length"].first.to_i
         else
-          response['content-length'].to_i
+          response["content-length"].to_i
         end
       end
 
       def validate(http_response, response_length)
         content_length    = response_content_length(http_response)
-        transfer_encoding = http_response['transfer-encoding']
-        content_encoding  = http_response['content-encoding']
+        transfer_encoding = http_response["transfer-encoding"]
+        content_encoding  = http_response["content-encoding"]
 
         if content_length.nil?
           Chef::Log.debug "HTTP server did not include a Content-Length header in response, cannot identify truncated downloads."
diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb
index d0b3b4c..26d3751 100644
--- a/lib/chef/json_compat.rb
+++ b/lib/chef/json_compat.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 
 # Wrapper class for interacting with JSON.
 
-require 'ffi_yajl'
-require 'chef/exceptions'
+require "ffi_yajl"
+require "chef/exceptions"
 # We're requiring this to prevent breaking consumers using Hash.to_json
-require 'json'
+require "json"
 
 class Chef
   class JSONCompat
@@ -41,6 +41,7 @@ class Chef
     CHEF_RESOURCECOLLECTION = "Chef::ResourceCollection".freeze
     CHEF_RESOURCESET        = "Chef::ResourceCollection::ResourceSet".freeze
     CHEF_RESOURCELIST       = "Chef::ResourceCollection::ResourceList".freeze
+    CHEF_RUNLISTEXPANSION   = "Chef::RunListExpansion".freeze
 
     class <<self
 
@@ -87,7 +88,7 @@ class Chef
             mapped_hash
           end
         when Array
-          json_obj.map {|e| map_to_rb_obj(e) }
+          json_obj.map { |e| map_to_rb_obj(e) }
         else
           json_obj
         end
diff --git a/lib/chef/key.rb b/lib/chef/key.rb
new file mode 100644
index 0000000..ef29bd7
--- /dev/null
+++ b/lib/chef/key.rb
@@ -0,0 +1,273 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/json_compat"
+require "chef/mixin/params_validate"
+require "chef/exceptions"
+require "chef/server_api"
+
+class Chef
+  # Class for interacting with a chef key object. Can be used to create new keys,
+  # save to server, load keys from server, list keys, delete keys, etc.
+  #
+  # @author Tyler Cloke
+  #
+  # @attr [String] actor           the name of the client or user that this key is for
+  # @attr [String] name            the name of the key
+  # @attr [String] public_key      the RSA string of this key
+  # @attr [String] private_key     the RSA string of the private key if returned via a POST or PUT
+  # @attr [String] expiration_date the ISO formatted string YYYY-MM-DDTHH:MM:SSZ, i.e. 2020-12-24T21:00:00Z
+  # @attr [String] rest            Chef::ServerAPI object, initialized and cached via chef_rest method
+  # @attr [string] api_base        either "users" or "clients", initialized and cached via api_base method
+  #
+  # @attr_reader [String] actor_field_name must be either 'client' or 'user'
+  class Key
+
+    include Chef::Mixin::ParamsValidate
+
+    attr_reader :actor_field_name
+
+    def initialize(actor, actor_field_name)
+      # Actor that the key is for, either a client or a user.
+      @actor = actor
+
+      unless actor_field_name == "user" || actor_field_name == "client"
+        raise Chef::Exceptions::InvalidKeyArgument, "the second argument to initialize must be either 'user' or 'client'"
+      end
+
+      @actor_field_name = actor_field_name
+
+      @name = nil
+      @public_key = nil
+      @private_key = nil
+      @expiration_date = nil
+      @create_key = nil
+    end
+
+    def chef_rest
+      @rest ||= if @actor_field_name == "user"
+                  Chef::ServerAPI.new(Chef::Config[:chef_server_root])
+                else
+                  Chef::ServerAPI.new(Chef::Config[:chef_server_url])
+                end
+    end
+
+    def api_base
+      @api_base ||= if @actor_field_name == "user"
+                      "users"
+                    else
+                      "clients"
+                    end
+    end
+
+    def actor(arg = nil)
+      set_or_return(:actor, arg,
+                    :regex => /^[a-z0-9\-_]+$/)
+    end
+
+    def name(arg = nil)
+      set_or_return(:name, arg,
+                    :kind_of => String)
+    end
+
+    def public_key(arg = nil)
+      raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set the public_key if create_key is true" if !arg.nil? && @create_key
+      set_or_return(:public_key, arg,
+                    :kind_of => String)
+    end
+
+    def private_key(arg = nil)
+      set_or_return(:private_key, arg,
+                    :kind_of => String)
+    end
+
+    def delete_public_key
+      @public_key = nil
+    end
+
+    def delete_create_key
+      @create_key = nil
+    end
+
+    def create_key(arg = nil)
+      raise Chef::Exceptions::InvalidKeyAttribute, "you cannot set create_key to true if the public_key field exists" if arg == true && !@public_key.nil?
+      set_or_return(:create_key, arg,
+                    :kind_of => [TrueClass, FalseClass])
+    end
+
+    def expiration_date(arg = nil)
+      set_or_return(:expiration_date, arg,
+                    :regex => /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z|infinity)$/)
+    end
+
+    def to_hash
+      result = {
+        @actor_field_name => @actor
+      }
+      result["name"] = @name if @name
+      result["public_key"] = @public_key if @public_key
+      result["private_key"] = @private_key if @private_key
+      result["expiration_date"] = @expiration_date if @expiration_date
+      result["create_key"] = @create_key if @create_key
+      result
+    end
+
+    def to_json(*a)
+      Chef::JSONCompat.to_json(to_hash, *a)
+    end
+
+    def create
+      # if public_key is undefined and create_key is false, we cannot create
+      if @public_key.nil? && !@create_key
+        raise Chef::Exceptions::MissingKeyAttribute, "either public_key must be defined or create_key must be true"
+      end
+
+      # defaults the key name to the fingerprint of the key
+      if @name.nil?
+        # if they didn't pass a public_key,
+        #then they must supply a name because we can't generate a fingerprint
+        unless @public_key.nil?
+          @name = fingerprint
+        else
+          raise Chef::Exceptions::MissingKeyAttribute, "a name cannot be auto-generated if no public key passed, either pass a public key or supply a name"
+        end
+      end
+
+      payload = { "name" => @name }
+      payload["public_key"] = @public_key unless @public_key.nil?
+      payload["create_key"] = @create_key if @create_key
+      payload["expiration_date"] = @expiration_date unless @expiration_date.nil?
+      result = chef_rest.post("#{api_base}/#{@actor}/keys", payload)
+      # append the private key to the current key if the server returned one,
+      # since the POST endpoint just returns uri and private_key if needed.
+      new_key = self.to_hash
+      new_key["private_key"] = result["private_key"] if result["private_key"]
+      Chef::Key.from_hash(new_key)
+    end
+
+    def fingerprint
+      self.class.generate_fingerprint(@public_key)
+    end
+
+    # set @name and pass put_name if you wish to update the name of an existing key put_name to @name
+    def update(put_name = nil)
+      if @name.nil? && put_name.nil?
+        raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated or you must pass a name to update when update is called"
+      end
+
+      # If no name was passed, fall back to using @name in the PUT URL, otherwise
+      # use the put_name passed. This will update the a key by the name put_name
+      # to @name.
+      put_name = @name if put_name.nil?
+
+      new_key = chef_rest.put("#{api_base}/#{@actor}/keys/#{put_name}", to_hash)
+      # if the server returned a public_key, remove the create_key field, as we now have a key
+      if new_key["public_key"]
+        self.delete_create_key
+      end
+      Chef::Key.from_hash(self.to_hash.merge(new_key))
+    end
+
+    def save
+      create
+    rescue Net::HTTPServerException => e
+      if e.response.code == "409"
+        update
+      else
+        raise e
+      end
+    end
+
+    def destroy
+      if @name.nil?
+        raise Chef::Exceptions::MissingKeyAttribute, "the name field must be populated when delete is called"
+      end
+
+      chef_rest.delete("#{api_base}/#{@actor}/keys/#{@name}")
+    end
+
+    # Class methods
+    def self.from_hash(key_hash)
+      if key_hash.has_key?("user")
+        key = Chef::Key.new(key_hash["user"], "user")
+      elsif key_hash.has_key?("client")
+        key = Chef::Key.new(key_hash["client"], "client")
+      else
+        raise Chef::Exceptions::MissingKeyAttribute, "The hash passed to from_hash does not contain the key 'user' or 'client'. Please pass a hash that defines one of those keys."
+      end
+      key.name key_hash["name"] if key_hash.key?("name")
+      key.public_key key_hash["public_key"] if key_hash.key?("public_key")
+      key.private_key key_hash["private_key"] if key_hash.key?("private_key")
+      key.create_key key_hash["create_key"] if key_hash.key?("create_key")
+      key.expiration_date key_hash["expiration_date"] if key_hash.key?("expiration_date")
+      key
+    end
+
+    def self.from_json(json)
+      Chef::Key.from_hash(Chef::JSONCompat.from_json(json))
+    end
+
+    def self.json_create(json)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Key#from_json or one of the load_by methods.")
+      Chef::Key.from_json(json)
+    end
+
+    def self.list_by_user(actor, inflate = false)
+      keys = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("users/#{actor}/keys")
+      self.list(keys, actor, :load_by_user, inflate)
+    end
+
+    def self.list_by_client(actor, inflate = false)
+      keys = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("clients/#{actor}/keys")
+      self.list(keys, actor, :load_by_client, inflate)
+    end
+
+    def self.load_by_user(actor, key_name)
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("users/#{actor}/keys/#{key_name}")
+      Chef::Key.from_hash(response.merge({ "user" => actor }))
+    end
+
+    def self.load_by_client(actor, key_name)
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("clients/#{actor}/keys/#{key_name}")
+      Chef::Key.from_hash(response.merge({ "client" => actor }))
+    end
+
+    def self.generate_fingerprint(public_key)
+      openssl_key_object = OpenSSL::PKey::RSA.new(public_key)
+      data_string = OpenSSL::ASN1::Sequence([
+                                              OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.n),
+                                              OpenSSL::ASN1::Integer.new(openssl_key_object.public_key.e),
+                                            ])
+      OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(":")
+    end
+
+    private
+
+    def self.list(keys, actor, load_method_symbol, inflate)
+      if inflate
+        keys.inject({}) do |key_map, result|
+          name = result["name"]
+          key_map[name] = Chef::Key.send(load_method_symbol, actor, name)
+          key_map
+        end
+      else
+        keys
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 2e0694a..164a2cd 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,22 +17,25 @@
 # limitations under the License.
 #
 
-require 'forwardable'
-require 'chef/version'
-require 'mixlib/cli'
-require 'chef/workstation_config_loader'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/path_sanity'
-require 'chef/knife/core/subcommand_loader'
-require 'chef/knife/core/ui'
-require 'chef/local_mode'
-require 'chef/rest'
-require 'pp'
+require "forwardable"
+require "chef/version"
+require "mixlib/cli"
+require "chef/workstation_config_loader"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/path_sanity"
+require "chef/knife/core/subcommand_loader"
+require "chef/knife/core/ui"
+require "chef/local_mode"
+require "chef/server_api"
+require "chef/http/authenticator"
+require "chef/http/http_request"
+require "chef/http"
+require "pp"
 
 class Chef
   class Knife
 
-    Chef::REST::RESTRequest.user_agent = "Chef Knife#{Chef::REST::RESTRequest::UA_COMMON}"
+    Chef::HTTP::HTTPRequest.user_agent = "Chef Knife#{Chef::HTTP::HTTPRequest::UA_COMMON}"
 
     include Mixlib::CLI
     include Chef::Mixin::PathSanity
@@ -69,7 +72,7 @@ class Chef
       @ui ||= Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
     end
 
-    def self.msg(msg="")
+    def self.msg(msg = "")
       ui.msg(msg)
     end
 
@@ -86,6 +89,16 @@ class Chef
     def self.inherited(subclass)
       unless subclass.unnamed?
         subcommands[subclass.snake_case_name] = subclass
+        subcommand_files[subclass.snake_case_name] +=
+          if subclass.superclass.to_s == "Chef::ChefFS::Knife"
+            # ChefFS-based commands have a superclass that defines an
+            # inhereited method which calls super. This means that the
+            # top of the call stack is not the class definition for
+            # our subcommand.  Try the second entry in the call stack.
+            [path_from_caller(caller[1])]
+          else
+            [path_from_caller(caller[0])]
+          end
       end
     end
 
@@ -103,15 +116,15 @@ class Chef
     end
 
     def self.subcommand_category
-      @category || snake_case_name.split('_').first unless unnamed?
+      @category || snake_case_name.split("_").first unless unnamed?
     end
 
     def self.snake_case_name
-      convert_to_snake_case(name.split('::').last) unless unnamed?
+      convert_to_snake_case(name.split("::").last) unless unnamed?
     end
 
     def self.common_name
-      snake_case_name.split('_').join(' ')
+      snake_case_name.split("_").join(" ")
     end
 
     # Does this class have a name? (Classes created via Class.new don't)
@@ -120,17 +133,29 @@ class Chef
     end
 
     def self.subcommand_loader
-      @subcommand_loader ||= Knife::SubcommandLoader.new(chef_config_dir)
+      @subcommand_loader ||= Chef::Knife::SubcommandLoader.for_config(chef_config_dir)
     end
 
     def self.load_commands
       @commands_loaded ||= subcommand_loader.load_commands
     end
 
+    def self.guess_category(args)
+      subcommand_loader.guess_category(args)
+    end
+
+    def self.subcommand_class_from(args)
+      subcommand_loader.command_class_from(args) || subcommand_not_found!(args)
+    end
+
     def self.subcommands
       @@subcommands ||= {}
     end
 
+    def self.subcommand_files
+      @@subcommand_files ||= Hash.new([])
+    end
+
     def self.subcommands_by_category
       unless @subcommands_by_category
         @subcommands_by_category = Hash.new { |hash, key| hash[key] = [] }
@@ -141,30 +166,6 @@ class Chef
       @subcommands_by_category
     end
 
-    # Print the list of subcommands knife knows about. If +preferred_category+
-    # is given, only subcommands in that category are shown
-    def self.list_commands(preferred_category=nil)
-      load_commands
-
-      category_desc = preferred_category ? preferred_category + " " : ''
-      msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
-
-      if preferred_category && subcommands_by_category.key?(preferred_category)
-        commands_to_show = {preferred_category => subcommands_by_category[preferred_category]}
-      else
-        commands_to_show = subcommands_by_category
-      end
-
-      commands_to_show.sort.each do |category, commands|
-        next if category =~ /deprecated/i
-        msg "** #{category.upcase} COMMANDS **"
-        commands.sort.each do |command|
-          msg subcommands[command].banner if subcommands[command]
-        end
-        msg
-      end
-    end
-
     # Shared with subclasses
     @@chef_config_dir = nil
 
@@ -194,18 +195,17 @@ class Chef
     # args::: usually ARGV
     # options::: A Mixlib::CLI option parser hash. These +options+ are how
     # subcommands know about global knife CLI options
-    def self.run(args, options={})
+    def self.run(args, options = {})
       # Fallback debug logging. Normally the logger isn't configured until we
       # read the config, but this means any logging that happens before the
       # config file is read may be lost. If the KNIFE_DEBUG variable is set, we
       # setup the logger for debug logging to stderr immediately to catch info
       # from early in the setup process.
-      if ENV['KNIFE_DEBUG']
+      if ENV["KNIFE_DEBUG"]
         Chef::Log.init($stderr)
         Chef::Log.level(:debug)
       end
 
-      load_commands
       subcommand_class = subcommand_class_from(args)
       subcommand_class.options = options.merge!(subcommand_class.options)
       subcommand_class.load_deps
@@ -214,34 +214,6 @@ class Chef
       instance.run_with_pretty_exceptions
     end
 
-    def self.guess_category(args)
-      category_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ }
-      category_words.map! {|w| w.split('-')}.flatten!
-      matching_category = nil
-      while (!matching_category) && (!category_words.empty?)
-        candidate_category = category_words.join(' ')
-        matching_category = candidate_category if subcommands_by_category.key?(candidate_category)
-        matching_category || category_words.pop
-      end
-      matching_category
-    end
-
-    def self.subcommand_class_from(args)
-      command_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ }
-
-      subcommand_class = nil
-
-      while ( !subcommand_class ) && ( !command_words.empty? )
-        snake_case_class_name = command_words.join("_")
-        unless subcommand_class = subcommands[snake_case_class_name]
-          command_words.pop
-        end
-      end
-      # see if we got the command as e.g., knife node-list
-      subcommand_class ||= subcommands[args.first.gsub('-', '_')]
-      subcommand_class || subcommand_not_found!(args)
-    end
-
     def self.dependency_loaders
       @dependency_loaders ||= []
     end
@@ -258,17 +230,27 @@ class Chef
 
     private
 
-    OFFICIAL_PLUGINS = %w[ec2 rackspace windows openstack terremark bluebox]
+    OFFICIAL_PLUGINS = %w{ec2 rackspace windows openstack terremark bluebox}
+
+    def self.path_from_caller(caller_line)
+      caller_line.split(/:\d+/).first
+    end
 
     # :nodoc:
     # Error out and print usage. probably because the arguments given by the
     # user could not be resolved to a subcommand.
     def self.subcommand_not_found!(args)
-      ui.fatal("Cannot find sub command for: '#{args.join(' ')}'")
+      ui.fatal("Cannot find subcommand for: '#{args.join(' ')}'")
+
+      # Mention rehash when the subcommands cache(plugin_manifest.json) is used
+      if subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::HashedCommandLoader) ||
+         subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::CustomManifestLoader)
+        ui.info("If this is a recently installed plugin, please run 'knife rehash' to update the subcommands cache.")
+      end
 
       if category_commands = guess_category(args)
         list_commands(category_commands)
-      elsif missing_plugin = ( OFFICIAL_PLUGINS.find {|plugin| plugin == args[0]} )
+      elsif missing_plugin = ( OFFICIAL_PLUGINS.find { |plugin| plugin == args[0] } )
         ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10")
         ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}`")
         ui.info("Use `chef gem install knife-#{missing_plugin}` instead if using ChefDK")
@@ -279,6 +261,20 @@ class Chef
       exit 10
     end
 
+    def self.list_commands(preferred_category = nil)
+      category_desc = preferred_category ? preferred_category + " " : ""
+      msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
+      subcommand_loader.list_commands(preferred_category).sort.each do |category, commands|
+        next if category =~ /deprecated/i
+        msg "** #{category.upcase} COMMANDS **"
+        commands.sort.each do |command|
+          subcommand_loader.load_command(command)
+          msg subcommands[command].banner if subcommands[command]
+        end
+        msg
+      end
+    end
+
     def self.reset_config_path!
       @@chef_config_dir = nil
     end
@@ -289,20 +285,20 @@ class Chef
 
     # Create a new instance of the current class configured for the given
     # arguments and options
-    def initialize(argv=[])
+    def initialize(argv = [])
       super() # having to call super in initialize is the most annoying anti-pattern :(
       @ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, config)
 
-      command_name_words = self.class.snake_case_name.split('_')
+      command_name_words = self.class.snake_case_name.split("_")
 
       # Mixlib::CLI ignores the embedded name_args
       @name_args = parse_options(argv)
-      @name_args.delete(command_name_words.join('-'))
+      @name_args.delete(command_name_words.join("-"))
       @name_args.reject! { |name_arg| command_name_words.delete(name_arg) }
 
       # knife node run_list add requires that we have extra logic to handle
       # the case that command name words could be joined by an underscore :/
-      command_name_words = command_name_words.join('_')
+      command_name_words = command_name_words.join("_")
       @name_args.reject! { |name_arg| command_name_words == name_arg }
 
       if config[:help]
@@ -312,7 +308,7 @@ class Chef
 
       # copy Mixlib::CLI over so that it can be configured in knife.rb
       # config file
-      Chef::Config[:verbosity] = config[:verbosity]
+      Chef::Config[:verbosity] = config[:verbosity] if config[:verbosity]
     end
 
     def parse_options(args)
@@ -358,14 +354,14 @@ class Chef
 
       case Chef::Config[:verbosity]
       when 0, nil
-        Chef::Config[:log_level] = :error
+        Chef::Config[:log_level] = :warn
       when 1
         Chef::Config[:log_level] = :info
       else
         Chef::Config[:log_level] = :debug
       end
 
-      Chef::Config[:log_level] = :debug if ENV['KNIFE_DEBUG']
+      Chef::Config[:log_level] = :debug if ENV["KNIFE_DEBUG"]
 
       Chef::Config[:node_name]         = config[:node_name]       if config[:node_name]
       Chef::Config[:client_key]        = config[:client_key]      if config[:client_key]
@@ -391,20 +387,17 @@ class Chef
       Mixlib::Log::Formatter.show_time = false
       Chef::Log.init(Chef::Config[:log_location])
       Chef::Log.level(Chef::Config[:log_level] || :error)
-
-      if Chef::Config[:node_name] && Chef::Config[:node_name].bytesize > 90
-        # node names > 90 bytes only work with authentication protocol >= 1.1
-        # see discussion in config.rb.
-        Chef::Config[:authentication_protocol_version] = "1.1"
-      end
     end
 
     def configure_chef
+      # knife needs to send logger output to STDERR by default
+      Chef::Config[:log_location] = STDERR
       config_loader = self.class.load_config(config[:config_file])
       config[:config_file] = config_loader.config_location
 
       merge_configs
       apply_computed_config
+      Chef::Config.export_proxies
       # This has to be after apply_computed_config so that Mixlib::Log is configured
       Chef::Log.info("Using configuration from #{config[:config_file]}") if config[:config_file]
     end
@@ -418,6 +411,7 @@ class Chef
         ui.error "You need to add a #run method to your knife command before you can use it"
       end
       enforce_path_sanity
+      maybe_setup_fips
       Chef::LocalMode.with_server_connectivity do
         run
       end
@@ -483,6 +477,15 @@ class Chef
       when Net::HTTPServiceUnavailable
         ui.error "Service temporarily unavailable"
         ui.info "Response: #{format_rest_error(response)}"
+      when Net::HTTPNotAcceptable
+        version_header = Chef::JSONCompat.from_json(response["x-ops-server-api-version"])
+        client_api_version = version_header["request_version"]
+        min_server_version = version_header["min_version"]
+        max_server_version = version_header["max_version"]
+        ui.error "The version of Chef that Knife is using is not supported by the Chef server you sent this request to"
+        ui.info "The request that Knife sent was using API version #{client_api_version}"
+        ui.info "The Chef server you sent the request to supports a min API verson of #{min_server_version} and a max API version of #{max_server_version}"
+        ui.info "Please either update your Chef client or server to be a compatible set"
       else
         ui.error response.message
         ui.info "Response: #{format_rest_error(response)}"
@@ -502,12 +505,12 @@ class Chef
     #--
     # TODO: this code belongs in Chef::REST
     def format_rest_error(response)
-      Array(Chef::JSONCompat.from_json(response.body)["error"]).join('; ')
+      Array(Chef::JSONCompat.from_json(response.body)["error"]).join("; ")
     rescue Exception
       response.body
     end
 
-    def create_object(object, pretty_name=nil, &block)
+    def create_object(object, pretty_name = nil, &block)
       output = edit_data(object)
 
       if Kernel.block_given?
@@ -523,7 +526,7 @@ class Chef
       output(output) if config[:print_after]
     end
 
-    def delete_object(klass, name, delete_name=nil, &block)
+    def delete_object(klass, name, delete_name = nil, &block)
       confirm("Do you really want to delete #{name}")
 
       if Kernel.block_given?
@@ -539,17 +542,27 @@ class Chef
       self.msg("Deleted #{obj_name}")
     end
 
+    # helper method for testing if a field exists
+    # and returning the usage and proper error if not
+    def test_mandatory_field(field, fieldname)
+      if field.nil?
+        show_usage
+        ui.fatal("You must specify a #{fieldname}")
+        exit 1
+      end
+    end
+
     def rest
       @rest ||= begin
-        require 'chef/rest'
-        Chef::REST.new(Chef::Config[:chef_server_url])
+        require "chef/server_api"
+        Chef::ServerAPI.new(Chef::Config[:chef_server_url])
       end
     end
 
     def noauth_rest
       @rest ||= begin
-        require 'chef/rest'
-        Chef::REST.new(Chef::Config[:chef_server_url], false, false)
+        require "chef/http/simple_json"
+        Chef::HTTP::SimpleJSON.new(Chef::Config[:chef_server_url])
       end
     end
 
@@ -557,5 +570,11 @@ class Chef
       Chef::Config[:chef_server_url]
     end
 
+    def maybe_setup_fips
+      if !config[:fips].nil?
+        Chef::Config[:fips] = config[:fips]
+      end
+      Chef::Config.init_openssl
+    end
   end
 end
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index a4095e8..7982c0f 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
-require 'erubis'
-require 'chef/knife/bootstrap/chef_vault_handler'
-require 'chef/knife/bootstrap/client_builder'
-require 'chef/util/path_helper'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
+require "erubis"
+require "chef/knife/bootstrap/chef_vault_handler"
+require "chef/knife/bootstrap/client_builder"
+require "chef/util/path_helper"
 
 class Chef
   class Knife
@@ -32,17 +32,17 @@ class Chef
       attr_accessor :chef_vault_handler
 
       deps do
-        require 'chef/knife/core/bootstrap_context'
-        require 'chef/json_compat'
-        require 'tempfile'
-        require 'highline'
-        require 'net/ssh'
-        require 'net/ssh/multi'
-        require 'chef/knife/ssh'
+        require "chef/knife/core/bootstrap_context"
+        require "chef/json_compat"
+        require "tempfile"
+        require "highline"
+        require "net/ssh"
+        require "net/ssh/multi"
+        require "chef/knife/ssh"
         Chef::Knife::Ssh.load_deps
       end
 
-      banner "knife bootstrap FQDN (options)"
+      banner "knife bootstrap [SSH_USER@]FQDN (options)"
 
       option :ssh_user,
         :short => "-x USERNAME",
@@ -74,8 +74,12 @@ class Chef
         :boolean => true
 
       option :identity_file,
-        :short => "-i IDENTITY_FILE",
         :long => "--identity-file IDENTITY_FILE",
+        :description => "The SSH identity file used for authentication. [DEPRECATED] Use --ssh-identity-file instead."
+
+      option :ssh_identity_file,
+        :short => "-i IDENTITY_FILE",
+        :long => "--ssh-identity-file IDENTITY_FILE",
         :description => "The SSH identity file used for authentication"
 
       option :chef_node_name,
@@ -122,6 +126,11 @@ class Chef
         :description => "Execute the bootstrap via sudo",
         :boolean => true
 
+      option :preserve_home,
+        :long => "--sudo-preserve-home",
+        :description => "Preserve non-root user HOME environment variable with sudo",
+        :boolean => true
+
       option :use_sudo_password,
         :long => "--use-sudo-password",
         :description => "Execute the bootstrap via sudo with password",
@@ -143,12 +152,34 @@ class Chef
         :proc => lambda { |o| o.split(/[\s,]+/) },
         :default => []
 
+      option :policy_name,
+        :long         => "--policy-name POLICY_NAME",
+        :description  => "Policyfile name to use (--policy-group must also be given)",
+        :default      => nil
+
+      option :policy_group,
+        :long         => "--policy-group POLICY_GROUP",
+        :description  => "Policy group name to use (--policy-name must also be given)",
+        :default      => nil
+
+      option :tags,
+        :long => "--tags TAGS",
+        :description => "Comma separated list of tags to apply to the node",
+        :proc => lambda { |o| o.split(/[\s,]+/) },
+        :default => []
+
       option :first_boot_attributes,
         :short => "-j JSON_ATTRIBS",
         :long => "--json-attributes",
         :description => "A JSON string to be added to the first run of chef-client",
         :proc => lambda { |o| Chef::JSONCompat.parse(o) },
-        :default => {}
+        :default => nil
+
+      option :first_boot_attributes_from_file,
+        :long => "--json-attribute-file FILE",
+        :description => "A JSON file to be used to the first run of chef-client",
+        :proc => lambda { |o| Chef::JSONCompat.parse(File.read(o)) },
+        :default => nil
 
       option :host_key_verify,
         :long => "--[no-]host-key-verify",
@@ -201,15 +232,15 @@ class Chef
         :boolean     => true
 
       option :bootstrap_vault_file,
-        :long        => '--bootstrap-vault-file VAULT_FILE',
-        :description => 'A JSON file with a list of vault(s) and item(s) to be updated'
+        :long        => "--bootstrap-vault-file VAULT_FILE",
+        :description => "A JSON file with a list of vault(s) and item(s) to be updated"
 
       option :bootstrap_vault_json,
-        :long        => '--bootstrap-vault-json VAULT_JSON',
-        :description => 'A JSON string with the vault(s) and item(s) to be updated'
+        :long        => "--bootstrap-vault-json VAULT_JSON",
+        :description => "A JSON string with the vault(s) and item(s) to be updated"
 
       option :bootstrap_vault_item,
-        :long        => '--bootstrap-vault-item VAULT_ITEM',
+        :long        => "--bootstrap-vault-item VAULT_ITEM",
         :description => 'A single vault and item to update as "vault:item"',
         :proc        => Proc.new { |i|
           (vault, item) = i.split(/:/)
@@ -219,7 +250,7 @@ class Chef
           Chef::Config[:knife][:bootstrap_vault_item]
         }
 
-      def initialize(argv=[])
+      def initialize(argv = [])
         super
         @client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(
           chef_config: Chef::Config,
@@ -228,7 +259,7 @@ class Chef
         )
         @chef_vault_handler = Chef::Knife::Bootstrap::ChefVaultHandler.new(
           knife_config: config,
-          ui: ui
+          ui: ui,
         )
       end
 
@@ -240,13 +271,25 @@ class Chef
         "chef-full"
       end
 
+      def host_descriptor
+        Array(@name_args).first
+      end
+
       # The server_name is the DNS or IP we are going to connect to, it is not necessarily
       # the node name, the fqdn, or the hostname of the server.  This is a public API hook
       # which knife plugins use or inherit and override.
       #
       # @return [String] The DNS or IP that bootstrap will connect to
       def server_name
-        Array(@name_args).first
+        if host_descriptor
+          @server_name ||= host_descriptor.split("@").reverse[0]
+        end
+      end
+
+      def user_name
+        if host_descriptor
+          @user_name ||= host_descriptor.split("@").reverse[1]
+        end
       end
 
       def bootstrap_template
@@ -267,10 +310,10 @@ class Chef
 
         # Otherwise search the template directories until we find the right one
         bootstrap_files = []
-        bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
+        bootstrap_files << File.join(File.dirname(__FILE__), "bootstrap/templates", "#{template}.erb")
         bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
-        Chef::Util::PathHelper.home('.chef', 'bootstrap', "#{template}.erb") {|p| bootstrap_files << p}
-        bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
+        Chef::Util::PathHelper.home(".chef", "bootstrap", "#{template}.erb") { |p| bootstrap_files << p }
+        bootstrap_files << Gem.find_files(File.join("chef", "knife", "bootstrap", "#{template}.erb"))
         bootstrap_files.flatten!
 
         template_file = Array(bootstrap_files).find do |bootstrap_template|
@@ -297,28 +340,44 @@ class Chef
           config,
           config[:run_list],
           Chef::Config,
-          secret
+          secret,
         )
       end
 
+      def first_boot_attributes
+        @config[:first_boot_attributes] || @config[:first_boot_attributes_from_file] || {}
+      end
+
       def render_template
+        @config[:first_boot_attributes] = first_boot_attributes
         template_file = find_template
         template = IO.read(template_file).chomp
         Erubis::Eruby.new(template).evaluate(bootstrap_context)
       end
 
       def run
+        if @config[:first_boot_attributes] && @config[:first_boot_attributes_from_file]
+          raise Chef::Exceptions::BootstrapCommandInputError
+        end
+
         validate_name_args!
+        validate_options!
 
         $stdout.sync = true
 
         # chef-vault integration must use the new client-side hawtness, otherwise to use the
         # new client-side hawtness, just delete your validation key.
-        if chef_vault_handler.doing_chef_vault? || 
-            (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
+        if chef_vault_handler.doing_chef_vault? ||
+           (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
+
+          unless config[:chef_node_name]
+            ui.error("You must pass a node name with -N when bootstrapping with user credentials")
+            exit 1
+          end
+
           client_builder.run
 
-          chef_vault_handler.run(node_name: config[:chef_node_name])
+          chef_vault_handler.run(client_builder.client)
 
           bootstrap_context.client_pem = client_builder.client_path
         else
@@ -335,7 +394,7 @@ class Chef
           if config[:ssh_password]
             raise
           else
-            ui.info("Failed to authenticate #{config[:ssh_user]} - trying password auth")
+            ui.info("Failed to authenticate #{knife_ssh.config[:ssh_user]} - trying password auth")
             knife_ssh_with_password_auth.run
           end
         end
@@ -351,16 +410,27 @@ class Chef
         end
       end
 
+      def validate_options!
+        if incomplete_policyfile_options?
+          ui.error("--policy-name and --policy-group must be specified together")
+          exit 1
+        elsif policyfile_and_run_list_given?
+          ui.error("Policyfile options and --run-list are exclusive")
+          exit 1
+        end
+        true
+      end
+
       def knife_ssh
         ssh = Chef::Knife::Ssh.new
         ssh.ui = ui
         ssh.name_args = [ server_name, ssh_command ]
-        ssh.config[:ssh_user] = config[:ssh_user]
+        ssh.config[:ssh_user] = user_name || config[:ssh_user]
         ssh.config[:ssh_password] = config[:ssh_password]
         ssh.config[:ssh_port] = config[:ssh_port]
         ssh.config[:ssh_gateway] = config[:ssh_gateway]
         ssh.config[:forward_agent] = config[:forward_agent]
-        ssh.config[:identity_file] = config[:identity_file]
+        ssh.config[:ssh_identity_file] = config[:ssh_identity_file] || config[:identity_file]
         ssh.config[:manual] = true
         ssh.config[:host_key_verify] = config[:host_key_verify]
         ssh.config[:on_error] = :raise
@@ -369,7 +439,7 @@ class Chef
 
       def knife_ssh_with_password_auth
         ssh = knife_ssh
-        ssh.config[:identity_file] = nil
+        ssh.config[:ssh_identity_file] = nil
         ssh.config[:ssh_password] = ssh.get_password
         ssh
       end
@@ -378,11 +448,33 @@ class Chef
         command = render_template
 
         if config[:use_sudo]
-          command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -SH #{command}" : "sudo -H #{command}"
+          sudo_prefix = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S " : "sudo "
+          command = config[:preserve_home] ? "#{sudo_prefix} #{command}" : "#{sudo_prefix} -H #{command}"
         end
 
         command
       end
+
+      private
+
+      # True if policy_name and run_list are both given
+      def policyfile_and_run_list_given?
+        run_list_given? && policyfile_options_given?
+      end
+
+      def run_list_given?
+        !config[:run_list].nil? && !config[:run_list].empty?
+      end
+
+      def policyfile_options_given?
+        !!config[:policy_name]
+      end
+
+      # True if one of policy_name or policy_group was given, but not both
+      def incomplete_policyfile_options?
+        (!!config[:policy_name] ^ config[:policy_group])
+      end
+
     end
   end
 end
diff --git a/lib/chef/knife/bootstrap/chef_vault_handler.rb b/lib/chef/knife/bootstrap/chef_vault_handler.rb
index 749f61e..86eed6a 100644
--- a/lib/chef/knife/bootstrap/chef_vault_handler.rb
+++ b/lib/chef/knife/bootstrap/chef_vault_handler.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+require "chef/knife/bootstrap"
 
 class Chef
   class Knife
@@ -27,8 +28,8 @@ class Chef
         # @return [Chef::Knife::UI] ui object for output
         attr_accessor :ui
 
-        # @return [String] name of the node (technically name of the client)
-        attr_reader :node_name
+        # @return [Chef::ApiClient] vault client
+        attr_reader :client
 
         # @param knife_config [Hash] knife merged config, typically @config
         # @param ui [Chef::Knife::UI] ui object for output
@@ -37,18 +38,15 @@ class Chef
           @ui           = ui
         end
 
-        # Updates the chef vault items for the newly created node.
+        # Updates the chef vault items for the newly created client.
         #
-        # @param node_name [String] name of the node (technically name of the client)
-        # @todo: node_name should be mandatory (ruby 2.0 compat)
-        def run(node_name: nil)
+        # @param client [Chef::ApiClient] vault client
+        def run(client)
           return unless doing_chef_vault?
 
           sanity_check
 
-          @node_name = node_name
-
-          ui.info("Updating Chef Vault, waiting for client to be searchable..") while wait_for_client
+          @client = client
 
           update_bootstrap_vault_json!
         end
@@ -125,7 +123,7 @@ class Chef
         def update_vault(vault, item)
           require_chef_vault!
           bootstrap_vault_item = load_chef_bootstrap_vault_item(vault, item)
-          bootstrap_vault_item.clients("name:#{node_name}")
+          bootstrap_vault_item.clients(client)
           bootstrap_vault_item.save
         end
 
@@ -138,24 +136,20 @@ class Chef
           ChefVault::Item.load(vault, item)
         end
 
-        public :load_chef_bootstrap_vault_item  # for stubbing
-
-        # Helper used to spin waiting for the client to appear in search.
-        #
-        # @return [Boolean] true if the client is searchable
-        def wait_for_client
-          sleep 1
-          !Chef::Search::Query.new.search(:client, "name:#{node_name}")[0]
-        end
+        public :load_chef_bootstrap_vault_item # for stubbing
 
         # Helper to very lazily require the chef-vault gem
         def require_chef_vault!
           @require_chef_vault ||=
             begin
-              require 'chef-vault'
+              error_message = "Knife bootstrap needs version 2.6.0 or higher of the chef-vault gem to configure chef vault items"
+              require "chef-vault"
+              if Gem::Version.new(ChefVault::VERSION) < Gem::Version.new("2.6.0")
+                raise error_message
+              end
               true
             rescue LoadError
-              raise "Knife bootstrap cannot configure chef vault items when the chef-vault gem is not installed"
+              raise error_message
             end
         end
 
diff --git a/lib/chef/knife/bootstrap/client_builder.rb b/lib/chef/knife/bootstrap/client_builder.rb
index b9c1d98..cab33cd 100644
--- a/lib/chef/knife/bootstrap/client_builder.rb
+++ b/lib/chef/knife/bootstrap/client_builder.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/node'
-require 'chef/rest'
-require 'chef/api_client/registration'
-require 'chef/api_client'
-require 'tmpdir'
+require "chef/node"
+require "chef/server_api"
+require "chef/api_client/registration"
+require "chef/api_client"
+require "chef/knife/bootstrap"
+require "tmpdir"
 
 class Chef
   class Knife
@@ -33,6 +34,8 @@ class Chef
         attr_accessor :chef_config
         # @return [Chef::Knife::UI] ui object for output
         attr_accessor :ui
+        # @return [Chef::ApiClient] client saved on run
+        attr_reader :client
 
         # @param knife_config [Hash] Hash of knife config settings
         # @param chef_config [Hash] Hash of chef config settings
@@ -50,7 +53,7 @@ class Chef
 
           ui.info("Creating new client for #{node_name}")
 
-          create_client!
+          @client = create_client!
 
           ui.info("Creating new node for #{node_name}")
 
@@ -90,6 +93,16 @@ class Chef
           knife_config[:run_list]
         end
 
+        # @return [String] policy_name from the knife_config
+        def policy_name
+          knife_config[:policy_name]
+        end
+
+        # @return [String] policy_group from the knife_config
+        def policy_group
+          knife_config[:policy_group]
+        end
+
         # @return [Hash,Array] Object representation of json first-boot attributes from the knife_config
         def first_boot_attributes
           knife_config[:first_boot_attributes]
@@ -140,6 +153,11 @@ class Chef
               node.run_list(normalized_run_list)
               node.normal_attrs = first_boot_attributes if first_boot_attributes
               node.environment(environment) if environment
+              node.policy_name = policy_name if policy_name
+              node.policy_group = policy_group if policy_group
+              (knife_config[:tags] || []).each do |tag|
+                node.tags << tag
+              end
               node
             end
         end
@@ -167,22 +185,22 @@ class Chef
         # @param relative_path [String] URI path relative to the chef organization
         # @return [Boolean] if the relative path exists or returns a 404
         def resource_exists?(relative_path)
-          rest.get_rest(relative_path)
+          rest.get(relative_path)
           true
         rescue Net::HTTPServerException => e
           raise unless e.response.code == "404"
           false
         end
 
-        # @return [Chef::REST] REST client using the client credentials
+        # @return [Chef::ServerAPI] REST client using the client credentials
         def client_rest
-          @client_rest ||= Chef::REST.new(chef_server_url, node_name, client_path)
+          @client_rest ||= Chef::ServerAPI.new(chef_server_url, :client_name => node_name, :signing_key_filename => client_path)
         end
 
-        # @return [Chef::REST] REST client using the cli user's knife credentials
+        # @return [Chef::ServerAPI] REST client using the cli user's knife credentials
         # this uses the users's credentials
         def rest
-          @rest ||= Chef::REST.new(chef_server_url)
+          @rest ||= Chef::ServerAPI.new(chef_server_url)
         end
       end
     end
diff --git a/lib/chef/knife/bootstrap/templates/README.md b/lib/chef/knife/bootstrap/templates/README.md
index 13a0fe7..b5bca25 100644
--- a/lib/chef/knife/bootstrap/templates/README.md
+++ b/lib/chef/knife/bootstrap/templates/README.md
@@ -1,12 +1,11 @@
 This directory contains bootstrap templates which can be used with the -d flag
 to 'knife bootstrap' to install Chef in different ways. To simplify installation,
 and reduce the matrix of common installation patterns to support, we have
-standardized on the [Omnibus](https://github.com/opscode/omnibus-ruby) built installation 
+standardized on the [Omnibus](https://github.com/chef/omnibus) built installation
 packages.
 
 The 'chef-full' template downloads a script which is used to determine the correct
-Omnibus package for this system from the [Omnitruck](https://github.com/opscode/opscode-omnitruck) API. All other templates in this directory are deprecated and will be removed
-in the future.
+Omnibus package for this system from the [Omnitruck](https://docs.chef.io/api_omnitruck.html) API.
 
 You can still utilize custom bootstrap templates on your system if your installation
-needs are unique. Additional information can be found on the [docs site](http://docs.opscode.com/knife_bootstrap.html#custom-templates).
\ No newline at end of file
+needs are unique. Additional information can be found on the [docs site](https://docs.chef.io/knife_bootstrap.html#custom-templates).
diff --git a/lib/chef/knife/bootstrap/templates/archlinux-gems.erb b/lib/chef/knife/bootstrap/templates/archlinux-gems.erb
deleted file mode 100644
index 55d2c0c..0000000
--- a/lib/chef/knife/bootstrap/templates/archlinux-gems.erb
+++ /dev/null
@@ -1,76 +0,0 @@
-bash -c '
-<%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
-
-if [ ! -f /usr/bin/chef-client ]; then
-  pacman -Syy
-  pacman -S --noconfirm ruby ntp base-devel
-  ntpdate -u pool.ntp.org
-  gem install ohai --no-user-install --no-document --verbose
-  gem install chef --no-user-install --no-document --verbose <%= Chef::VERSION %>
-fi
-
-mkdir -p /etc/chef
-
-<% if validation_key -%>
-cat > /etc/chef/validation.pem <<'EOP'
-<%= validation_key %>
-EOP
-chmod 0600 /etc/chef/validation.pem
-<% end -%>
-
-<% if encrypted_data_bag_secret -%>
-cat > /etc/chef/encrypted_data_bag_secret <<'EOP'
-<%= encrypted_data_bag_secret %>
-EOP
-chmod 0600 /etc/chef/encrypted_data_bag_secret
-<% end -%>
-
-<% unless trusted_certs.empty? -%>
-mkdir -p /etc/chef/trusted_certs
-<%= trusted_certs %>
-<% end -%>
-
-<%# Generate Ohai Hints -%>
-<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
-mkdir -p /etc/chef/ohai/hints
-
-<% @chef_config[:knife][:hints].each do |name, hash| -%>
-cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP'
-<%= Chef::JSONCompat.to_json(hash) %>
-EOP
-<% end -%>
-<% end -%>
-
-<% if client_pem -%>
-cat > /etc/chef/client.pem <<'EOP'
-<%= ::File.read(::File.expand_path(client_pem)) %>
-EOP
-chmod 0600 /etc/chef/client.pem
-<% end -%>
-
-cat > /etc/chef/client.rb <<'EOP'
-log_level        :info
-log_location     STDOUT
-chef_server_url  "<%= @chef_config[:chef_server_url] %>"
-validation_client_name "<%= @chef_config[:validation_client_name] %>"
-<% if @config[:chef_node_name] -%>
-node_name "<%= @config[:chef_node_name] %>"
-<% else -%>
-# Using default node name (fqdn)
-<% end -%>
-# ArchLinux follows the Filesystem Hierarchy Standard
-file_cache_path    "/var/cache/chef"
-file_backup_path   "/var/lib/chef/backup"
-pid_file           "/var/run/chef/client.pid"
-cache_options({ :path => "/var/cache/chef/checksums", :skip_expires => true})
-<% if knife_config[:bootstrap_proxy] %>
-http_proxy         "<%= knife_config[:bootstrap_proxy] %>"
-https_proxy        "<%= knife_config[:bootstrap_proxy] %>"
-<% end -%>
-EOP
-
-cat > /etc/chef/first-boot.json <<'EOP'
-<%= Chef::JSONCompat.to_json(first_boot) %>
-EOP
-
-<%= start_chef %>'
diff --git a/lib/chef/knife/bootstrap/templates/chef-aix.erb b/lib/chef/knife/bootstrap/templates/chef-aix.erb
deleted file mode 100644
index 45fbba7..0000000
--- a/lib/chef/knife/bootstrap/templates/chef-aix.erb
+++ /dev/null
@@ -1,72 +0,0 @@
-ksh -c '
-
-function exists {
-  if type $1 >/dev/null 2>&1
-  then
-    return 0
-  else
-    return 1
-  fi
-}
-
-if ! exists /usr/bin/chef-client; then
-  <% if @chef_config[:aix_package] -%>
-    # Read the download URL/location from knife.rb with option aix_package
-    rm -rf /tmp/chef_installer # ensure there no older pkg
-    echo "<%= @chef_config[:aix_package] %>"
-    perl -e '\''use LWP::Simple; getprint($ARGV[0]);'\'' <%= @chef_config[:aix_package] %> > /tmp/chef_installer
-    installp -aYF -d  /tmp/chef_installer chef
-  <% else -%>
-     echo ":aix_package location is not set in knife.rb"
-     exit
-  <% end -%>
-fi
-
-mkdir -p /etc/chef
-
-<% if client_pem -%>
-cat > /etc/chef/client.pem <<'EOP'
-<%= ::File.read(::File.expand_path(client_pem)) %>
-EOP
-chmod 0600 /etc/chef/client.pem
-<% end -%>
-
-<% if validation_key -%>
-cat > /etc/chef/validation.pem <<'EOP'
-<%= validation_key %>
-EOP
-chmod 0600 /etc/chef/validation.pem
-<% end -%>
-
-<% if encrypted_data_bag_secret -%>
-cat > /etc/chef/encrypted_data_bag_secret <<'EOP'
-<%= encrypted_data_bag_secret %>
-EOP
-chmod 0600 /etc/chef/encrypted_data_bag_secret
-<% end -%>
-
-<% unless trusted_certs.empty? -%>
-mkdir -p /etc/chef/trusted_certs
-<%= trusted_certs %>
-<% end -%>
-
-<%# Generate Ohai Hints -%>
-<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
-mkdir -p /etc/chef/ohai/hints
-
-<% @chef_config[:knife][:hints].each do |name, hash| -%>
-cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP'
-<%= Chef::JSONCompat.to_json(hash) %>
-EOP
-<% end -%>
-<% end -%>
-
-cat > /etc/chef/client.rb <<'EOP'
-<%= config_content %>
-EOP
-
-cat > /etc/chef/first-boot.json <<'EOP'
-<%= Chef::JSONCompat.to_json(first_boot) %>
-EOP
-
-<%= start_chef %>'
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index a87ab8e..020645c 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -1,17 +1,18 @@
-bash -c '
+sh -c '
 <%= "export https_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
 
-distro=`uname -s`
-
-if test "x$distro" = "xSunOS"; then
-  if test -d "/usr/sfw/bin"; then
-    PATH=/usr/sfw/bin:$PATH
-    export PATH
-  fi
+if test "x$TMPDIR" = "x"; then
+  tmp="/tmp"
+else
+  tmp=$TMPDIR
 fi
 
+# secure-ish temp dir creation without having mktemp available (DDoS-able but not exploitable)
+tmp_dir="$tmp/install.sh.$$"
+(umask 077 && mkdir $tmp_dir) || exit 1
+
 exists() {
-  if command -v $1 &>/dev/null
+  if command -v $1 >/dev/null 2>&1
   then
     return 0
   else
@@ -19,41 +20,183 @@ exists() {
   fi
 }
 
+http_404_error() {
+  echo "ERROR 404: Could not retrieve a valid install.sh!"
+  exit 1
+}
+
+capture_tmp_stderr() {
+  # spool up /tmp/stderr from all the commands we called
+  if test -f "$tmp_dir/stderr"; then
+    output=`cat $tmp_dir/stderr`
+    stderr_results="${stderr_results}\nSTDERR from $1:\n\n$output\n"
+    rm $tmp_dir/stderr
+  fi
+}
+
+# do_wget URL FILENAME
+do_wget() {
+  echo "trying wget..."
+  wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_wget_options] %> -O "$2" "$1" 2>$tmp_dir/stderr
+  rc=$?
+  # check for 404
+  grep "ERROR 404" $tmp_dir/stderr 2>&1 >/dev/null
+  if test $? -eq 0; then
+    http_404_error
+  fi
+
+  # check for bad return status or empty output
+  if test $rc -ne 0 || test ! -s "$2"; then
+    capture_tmp_stderr "wget"
+    return 1
+  fi
+
+  return 0
+}
+
+# do_curl URL FILENAME
+do_curl() {
+  echo "trying curl..."
+  curl -sL <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_curl_options] %> -D $tmp_dir/stderr -o "$2" "$1" 2>$tmp_dir/stderr
+  rc=$?
+  # check for 404
+  grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
+  if test $? -eq 0; then
+    http_404_error
+  fi
+
+  # check for bad return status or empty output
+  if test $rc -ne 0 || test ! -s "$2"; then
+    capture_tmp_stderr "curl"
+    return 1
+  fi
+
+  return 0
+}
+
+# do_fetch URL FILENAME
+do_fetch() {
+  echo "trying fetch..."
+  fetch -o "$2" "$1" 2>$tmp_dir/stderr
+  # check for bad return status
+  test $? -ne 0 && return 1
+  return 0
+}
+
+# do_perl URL FILENAME
+do_perl() {
+  echo "trying perl..."
+  perl -e "use LWP::Simple; getprint(shift @ARGV);" "$1" > "$2" 2>$tmp_dir/stderr
+  rc=$?
+  # check for 404
+  grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null
+  if test $? -eq 0; then
+    http_404_error
+  fi
+
+  # check for bad return status or empty output
+  if test $rc -ne 0 || test ! -s "$2"; then
+    capture_tmp_stderr "perl"
+    return 1
+  fi
+
+  return 0
+}
+
+# do_python URL FILENAME
+do_python() {
+  echo "trying python..."
+  python -c "import sys,urllib2 ; sys.stdout.write(urllib2.urlopen(sys.argv[1]).read())" "$1" > "$2" 2>$tmp_dir/stderr
+  rc=$?
+  # check for 404
+  grep "HTTP Error 404" $tmp_dir/stderr 2>&1 >/dev/null
+  if test $? -eq 0; then
+    http_404_error
+  fi
+
+  # check for bad return status or empty output
+  if test $rc -ne 0 || test ! -s "$2"; then
+    capture_tmp_stderr "python"
+    return 1
+  fi
+  return 0
+}
+
+# do_download URL FILENAME
+do_download() {
+  PATH=/opt/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sfw/bin:/sbin:/bin:/usr/sbin:/usr/bin
+  export PATH
+
+  echo "downloading $1"
+  echo "  to file $2"
+
+  # we try all of these until we get success.
+  # perl, in particular may be present but LWP::Simple may not be installed
+
+  if exists wget; then
+    do_wget $1 $2 && return 0
+  fi
+
+  if exists curl; then
+    do_curl $1 $2 && return 0
+  fi
+
+  if exists fetch; then
+    do_fetch $1 $2 && return 0
+  fi
+
+  if exists perl; then
+    do_perl $1 $2 && return 0
+  fi
+
+  if exists python; then
+    do_python $1 $2 && return 0
+  fi
+
+  echo ">>>>>> wget, curl, fetch, perl, or python not found on this instance."
+
+  if test "x$stderr_results" != "x"; then
+    echo "\nDEBUG OUTPUT FOLLOWS:\n$stderr_results"
+  fi
+
+  return 16
+}
+
 <% if knife_config[:bootstrap_install_command] %>
   <%= knife_config[:bootstrap_install_command] %>
 <% else %>
-  install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.opscode.com/chef/install.sh" %>"
-  if ! exists /usr/bin/chef-client; then
-    echo "Installing Chef Client..."
-    if exists wget; then
-      bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_wget_options] %> ${install_sh} -O -) <%= latest_current_chef_version_string %>
-    elif exists curl; then
-      bash <(curl -L <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_curl_options] %> ${install_sh}) <%= latest_current_chef_version_string %>
-    else
-      echo "Neither wget nor curl found. Please install one and try again." >&2
-      exit 1
-    fi
+  install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://omnitruck-direct.chef.io/chef/install.sh" %>"
+  if test -f /usr/bin/chef-client; then
+    echo "-----> Existing Chef installation detected"
+  else
+    echo "-----> Installing Chef Omnibus (<%= latest_current_chef_version_string %>)"
+    do_download ${install_sh} $tmp_dir/install.sh
+    sh $tmp_dir/install.sh -P chef <%= latest_current_chef_version_string %>
   fi
 <% end %>
 
+if test "x$tmp_dir" != "x"; then
+  rm -r "$tmp_dir"
+fi
+
 mkdir -p /etc/chef
 
 <% if client_pem -%>
-cat > /etc/chef/client.pem <<'EOP'
+cat > /etc/chef/client.pem <<EOP
 <%= ::File.read(::File.expand_path(client_pem)) %>
 EOP
 chmod 0600 /etc/chef/client.pem
 <% end -%>
 
 <% if validation_key -%>
-cat > /etc/chef/validation.pem <<'EOP'
+cat > /etc/chef/validation.pem <<EOP
 <%= validation_key %>
 EOP
 chmod 0600 /etc/chef/validation.pem
 <% end -%>
 
 <% if encrypted_data_bag_secret -%>
-cat > /etc/chef/encrypted_data_bag_secret <<'EOP'
+cat > /etc/chef/encrypted_data_bag_secret <<EOP
 <%= encrypted_data_bag_secret %>
 EOP
 chmod 0600 /etc/chef/encrypted_data_bag_secret
@@ -69,20 +212,20 @@ mkdir -p /etc/chef/trusted_certs
 mkdir -p /etc/chef/ohai/hints
 
 <% @chef_config[:knife][:hints].each do |name, hash| -%>
-cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP'
+cat > /etc/chef/ohai/hints/<%= name %>.json <<EOP
 <%= Chef::JSONCompat.to_json(hash) %>
 EOP
 <% end -%>
 <% end -%>
 
-cat > /etc/chef/client.rb <<'EOP'
+cat > /etc/chef/client.rb <<EOP
 <%= config_content %>
 EOP
 
-cat > /etc/chef/first-boot.json <<'EOP'
+cat > /etc/chef/first-boot.json <<EOP
 <%= Chef::JSONCompat.to_json(first_boot) %>
 EOP
 
-echo "Starting first Chef Client run..."
+echo "Starting the first Chef Client run..."
 
 <%= start_chef %>'
diff --git a/lib/chef/knife/client_bulk_delete.rb b/lib/chef/knife/client_bulk_delete.rb
index f2be772..af3e862 100644
--- a/lib/chef/knife/client_bulk_delete.rb
+++ b/lib/chef/knife/client_bulk_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientBulkDelete < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       option :delete_validators,
@@ -39,7 +39,7 @@ class Chef
           ui.fatal("You must supply a regular expression to match the results against")
           exit 42
         end
-        all_clients = Chef::ApiClient.list(true)
+        all_clients = Chef::ApiClientV1.list(true)
 
         matcher = /#{name_args[0]}/
         clients_to_delete = {}
diff --git a/lib/chef/knife/client_create.rb b/lib/chef/knife/client_create.rb
index 477a400..ecacb36 100644
--- a/lib/chef/knife/client_create.rb
+++ b/lib/chef/knife/client_create.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,70 +16,94 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientCreate < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       option :file,
-        :short => "-f FILE",
-        :long  => "--file FILE",
-        :description => "Write the key to a file"
+             :short => "-f FILE",
+             :long  => "--file FILE",
+             :description => "Write the private key to a file if the server generated one."
 
       option :admin,
-        :short => "-a",
-        :long  => "--admin",
-        :description => "Create the client as an admin",
-        :boolean => true
+             :short => "-a",
+             :long  => "--admin",
+             :description => "Open Source Chef 11 only. Create the client as an admin.",
+             :boolean => true
 
       option :validator,
-        :long  => "--validator",
-        :description => "Create the client as a validator",
-        :boolean => true
+             :long  => "--validator",
+             :description => "Create the client as a validator.",
+             :boolean => true
 
-      banner "knife client create CLIENT (options)"
+      option :public_key,
+             :short => "-p FILE",
+             :long  => "--public-key",
+             :description => "Set the initial default key for the client from a file on disk (cannot pass with --prevent-keygen)."
+
+      option :prevent_keygen,
+             :short => "-k",
+             :long  => "--prevent-keygen",
+             :description => "API V1 only. Prevent server from generating a default key pair for you. Cannot be passed with --public-key.",
+             :boolean => true
+
+      banner "knife client create CLIENTNAME (options)"
+
+      def client
+        @client_field ||= Chef::ApiClientV1.new
+      end
+
+      def create_client(client)
+        # should not be using save :( bad behavior
+        Chef::ApiClientV1.from_hash(client).save
+      end
 
       def run
-        @client_name = @name_args[0]
+        test_mandatory_field(@name_args[0], "client name")
+        client.name @name_args[0]
 
-        if @client_name.nil?
+        if config[:public_key] && config[:prevent_keygen]
           show_usage
-          ui.fatal("You must specify a client name")
+          ui.fatal("You cannot pass --public-key and --prevent-keygen")
           exit 1
         end
 
-        client_hash = {
-          "name" => @client_name,
-          "admin" => !!config[:admin],
-          "validator" => !!config[:validator]
-        }
+        if !config[:prevent_keygen] && !config[:public_key]
+          client.create_key(true)
+        end
+
+        if config[:admin]
+          client.admin(true)
+        end
 
-        output = Chef::ApiClient.from_hash(edit_hash(client_hash))
+        if config[:validator]
+          client.validator(true)
+        end
 
-        # Chef::ApiClient.save will try to create a client and if it
-        # exists will update it instead silently.
-        client = output.save
+        if config[:public_key]
+          client.public_key File.read(File.expand_path(config[:public_key]))
+        end
 
-        # We only get a private_key on client creation, not on client update.
-        if client['private_key']
-          ui.info("Created #{output}")
+        output = edit_data(client)
+        final_client = create_client(output)
+        ui.info("Created #{final_client}")
 
+        # output private_key if one
+        if final_client.private_key
           if config[:file]
             File.open(config[:file], "w") do |f|
-              f.print(client['private_key'])
+              f.print(final_client.private_key)
             end
           else
-            puts client['private_key']
+            puts final_client.private_key
           end
-        else
-          ui.error "Client '#{client['name']}' already exists"
-          exit 1
         end
       end
     end
diff --git a/lib/chef/knife/client_delete.rb b/lib/chef/knife/client_delete.rb
index d7d302e..e1b2365 100644
--- a/lib/chef/knife/client_delete.rb
+++ b/lib/chef/knife/client_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientDelete < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       option :delete_validators,
@@ -43,8 +43,8 @@ class Chef
           exit 1
         end
 
-        delete_object(Chef::ApiClient, @client_name, 'client') {
-          object = Chef::ApiClient.load(@client_name)
+        delete_object(Chef::ApiClientV1, @client_name, "client") {
+          object = Chef::ApiClientV1.load(@client_name)
           if object.validator
             unless config[:delete_validators]
               ui.fatal("You must specify --delete-validators to delete the validator client #{@client_name}")
diff --git a/lib/chef/knife/client_edit.rb b/lib/chef/knife/client_edit.rb
index c81bce9..c05b677 100644
--- a/lib/chef/knife/client_edit.rb
+++ b/lib/chef/knife/client_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientEdit < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       banner "knife client edit CLIENT (options)"
@@ -38,7 +38,15 @@ class Chef
           exit 1
         end
 
-        edit_object(Chef::ApiClient, @client_name)
+        original_data = Chef::ApiClientV1.load(@client_name).to_hash
+        edited_client = edit_data(original_data)
+        if original_data != edited_client
+          client = Chef::ApiClientV1.from_hash(edited_client)
+          client.save
+          ui.msg("Saved #{client}.")
+        else
+          ui.msg("Client unchanged, not saving.")
+        end
       end
     end
   end
diff --git a/lib/chef/knife/client_key_create.rb b/lib/chef/knife/client_key_create.rb
new file mode 100644
index 0000000..68ad4d1
--- /dev/null
+++ b/lib/chef/knife/client_key_create.rb
@@ -0,0 +1,67 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_create_base"
+
+class Chef
+  class Knife
+    # Implements knife user key create using Chef::Knife::KeyCreate
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class ClientKeyCreate < Knife
+      include Chef::Knife::KeyCreateBase
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "client"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyCreate.new(@actor, actor_field_name, ui, config)
+      end
+
+      def actor_missing_error
+        "You must specify a client name"
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/client_key_delete.rb b/lib/chef/knife/client_key_delete.rb
new file mode 100644
index 0000000..64eae2e
--- /dev/null
+++ b/lib/chef/knife/client_key_delete.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+class Chef
+  class Knife
+    # Implements knife client key delete using Chef::Knife::KeyDelete
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class ClientKeyDelete < Knife
+      banner "knife client key delete CLIENT KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "client"
+      end
+
+      def actor_missing_error
+        "You must specify a client name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyDelete.new(@name, @actor, actor_field_name, ui)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/client_key_edit.rb b/lib/chef/knife/client_key_edit.rb
new file mode 100644
index 0000000..1dbd3c4
--- /dev/null
+++ b/lib/chef/knife/client_key_edit.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_edit_base"
+
+class Chef
+  class Knife
+    # Implements knife client key edit using Chef::Knife::KeyEdit
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class ClientKeyEdit < Knife
+      include Chef::Knife::KeyEditBase
+
+      banner "knife client key edit CLIENT KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "client"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyEdit.new(@name, @actor, actor_field_name, ui, config)
+      end
+
+      def actor_missing_error
+        "You must specify a client name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/client_key_list.rb b/lib/chef/knife/client_key_list.rb
new file mode 100644
index 0000000..194ad42
--- /dev/null
+++ b/lib/chef/knife/client_key_list.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_list_base"
+
+class Chef
+  class Knife
+    # Implements knife user key list using Chef::Knife::KeyList
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class ClientKeyList < Knife
+      include Chef::Knife::KeyListBase
+
+      banner "knife client key list CLIENT (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def list_method
+        :list_by_client
+      end
+
+      def actor_missing_error
+        "You must specify a client name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyList.new(@actor, list_method, ui, config)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/client_key_show.rb b/lib/chef/knife/client_key_show.rb
new file mode 100644
index 0000000..77f9e96
--- /dev/null
+++ b/lib/chef/knife/client_key_show.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+class Chef
+  class Knife
+    # Implements knife client key show using Chef::Knife::KeyShow
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class ClientKeyShow < Knife
+      banner "knife client key show CLIENT KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def load_method
+        :load_by_client
+      end
+
+      def actor_missing_error
+        "You must specify a client name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyShow.new(@name, @actor, load_method, ui)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/client_list.rb b/lib/chef/knife/client_list.rb
index da0bf12..b17de0f 100644
--- a/lib/chef/knife/client_list.rb
+++ b/lib/chef/knife/client_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientList < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       banner "knife client list (options)"
@@ -35,7 +35,7 @@ class Chef
         :description => "Show corresponding URIs"
 
       def run
-        output(format_list_for_display(Chef::ApiClient.list))
+        output(format_list_for_display(Chef::ApiClientV1.list))
       end
     end
   end
diff --git a/lib/chef/knife/client_reregister.rb b/lib/chef/knife/client_reregister.rb
index 666fd09..5d9b2c0 100644
--- a/lib/chef/knife/client_reregister.rb
+++ b/lib/chef/knife/client_reregister.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class ClientReregister < Knife
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       banner "knife client reregister CLIENT (options)"
@@ -43,7 +43,7 @@ class Chef
           exit 1
         end
 
-        client = Chef::ApiClient.reregister(@client_name)
+        client = Chef::ApiClientV1.reregister(@client_name)
         Chef::Log.debug("Updated client data: #{client.inspect}")
         key = client.private_key
         if config[:file]
diff --git a/lib/chef/knife/client_show.rb b/lib/chef/knife/client_show.rb
index 822848f..ce3bf45 100644
--- a/lib/chef/knife/client_show.rb
+++ b/lib/chef/knife/client_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,8 +25,8 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/api_client'
-        require 'chef/json_compat'
+        require "chef/api_client_v1"
+        require "chef/json_compat"
       end
 
       banner "knife client show CLIENT (options)"
@@ -40,7 +40,7 @@ class Chef
           exit 1
         end
 
-        client = Chef::ApiClient.load(@client_name)
+        client = Chef::ApiClientV1.load(@client_name)
         output(format_for_display(client))
       end
 
diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb
index 8bb8930..e62a9dd 100644
--- a/lib/chef/knife/configure.rb
+++ b/lib/chef/knife/configure.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,7 +25,7 @@ class Chef
       attr_reader :chef_repo, :new_client_key, :validation_client_name, :validation_key
 
       deps do
-        require 'ohai'
+        require "ohai"
         Chef::Knife::ClientCreate.load_deps
         Chef::Knife::UserCreate.load_deps
       end
@@ -61,7 +61,7 @@ class Chef
 
       def configure_chef
         # We are just faking out the system so that you can do this without a key specified
-        Chef::Config[:node_name] = 'woot'
+        Chef::Config[:node_name] = "woot"
         super
         Chef::Config[:node_name] = nil
       end
@@ -97,7 +97,7 @@ EOH
           user_create = Chef::Knife::UserCreate.new
           user_create.name_args = [ new_client_name ]
           user_create.config[:user_password] = config[:user_password] ||
-            ui.ask("Please enter a password for the new user: ") {|q| q.echo = false}
+                                               ui.ask("Please enter a password for the new user: ") { |q| q.echo = false }
           user_create.config[:admin] = true
           user_create.config[:file] = new_client_key
           user_create.config[:yes] = true
@@ -133,17 +133,17 @@ EOH
 
       def ask_user_for_config
         server_name = guess_servername
-        @chef_server            = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}:443")
+        @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}:443")
         if config[:initial]
           @new_client_name        = config[:node_name] || ask_question("Please enter a name for the new user: ", :default => Etc.getlogin)
-          @admin_client_name      = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => 'admin')
-          @admin_client_key       = config[:admin_client_key] || ask_question("Please enter the location of the existing admin's private key: ", :default => '/etc/chef-server/admin.pem')
+          @admin_client_name      = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => "admin")
+          @admin_client_key       = config[:admin_client_key] || ask_question("Please enter the location of the existing admin's private key: ", :default => "/etc/chef-server/admin.pem")
           @admin_client_key       = File.expand_path(@admin_client_key)
         else
           @new_client_name        = config[:node_name] || ask_question("Please enter an existing username or clientname for the API: ", :default => Etc.getlogin)
         end
-        @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => 'chef-validator')
-        @validation_key         = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => '/etc/chef-server/chef-validator.pem')
+        @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => "chef-validator")
+        @validation_key         = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => "/etc/chef-server/chef-validator.pem")
         @validation_key         = File.expand_path(@validation_key)
         @chef_repo              = config[:repository] || ask_question("Please enter the path to a chef repository (or leave blank): ")
 
@@ -154,9 +154,9 @@ EOH
       def guess_servername
         o = Ohai::System.new
         o.load_plugins
-        o.require_plugin 'os'
-        o.require_plugin 'hostname'
-        o[:fqdn] || o[:machinename] || o[:hostname] || 'localhost'
+        o.require_plugin "os"
+        o.require_plugin "hostname"
+        o[:fqdn] || o[:machinename] || o[:hostname] || "localhost"
       end
 
       def config_file
diff --git a/lib/chef/knife/configure_client.rb b/lib/chef/knife/configure_client.rb
index 838d9a1..7d0b3d2 100644
--- a/lib/chef/knife/configure_client.rb
+++ b/lib/chef/knife/configure_client.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -34,13 +34,13 @@ class Chef
         FileUtils.mkdir_p(@config_dir)
         ui.info("Writing client.rb")
         File.open(File.join(@config_dir, "client.rb"), "w") do |file|
-          file.puts('log_level        :info')
-          file.puts('log_location     STDOUT')
+          file.puts("log_level        :info")
+          file.puts("log_location     STDOUT")
           file.puts("chef_server_url  '#{Chef::Config[:chef_server_url]}'")
           file.puts("validation_client_name '#{Chef::Config[:validation_client_name]}'")
         end
         ui.info("Writing validation.pem")
-        File.open(File.join(@config_dir, 'validation.pem'), "w") do |validation|
+        File.open(File.join(@config_dir, "validation.pem"), "w") do |validation|
           validation.puts(IO.read(Chef::Config[:validation_key]))
         end
       end
diff --git a/lib/chef/knife/cookbook_bulk_delete.rb b/lib/chef/knife/cookbook_bulk_delete.rb
index 65fa888..6c2ad5a 100644
--- a/lib/chef/knife/cookbook_bulk_delete.rb
+++ b/lib/chef/knife/cookbook_bulk_delete.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookBulkDelete < Knife
 
       deps do
-        require 'chef/knife/cookbook_delete'
-        require 'chef/cookbook_version'
+        require "chef/knife/cookbook_delete"
+        require "chef/cookbook_version"
       end
 
-      option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store'
+      option :purge, :short => "-p", :long => "--purge", :boolean => true, :description => "Permanently remove files from backing data store"
 
       banner "knife cookbook bulk delete REGEX (options)"
 
@@ -58,11 +58,10 @@ class Chef
           ui.msg ""
         end
 
-
         cookbooks_names.each do |cookbook_name|
-          versions = rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map {|v| v["version"]}.flatten
+          versions = rest.get("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map { |v| v["version"] }.flatten
           versions.each do |version|
-            object = rest.delete_rest("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}")
+            object = rest.delete("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}")
             ui.info("Deleted cookbook  #{cookbook_name.ljust(25)} [#{version}]")
           end
         end
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index e17a540..1e19535 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookCreate < Knife
 
       deps do
-        require 'chef/json_compat'
-        require 'uri'
-        require 'fileutils'
+        require "chef/json_compat"
+        require "uri"
+        require "fileutils"
       end
 
       banner "knife cookbook create COOKBOOK (options)"
@@ -48,7 +48,7 @@ class Chef
       option :cookbook_copyright,
         :short => "-C COPYRIGHT",
         :long => "--copyright COPYRIGHT",
-        :description => "Name of Copyright holder"
+        :description => "Name of copyright holder"
 
       option :cookbook_email,
         :short => "-m EMAIL",
@@ -182,11 +182,11 @@ EOH
 
       def create_changelog(dir, cookbook_name)
         msg("** Creating CHANGELOG for cookbook: #{cookbook_name}")
-        unless File.exists?(File.join(dir,cookbook_name,'CHANGELOG.md'))
-          open(File.join(dir, cookbook_name, 'CHANGELOG.md'),'w') do |file|
+        unless File.exists?(File.join(dir, cookbook_name, "CHANGELOG.md"))
+          open(File.join(dir, cookbook_name, "CHANGELOG.md"), "w") do |file|
             file.puts <<-EOH
 #{cookbook_name} CHANGELOG
-#{'='*"#{cookbook_name} CHANGELOG".length}
+#{'=' * "#{cookbook_name} CHANGELOG".length}
 
 This file is used to list changes made in each version of the #{cookbook_name} cookbook.
 
@@ -271,10 +271,10 @@ e.g.
 == License and Authors
 Authors: TODO: List authors
 EOH
-            when "md","mkd","txt"
+            when "md", "mkd", "txt"
               file.puts <<-EOH
 #{cookbook_name} Cookbook
-#{'='*"#{cookbook_name} Cookbook".length}
+#{'=' * "#{cookbook_name} Cookbook".length}
 TODO: Enter the cookbook description here.
 
 e.g.
@@ -345,7 +345,7 @@ EOH
             else
               file.puts <<-EOH
 #{cookbook_name} Cookbook
-#{'='*"#{cookbook_name} Cookbook".length}
+#{'=' * "#{cookbook_name} Cookbook".length}
   TODO: Enter the cookbook description here.
 
   e.g.
diff --git a/lib/chef/knife/cookbook_delete.rb b/lib/chef/knife/cookbook_delete.rb
index f436d27..b1bb88b 100644
--- a/lib/chef/knife/cookbook_delete.rb
+++ b/lib/chef/knife/cookbook_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,12 +25,12 @@ class Chef
       attr_accessor :cookbook_name, :version
 
       deps do
-        require 'chef/cookbook_version'
+        require "chef/cookbook_version"
       end
 
-      option :all, :short => '-a', :long => '--all', :boolean => true, :description => 'delete all versions'
+      option :all, :short => "-a", :long => "--all", :boolean => true, :description => "delete all versions"
 
-      option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store'
+      option :purge, :short => "-p", :long => "--purge", :boolean => true, :description => "Permanently remove files from backing data store"
 
       banner "knife cookbook delete COOKBOOK VERSION (options)"
 
@@ -85,8 +85,8 @@ class Chef
       end
 
       def available_versions
-        @available_versions ||= rest.get_rest("cookbooks/#{@cookbook_name}").map do |name, url_and_version|
-          url_and_version["versions"].map {|url_by_version| url_by_version["version"]}
+        @available_versions ||= rest.get("cookbooks/#{@cookbook_name}").map do |name, url_and_version|
+          url_and_version["versions"].map { |url_by_version| url_by_version["version"] }
         end.flatten
       rescue Net::HTTPServerException => e
         if e.to_s =~ /^404/
@@ -106,7 +106,7 @@ class Chef
         end
         valid_responses[(available_versions.size + 1).to_s] = :all
         question << "#{available_versions.size + 1}. All versions\n\n"
-        responses = ask_question(question).split(',').map { |response| response.strip }
+        responses = ask_question(question).split(",").map { |response| response.strip }
 
         if responses.empty?
           ui.error("No versions specified, exiting")
@@ -143,7 +143,7 @@ class Chef
 
       def delete_request(path)
         path += "?purge=true" if config[:purge]
-        rest.delete_rest(path)
+        rest.delete(path)
       end
 
     end
diff --git a/lib/chef/knife/cookbook_download.rb b/lib/chef/knife/cookbook_download.rb
index cb8eeb8..741f444 100644
--- a/lib/chef/knife/cookbook_download.rb
+++ b/lib/chef/knife/cookbook_download.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -27,7 +27,7 @@ class Chef
       attr_accessor :cookbook_name
 
       deps do
-        require 'chef/cookbook_version'
+        require "chef/cookbook_version"
       end
 
       banner "knife cookbook download COOKBOOK [VERSION] (options)"
@@ -69,7 +69,7 @@ class Chef
 
         ui.info("Downloading #{@cookbook_name} cookbook version #{@version}")
 
-        cookbook = rest.get_rest("cookbooks/#{@cookbook_name}/#{@version}")
+        cookbook = Chef::CookbookVersion.load(@cookbook_name, @version)
         manifest = cookbook.manifest
 
         basedir = File.join(config[:download_directory], "#{@cookbook_name}-#{cookbook.version}")
@@ -87,11 +87,10 @@ class Chef
           next unless manifest.has_key?(segment)
           ui.info("Downloading #{segment}")
           manifest[segment].each do |segment_file|
-            dest = File.join(basedir, segment_file['path'].gsub('/', File::SEPARATOR))
+            dest = File.join(basedir, segment_file["path"].gsub("/", File::SEPARATOR))
             Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}")
             FileUtils.mkdir_p(File.dirname(dest))
-            rest.sign_on_redirect = false
-            tempfile = rest.get_rest(segment_file['url'], true)
+            tempfile = rest.streaming_request(segment_file["url"])
             FileUtils.mv(tempfile.path, dest)
           end
         end
@@ -99,7 +98,6 @@ class Chef
       end
 
       def determine_version
-
         if available_versions.nil?
           nil
         elsif available_versions.size == 1
diff --git a/lib/chef/knife/cookbook_list.rb b/lib/chef/knife/cookbook_list.rb
index 75f18a1..ea81f5d 100644
--- a/lib/chef/knife/cookbook_list.rb
+++ b/lib/chef/knife/cookbook_list.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -39,7 +39,7 @@ class Chef
         env          = config[:environment]
         num_versions = config[:all_versions] ? "num_versions=all" : "num_versions=1"
         api_endpoint = env ? "/environments/#{env}/cookbooks?#{num_versions}" : "/cookbooks?#{num_versions}"
-        cookbook_versions = rest.get_rest(api_endpoint)
+        cookbook_versions = rest.get(api_endpoint)
         ui.output(format_cookbook_list_for_display(cookbook_versions))
       end
     end
diff --git a/lib/chef/knife/cookbook_metadata.rb b/lib/chef/knife/cookbook_metadata.rb
index dfa69ae..b13ab18 100644
--- a/lib/chef/knife/cookbook_metadata.rb
+++ b/lib/chef/knife/cookbook_metadata.rb
@@ -1,7 +1,7 @@
 #
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookMetadata < Knife
 
       deps do
-        require 'chef/cookbook_loader'
-        require 'chef/cookbook/metadata'
+        require "chef/cookbook_loader"
+        require "chef/cookbook/metadata"
       end
 
       banner "knife cookbook metadata COOKBOOK (options)"
@@ -62,7 +62,7 @@ class Chef
 
       def generate_metadata(cookbook)
         Array(config[:cookbook_path]).reverse.each do |path|
-          file = File.expand_path(File.join(path, cookbook, 'metadata.rb'))
+          file = File.expand_path(File.join(path, cookbook, "metadata.rb"))
           if File.exists?(file)
             generate_metadata_from_file(cookbook, file)
           else
@@ -76,7 +76,7 @@ class Chef
         md = Chef::Cookbook::Metadata.new
         md.name(cookbook)
         md.from_file(file)
-        json_file = File.join(File.dirname(file), 'metadata.json')
+        json_file = File.join(File.dirname(file), "metadata.json")
         File.open(json_file, "w") do |f|
           f.write(Chef::JSONCompat.to_json_pretty(md))
         end
@@ -91,7 +91,7 @@ class Chef
       end
 
       def validate_metadata_json(path, cookbook)
-        json_file = File.join(path, cookbook, 'metadata.json')
+        json_file = File.join(path, cookbook, "metadata.json")
         if File.exist?(json_file)
           Chef::Cookbook::Metadata.validate_json(IO.read(json_file))
         end
diff --git a/lib/chef/knife/cookbook_metadata_from_file.rb b/lib/chef/knife/cookbook_metadata_from_file.rb
index 8e26251..ec46379 100644
--- a/lib/chef/knife/cookbook_metadata_from_file.rb
+++ b/lib/chef/knife/cookbook_metadata_from_file.rb
@@ -1,9 +1,9 @@
 #
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Matthew Kent
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookMetadataFromFile < Knife
 
       deps do
-        require 'chef/cookbook/metadata'
+        require "chef/cookbook/metadata"
       end
 
       banner "knife cookbook metadata from FILE (options)"
diff --git a/lib/chef/knife/cookbook_show.rb b/lib/chef/knife/cookbook_show.rb
index 7c9cbeb..5fab7c3 100644
--- a/lib/chef/knife/cookbook_show.rb
+++ b/lib/chef/knife/cookbook_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookShow < Knife
 
       deps do
-        require 'chef/json_compat'
-        require 'uri'
-        require 'chef/cookbook_version'
+        require "chef/json_compat"
+        require "uri"
+        require "chef/cookbook_version"
       end
 
       banner "knife cookbook show COOKBOOK [VERSION] [PART] [FILENAME] (options)"
@@ -65,28 +65,28 @@ class Chef
           end
 
           cookbook_name, segment, filename = @name_args[0], @name_args[2], @name_args[3]
-          cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
+          cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
 
-          cookbook = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}")
+          cookbook = rest.get("cookbooks/#{cookbook_name}/#{cookbook_version}")
           manifest_entry = cookbook.preferred_manifest_record(node, segment, filename)
-          temp_file = rest.get_rest(manifest_entry[:url], true)
+          temp_file = rest.streaming_request(manifest_entry[:url])
 
           # the temp file is cleaned up elsewhere
           temp_file.open if temp_file.closed?
           pretty_print(temp_file.read)
 
         when 3 # We are showing a specific part of the cookbook
-          cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
-          result = rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}")
+          cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
+          result = rest.get("cookbooks/#{@name_args[0]}/#{cookbook_version}")
           output(result.manifest[@name_args[2]])
         when 2 # We are showing the whole cookbook data
-          cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
-          output(rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}"))
+          cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
+          output(rest.get("cookbooks/#{@name_args[0]}/#{cookbook_version}"))
         when 1 # We are showing the cookbook versions (all of them)
           cookbook_name = @name_args[0]
           env           = config[:environment]
           api_endpoint  = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}"
-          output(format_cookbook_list_for_display(rest.get_rest(api_endpoint)))
+          output(format_cookbook_list_for_display(rest.get(api_endpoint)))
         when 0
           show_usage
           ui.fatal("You must specify a cookbook name")
@@ -96,7 +96,3 @@ class Chef
     end
   end
 end
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_download.rb b/lib/chef/knife/cookbook_site_download.rb
index c2d72ef..2bdeea9 100644
--- a/lib/chef/knife/cookbook_site_download.rb
+++ b/lib/chef/knife/cookbook_site_download.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookSiteDownload < Knife
 
       deps do
-        require 'fileutils'
+        require "fileutils"
       end
 
       banner "knife cookbook site download COOKBOOK [VERSION] (options)"
@@ -39,12 +39,12 @@ class Chef
 
       def run
         if current_cookbook_deprecated?
-          message = 'DEPRECATION: This cookbook has been deprecated. '
+          message = "DEPRECATION: This cookbook has been deprecated. "
           message << "It has been replaced by #{replacement_cookbook}."
           ui.warn message
 
           unless config[:force]
-            ui.warn 'Use --force to force download deprecated cookbook.'
+            ui.warn "Use --force to force download deprecated cookbook."
             return
           end
         end
@@ -53,40 +53,40 @@ class Chef
       end
 
       def version
-        @version = desired_cookbook_data['version']
+        @version = desired_cookbook_data["version"]
       end
 
       private
+
       def cookbooks_api_url
-        'https://supermarket.chef.io/api/v1/cookbooks'
+        "https://supermarket.chef.io/api/v1/cookbooks"
       end
 
       def current_cookbook_data
         @current_cookbook_data ||= begin
-          noauth_rest.get_rest "#{cookbooks_api_url}/#{@name_args[0]}"
-        end
+                                     noauth_rest.get "#{cookbooks_api_url}/#{@name_args[0]}"
+                                   end
       end
 
       def current_cookbook_deprecated?
-        current_cookbook_data['deprecated'] == true
+        current_cookbook_data["deprecated"] == true
       end
 
       def desired_cookbook_data
         @desired_cookbook_data ||= begin
-          uri = if @name_args.length == 1
-            current_cookbook_data['latest_version']
-          else
-            specific_cookbook_version_url
-          end
-
-          noauth_rest.get_rest uri
-        end
+                                     uri = if @name_args.length == 1
+                                             current_cookbook_data["latest_version"]
+                                           else
+                                             specific_cookbook_version_url
+                                           end
+
+                                     noauth_rest.get uri
+                                   end
       end
 
       def download_cookbook
-        ui.info "Downloading #{@name_args[0]} from the cookbooks site at version #{version} to #{download_location}"
-        noauth_rest.sign_on_redirect = false
-        tf = noauth_rest.get_rest desired_cookbook_data["file"], true
+        ui.info "Downloading #{@name_args[0]} from Supermarket at version #{version} to #{download_location}"
+        tf = noauth_rest.streaming_request(desired_cookbook_data["file"])
 
         ::FileUtils.cp tf.path, download_location
         ui.info "Cookbook saved: #{download_location}"
@@ -98,7 +98,7 @@ class Chef
       end
 
       def replacement_cookbook
-        replacement = File.basename(current_cookbook_data['replacement'])
+        replacement = File.basename(current_cookbook_data["replacement"])
       end
 
       def specific_cookbook_version_url
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index d0ab6da..9a79cd0 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/exceptions'
-require 'shellwords'
+require "chef/knife"
+require "chef/exceptions"
+require "shellwords"
 
 class Chef
   class Knife
     class CookbookSiteInstall < Knife
 
       deps do
-        require 'chef/mixin/shell_out'
-        require 'chef/knife/core/cookbook_scm_repo'
-        require 'chef/cookbook/metadata'
+        require "chef/mixin/shell_out"
+        require "chef/knife/core/cookbook_scm_repo"
+        require "chef/cookbook/metadata"
       end
 
       banner "knife cookbook site install COOKBOOK [VERSION] (options)"
@@ -93,7 +93,7 @@ class Chef
 
         # TODO: it'd be better to store these outside the cookbook repo and
         # keep them around, e.g., in ~/Library/Caches on OS X.
-        ui.info("removing downloaded tarball")
+        ui.info("Removing downloaded tarball")
         File.unlink(upstream_file)
 
         if @repo.finalize_updates_to(@cookbook_name, downloader.version)
@@ -142,7 +142,11 @@ class Chef
       def extract_cookbook(upstream_file, version)
         ui.info("Uncompressing #{@cookbook_name} version #{version}.")
         # FIXME: Detect if we have the bad tar from git on Windows: https://github.com/opscode/chef/issues/1753
-        shell_out!("tar zxvf #{convert_path upstream_file}", :cwd => @install_path)
+        extract_command = "tar zxvf \"#{convert_path upstream_file}\""
+        if Chef::Platform.windows?
+          extract_command << " --force-local"
+        end
+        shell_out!(extract_command, :cwd => @install_path)
       end
 
       def clear_existing_files(cookbook_path)
@@ -152,7 +156,7 @@ class Chef
 
       def convert_path(upstream_file)
         # converts a Windows path (C:\foo) to a mingw path (/c/foo)
-        if ENV['MSYSTEM'] == 'MINGW32'
+        if ENV["MSYSTEM"] == "MINGW32"
           return upstream_file.sub(/^([[:alpha:]]):/, '/\1')
         else
           return Shellwords.escape upstream_file
diff --git a/lib/chef/knife/cookbook_site_list.rb b/lib/chef/knife/cookbook_site_list.rb
index 846123c..abe48bf 100644
--- a/lib/chef/knife/cookbook_site_list.rb
+++ b/lib/chef/knife/cookbook_site_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -33,16 +33,16 @@ class Chef
       def run
         if config[:with_uri]
           cookbooks = Hash.new
-          get_cookbook_list.each{ |k,v| cookbooks[k] = v['cookbook'] }
+          get_cookbook_list.each { |k, v| cookbooks[k] = v["cookbook"] }
           ui.output(format_for_display(cookbooks))
         else
           ui.msg(ui.list(get_cookbook_list.keys.sort, :columns_down))
         end
       end
 
-      def get_cookbook_list(items=10, start=0, cookbook_collection={})
+      def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
         cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
-        cr = noauth_rest.get_rest(cookbooks_url)
+        cr = noauth_rest.get(cookbooks_url)
         cr["items"].each do |cookbook|
           cookbook_collection[cookbook["cookbook_name"]] = cookbook
         end
@@ -56,7 +56,3 @@ class Chef
     end
   end
 end
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_search.rb b/lib/chef/knife/cookbook_site_search.rb
index 0baaf90..ba4b873 100644
--- a/lib/chef/knife/cookbook_site_search.rb
+++ b/lib/chef/knife/cookbook_site_search.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -28,9 +28,9 @@ class Chef
         output(search_cookbook(name_args[0]))
       end
 
-      def search_cookbook(query, items=10, start=0, cookbook_collection={})
+      def search_cookbook(query, items = 10, start = 0, cookbook_collection = {})
         cookbooks_url = "https://supermarket.chef.io/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
-        cr = noauth_rest.get_rest(cookbooks_url)
+        cr = noauth_rest.get(cookbooks_url)
         cr["items"].each do |cookbook|
           cookbook_collection[cookbook["cookbook_name"]] = cookbook
         end
@@ -44,8 +44,3 @@ class Chef
     end
   end
 end
-
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index efd2e7f..fc5517c 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -1,6 +1,6 @@
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/mixin/shell_out'
+require "chef/knife"
+require "chef/mixin/shell_out"
 
 class Chef
   class Knife
@@ -26,10 +26,10 @@ class Chef
       include Chef::Mixin::ShellOut
 
       deps do
-        require 'chef/cookbook_loader'
-        require 'chef/cookbook_uploader'
-        require 'chef/cookbook_site_streaming_uploader'
-        require 'mixlib/shellout'
+        require "chef/cookbook_loader"
+        require "chef/cookbook_uploader"
+        require "chef/cookbook_site_streaming_uploader"
+        require "mixlib/shellout"
       end
 
       include Chef::Mixin::ShellOut
@@ -44,11 +44,11 @@ class Chef
         :proc => lambda { |o| Chef::Config.cookbook_path = o.split(":") }
 
       option :dry_run,
-        :long => '--dry-run',
-        :short => '-n',
+        :long => "--dry-run",
+        :short => "-n",
         :boolean => true,
         :default => false,
-        :description => "Don't take action, only print what files will be upload to SuperMarket."
+        :description => "Don't take action, only print what files will be uploaded to Supermarket."
 
       def run
         config[:cookbook_path] ||= Chef::Config[:cookbook_path]
@@ -94,7 +94,7 @@ class Chef
             Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}")
             FileUtils.rm_rf tmp_cookbook_dir
           rescue => e
-            ui.error("Error uploading cookbook #{cookbook_name} to the Opscode Cookbook Site: #{e.message}. Increase log verbosity (-VV) for more information.")
+            ui.error("Error uploading cookbook #{cookbook_name} to Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
             Chef::Log.debug("\n#{e.backtrace.join("\n")}")
             exit(1)
           end
@@ -103,20 +103,19 @@ class Chef
           ui.error("Could not find cookbook #{cookbook_name} in your cookbook path.")
           exit(1)
         end
-
       end
 
       def get_category(cookbook_name)
         begin
-          data = noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}")
+          data = noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
           if !data["category"] && data["error_code"]
-            ui.fatal("Received an error from the Opscode Cookbook site: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
+            ui.fatal("Received an error from Supermarket: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
             exit(1)
           else
-            data['category']
+            data["category"]
           end
         rescue => e
-          ui.fatal("Unable to reach Opscode Cookbook Site: #{e.message}. Increase log verbosity (-VV) for more information.")
+          ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
           Chef::Log.debug("\n#{e.backtrace.join("\n")}")
           exit(1)
         end
@@ -125,18 +124,18 @@ class Chef
       def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
         uri = "https://supermarket.chef.io/api/v1/cookbooks"
 
-        category_string = Chef::JSONCompat.to_json({ 'category'=>cookbook_category })
+        category_string = Chef::JSONCompat.to_json({ "category" => cookbook_category })
 
         http_resp = Chef::CookbookSiteStreamingUploader.post(uri, user_id, user_secret_filename, {
           :tarball => File.open(cookbook_filename),
-          :cookbook => category_string
+          :cookbook => category_string,
         })
 
         res = Chef::JSONCompat.from_json(http_resp.body)
         if http_resp.code.to_i != 201
-          if res['error_messages']
-            if res['error_messages'][0] =~ /Version already exists/
-              ui.error "The same version of this cookbook already exists on the Opscode Cookbook Site."
+          if res["error_messages"]
+            if res["error_messages"][0] =~ /Version already exists/
+              ui.error "The same version of this cookbook already exists on Supermarket."
               exit(1)
             else
               ui.error "#{res['error_messages'][0]}"
diff --git a/lib/chef/knife/cookbook_site_show.rb b/lib/chef/knife/cookbook_site_show.rb
index 6b65b62..a6a4c82 100644
--- a/lib/chef/knife/cookbook_site_show.rb
+++ b/lib/chef/knife/cookbook_site_show.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -31,15 +31,15 @@ class Chef
       def get_cookbook_data
         case @name_args.length
         when 1
-          noauth_rest.get_rest("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
+          noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
         when 2
-          noauth_rest.get_rest("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].gsub('.', '_')}")
+          noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].gsub('.', '_')}")
         end
       end
 
-      def get_cookbook_list(items=10, start=0, cookbook_collection={})
+      def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
         cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
-        cr = noauth_rest.get_rest(cookbooks_url)
+        cr = noauth_rest.get(cookbooks_url)
         cr["items"].each do |cookbook|
           cookbook_collection[cookbook["cookbook_name"]] = cookbook
         end
@@ -53,8 +53,3 @@ class Chef
     end
   end
 end
-
-
-
-
-
diff --git a/lib/chef/knife/cookbook_site_unshare.rb b/lib/chef/knife/cookbook_site_unshare.rb
index b34282e..310f6ac 100644
--- a/lib/chef/knife/cookbook_site_unshare.rb
+++ b/lib/chef/knife/cookbook_site_unshare.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,14 +17,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookSiteUnshare < Knife
 
       deps do
-        require 'chef/json_compat'
+        require "chef/json_compat"
       end
 
       banner "knife cookbook site unshare COOKBOOK"
@@ -38,17 +38,17 @@ class Chef
           exit 1
         end
 
-        confirm "Do you really want to unshare the cookbook #{@cookbook_name}"
+        confirm "Do you really want to unshare all versions of the cookbook #{@cookbook_name}"
 
         begin
-          rest.delete_rest "https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}"
+          rest.delete "https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}"
         rescue Net::HTTPServerException => e
           raise e unless e.message =~ /Forbidden/
           ui.error "Forbidden: You must be the maintainer of #{@cookbook_name} to unshare it."
           exit 1
         end
 
-        ui.info "Unshared cookbook #{@cookbook_name}"
+        ui.info "Unshared all versions of the cookbook #{@cookbook_name}"
       end
 
     end
diff --git a/lib/chef/knife/cookbook_site_vendor.rb b/lib/chef/knife/cookbook_site_vendor.rb
index 8257595..291715c 100644
--- a/lib/chef/knife/cookbook_site_vendor.rb
+++ b/lib/chef/knife/cookbook_site_vendor.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/cookbook_site_install'
+require "chef/knife"
+require "chef/knife/cookbook_site_install"
 
 class Chef::Knife::CookbookSiteVendor < Chef::Knife::CookbookSiteInstall
 
@@ -41,6 +41,6 @@ DEPRECATED: please use knife cookbook site install
 #{superclass.banner}
 B
 
-  category 'deprecated'
+  category "deprecated"
 
 end
diff --git a/lib/chef/knife/cookbook_test.rb b/lib/chef/knife/cookbook_test.rb
index 91e0b55..ee42fac 100644
--- a/lib/chef/knife/cookbook_test.rb
+++ b/lib/chef/knife/cookbook_test.rb
@@ -1,9 +1,9 @@
 #
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Matthew Kent
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,15 +18,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class CookbookTest < Knife
 
       deps do
-        require 'chef/cookbook_loader'
-        require 'chef/cookbook/syntax_check'
+        require "chef/cookbook_loader"
+        require "chef/cookbook/syntax_check"
       end
 
       banner "knife cookbook test [COOKBOOKS...] (options)"
@@ -76,7 +76,6 @@ class Chef
         end
       end
 
-
       def test_ruby(syntax_checker)
         ui.info("Validating ruby files")
         exit(1) unless syntax_checker.validate_ruby_files
diff --git a/lib/chef/knife/cookbook_upload.rb b/lib/chef/knife/cookbook_upload.rb
index b2acd74..e16e21a 100644
--- a/lib/chef/knife/cookbook_upload.rb
+++ b/lib/chef/knife/cookbook_upload.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
 # Author:: Nuo Yan (<yan.nuo at gmail.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/cookbook_uploader'
+require "chef/knife"
+require "chef/cookbook_uploader"
 
 class Chef
   class Knife
@@ -29,9 +29,9 @@ class Chef
       MATCH_CHECKSUM = /[0-9a-f]{32,}/
 
       deps do
-        require 'chef/exceptions'
-        require 'chef/cookbook_loader'
-        require 'chef/cookbook_uploader'
+        require "chef/exceptions"
+        require "chef/cookbook_loader"
+        require "chef/cookbook_uploader"
       end
 
       banner "knife cookbook upload [COOKBOOKS...] (options)"
@@ -43,8 +43,8 @@ class Chef
         :proc => lambda { |o| o.split(":") }
 
       option :freeze,
-        :long => '--freeze',
-        :description => 'Freeze this version of the cookbook so that it cannot be overwritten',
+        :long => "--freeze",
+        :description => "Freeze this version of the cookbook so that it cannot be overwritten",
         :boolean => true
 
       option :all,
@@ -53,19 +53,19 @@ class Chef
         :description => "Upload all cookbooks, rather than just a single cookbook"
 
       option :force,
-        :long => '--force',
+        :long => "--force",
         :boolean => true,
         :description => "Update cookbook versions even if they have been frozen"
 
       option :concurrency,
-        :long => '--concurrency NUMBER_OF_THREADS',
+        :long => "--concurrency NUMBER_OF_THREADS",
         :description => "How many concurrent threads will be used",
         :default => 10,
         :proc => lambda { |o| o.to_i }
 
       option :environment,
-        :short => '-E',
-        :long  => '--environment ENVIRONMENT',
+        :short => "-E",
+        :long  => "--environment ENVIRONMENT",
         :description => "Set ENVIRONMENT's version dependency match the version you're uploading.",
         :default => nil
 
@@ -101,7 +101,7 @@ class Chef
         # Get a list of cookbooks and their versions from the server
         # to check for the existence of a cookbook's dependencies.
         @server_side_cookbooks = Chef::CookbookVersion.list_all_versions
-        justify_width = @server_side_cookbooks.map {|name| name.size}.max.to_i + 2
+        justify_width = @server_side_cookbooks.map { |name| name.size }.max.to_i + 2
         if config[:all]
           cookbook_repo.load_cookbooks
           cookbooks_for_upload = []
@@ -118,7 +118,7 @@ class Chef
             end
             ui.info("Uploaded all cookbooks.")
           else
-            cookbook_path = config[:cookbook_path].respond_to?(:join) ? config[:cookbook_path].join(', ') : config[:cookbook_path]
+            cookbook_path = config[:cookbook_path].respond_to?(:join) ? config[:cookbook_path].join(", ") : config[:cookbook_path]
             ui.warn("Could not find any cookbooks in your cookbook path: #{cookbook_path}. Use --cookbook-path to specify the desired path.")
           end
         else
@@ -145,7 +145,6 @@ class Chef
             end
           end
 
-
           upload_failures += @name_args.length - @cookbooks_to_upload.length
 
           if upload_failures == 0
@@ -259,7 +258,7 @@ WARNING
           info[CHECKSUM].nil? || info[CHECKSUM] !~ MATCH_CHECKSUM
         end
         unless broken_files.empty?
-          broken_filenames = Array(broken_files).map {|path, info| path}
+          broken_filenames = Array(broken_files).map { |path, info| path }
           ui.error "The cookbook #{cookbook.name} has one or more broken files"
           ui.error "This is probably caused by broken symlinks in the cookbook directory"
           ui.error "The broken file(s) are: #{broken_filenames.join(' ')}"
@@ -275,7 +274,7 @@ WARNING
         end
 
         unless missing_dependencies.empty?
-          missing_cookbook_names = missing_dependencies.map { |cookbook_name, version|  "'#{cookbook_name}' version '#{version}'"}
+          missing_cookbook_names = missing_dependencies.map { |cookbook_name, version| "'#{cookbook_name}' version '#{version}'" }
           ui.error "Cookbook #{cookbook.name} depends on cookbooks which are not currently"
           ui.error "being uploaded and cannot be found on the server."
           ui.error "The missing cookbook(s) are: #{missing_cookbook_names.join(', ')}"
@@ -287,7 +286,7 @@ WARNING
         if @server_side_cookbooks[cookbook_name].nil?
           false
         else
-          versions = @server_side_cookbooks[cookbook_name]['versions'].collect {|versions| versions["version"]}
+          versions = @server_side_cookbooks[cookbook_name]["versions"].collect { |versions| versions["version"] }
           Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}"
           @server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
             if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 7197653..a863e0c 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/run_list'
-require 'chef/util/path_helper'
+require "chef/run_list"
+require "chef/util/path_helper"
 
 class Chef
   class Knife
@@ -40,7 +40,7 @@ class Chef
         end
 
         def bootstrap_environment
-          @chef_config[:environment] || '_default'
+          @config[:environment]
         end
 
         def validation_key
@@ -66,7 +66,7 @@ class Chef
 log_location     STDOUT
 chef_server_url  "#{@chef_config[:chef_server_url]}"
 validation_client_name "#{@chef_config[:validation_client_name]}"
-CONFIG
+          CONFIG
           if @config[:chef_node_name]
             client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
           else
@@ -84,15 +84,15 @@ CONFIG
           # or when specified in the knife config.
           if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
             value = case @config[:node_ssl_verify_mode]
-            when "peer"
-              :verify_peer
-            when "none"
-              :verify_none
-            when nil
-              knife_config[:ssl_verify_mode]
-            else
-              nil
-            end
+                    when "peer"
+                      :verify_peer
+                    when "none"
+                      :verify_none
+                    when nil
+                      knife_config[:ssl_verify_mode]
+                    else
+                      nil
+                    end
 
             if value
               client_rb << %Q{ssl_verify_mode :#{value}\n}
@@ -120,15 +120,20 @@ CONFIG
             client_rb << %Q{trusted_certs_dir "/etc/chef/trusted_certs"\n}
           end
 
+          if Chef::Config[:fips]
+            client_rb << %Q{fips true\n}
+          end
+
           client_rb
         end
 
         def start_chef
           # If the user doesn't have a client path configure, let bash use the PATH for what it was designed for
-          client_path = @chef_config[:chef_client_path] || 'chef-client'
+          client_path = @chef_config[:chef_client_path] || "chef-client"
           s = "#{client_path} -j /etc/chef/first-boot.json"
-          s << ' -l debug' if @config[:verbosity] and @config[:verbosity] >= 2
-          s << " -E #{bootstrap_environment}"
+          s << " -l debug" if @config[:verbosity] and @config[:verbosity] >= 2
+          s << " -E #{bootstrap_environment}" unless bootstrap_environment.nil?
+          s << " --no-color" unless @config[:color]
           s
         end
 
@@ -146,10 +151,10 @@ CONFIG
             installer_version_string = ["-p"]
           else
             chef_version_string = if knife_config[:bootstrap_version]
-              knife_config[:bootstrap_version]
-            else
-              Chef::VERSION.split(".").first
-            end
+                                    knife_config[:bootstrap_version]
+                                  else
+                                    Chef::VERSION.split(".").first
+                                  end
 
             installer_version_string = ["-v", chef_version_string]
 
@@ -163,11 +168,19 @@ CONFIG
         end
 
         def first_boot
-          (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list)
+          (@config[:first_boot_attributes] || {}).tap do |attributes|
+            if @config[:policy_name] && @config[:policy_group]
+              attributes.merge!(:policy_name => @config[:policy_name], :policy_group => @config[:policy_group])
+            else
+              attributes.merge!(:run_list => @run_list)
+            end
+
+            attributes.merge!(:tags => @config[:tags]) if @config[:tags] && !@config[:tags].empty?
+          end
         end
 
         private
-       
+
         # Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped
         # This string should contain both the commands necessary to both create the files, as well as their content
         def trusted_certs_content
@@ -175,7 +188,7 @@ CONFIG
           if @chef_config[:trusted_certs_dir]
             Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
               content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" +
-                         IO.read(File.expand_path(cert)) + "\nEOP\n"
+                IO.read(File.expand_path(cert)) + "\nEOP\n"
             end
           end
           content
diff --git a/lib/chef/knife/core/cookbook_scm_repo.rb b/lib/chef/knife/core/cookbook_scm_repo.rb
index 727cff3..e909066 100644
--- a/lib/chef/knife/core/cookbook_scm_repo.rb
+++ b/lib/chef/knife/core/cookbook_scm_repo.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/shell_out'
+require "chef/mixin/shell_out"
 
 class Chef
   class Knife
@@ -31,10 +31,10 @@ class Chef
       attr_reader :use_current_branch
       attr_reader :ui
 
-      def initialize(repo_path, ui, opts={})
+      def initialize(repo_path, ui, opts = {})
         @repo_path = repo_path
         @ui = ui
-        @default_branch = 'master'
+        @default_branch = "master"
         @use_current_branch = false
         apply_opts(opts)
       end
@@ -57,7 +57,7 @@ class Chef
           ui.info "If this is a new git repo, make sure you have at least one commit before installing cookbooks"
           exit 1
         end
-        cmd = git('status --porcelain')
+        cmd = git("status --porcelain")
         if cmd.stdout =~ DIRTY_REPO
           ui.error "You have uncommitted changes to your cookbook repo (#{repo_path}):"
           ui.msg cmd.stdout
@@ -119,18 +119,18 @@ class Chef
       end
 
       def branch_exists?(branch_name)
-        git("branch --no-color").stdout.lines.any? {|l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ }
+        git("branch --no-color").stdout.lines.any? { |l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ }
       end
 
       def get_current_branch()
         ref = git("symbolic-ref HEAD").stdout
-        ref.chomp.split('/')[2]
+        ref.chomp.split("/")[2]
       end
 
       private
 
       def git_repo?(directory)
-        if File.directory?(File.join(directory, '.git'))
+        if File.directory?(File.join(directory, ".git"))
           return true
         elsif File.dirname(directory) == directory
           return false
@@ -142,9 +142,9 @@ class Chef
       def apply_opts(opts)
         opts.each do |option, value|
           case option.to_s
-          when 'default_branch'
+          when "default_branch"
             @default_branch = value
-          when 'use_current_branch'
+          when "use_current_branch"
             @use_current_branch = value
           end
         end
@@ -157,4 +157,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/core/custom_manifest_loader.rb b/lib/chef/knife/core/custom_manifest_loader.rb
new file mode 100644
index 0000000..e5ebce2
--- /dev/null
+++ b/lib/chef/knife/core/custom_manifest_loader.rb
@@ -0,0 +1,69 @@
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/version"
+class Chef
+  class Knife
+    class SubcommandLoader
+
+      #
+      # Load a subcommand from a user-supplied
+      # manifest file
+      #
+      class CustomManifestLoader < Chef::Knife::SubcommandLoader
+        attr_accessor :manifest
+        def initialize(chef_config_dir, plugin_manifest)
+          super(chef_config_dir)
+          @manifest = plugin_manifest
+        end
+
+        # If the user has created a ~/.chef/plugin_manifest.json file, we'll use
+        # that instead of inspecting the on-system gems to find the plugins. The
+        # file format is expected to look like:
+        #
+        #   { "plugins": {
+        #       "knife-ec2": {
+        #         "paths": [
+        #           "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_create.rb",
+        #           "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_delete.rb"
+        #         ]
+        #       }
+        #     }
+        #   }
+        #
+        # Extraneous content in this file is ignored. This is intentional so that we
+        # can adapt the file format for potential behavior changes to knife in
+        # the future.
+        def find_subcommands_via_manifest
+          # Format of subcommand_files is "relative_path" (something you can
+          # Kernel.require()) => full_path. The relative path isn't used
+          # currently, so we just map full_path => full_path.
+          subcommand_files = {}
+          manifest["plugins"].each do |plugin_name, plugin_manifest|
+            plugin_manifest["paths"].each do |cmd_path|
+              subcommand_files[cmd_path] = cmd_path
+            end
+          end
+          subcommand_files.merge(find_subcommands_via_dirglob)
+        end
+
+        def subcommand_files
+          subcommand_files ||= (find_subcommands_via_manifest.values + site_subcommands).flatten.uniq
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/core/gem_glob_loader.rb b/lib/chef/knife/core/gem_glob_loader.rb
new file mode 100644
index 0000000..6802be2
--- /dev/null
+++ b/lib/chef/knife/core/gem_glob_loader.rb
@@ -0,0 +1,138 @@
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/version"
+require "chef/util/path_helper"
+class Chef
+  class Knife
+    class SubcommandLoader
+      class GemGlobLoader < Chef::Knife::SubcommandLoader
+        MATCHES_CHEF_GEM = %r{/chef-[\d]+\.[\d]+\.[\d]+}.freeze
+        MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}(-\w+)?(-\w+)?/}.freeze
+
+        def subcommand_files
+          @subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq
+        end
+
+        # Returns a Hash of paths to knife commands built-in to chef, or installed via gem.
+        # If rubygems is not installed, falls back to globbing the knife directory.
+        # The Hash is of the form {"relative/path" => "/absolute/path"}
+        #--
+        # Note: the "right" way to load the plugins is to require the relative path, i.e.,
+        #   require 'chef/knife/command'
+        # but we're getting frustrated by bugs at every turn, and it's slow besides. So
+        # subcommand loader has been modified to load the plugins by using Kernel.load
+        # with the absolute path.
+        def gem_and_builtin_subcommands
+          require "rubygems"
+          find_subcommands_via_rubygems
+        rescue LoadError
+          find_subcommands_via_dirglob
+        end
+
+        def find_subcommands_via_dirglob
+          # The "require paths" of the core knife subcommands bundled with chef
+          files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path("../../../knife", __FILE__)), "*.rb")]
+          subcommand_files = {}
+          files.each do |knife_file|
+            rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/, 1]
+            subcommand_files[rel_path] = knife_file
+          end
+          subcommand_files
+        end
+
+        def find_subcommands_via_rubygems
+          files = find_files_latest_gems "chef/knife/*.rb"
+          subcommand_files = {}
+          files.each do |file|
+            rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1]
+
+            # When not installed as a gem (ChefDK/appbundler in particular), AND
+            # a different version of Chef is installed via gems, `files` will
+            # include some files from the 'other' Chef install. If this contains
+            # a knife command that doesn't exist in this version of Chef, we will
+            # get a LoadError later when we try to require it.
+            next if from_different_chef_version?(file)
+
+            subcommand_files[rel_path] = file
+          end
+
+          subcommand_files.merge(find_subcommands_via_dirglob)
+        end
+
+        private
+
+        def find_files_latest_gems(glob, check_load_path = true)
+          files = []
+
+          if check_load_path
+            files = $LOAD_PATH.map { |load_path|
+              Dir["#{File.expand_path glob, Chef::Util::PathHelper.escape_glob(load_path)}#{Gem.suffix_pattern}"]
+            }.flatten.select { |file| File.file? file.untaint }
+          end
+
+          gem_files = latest_gem_specs.map do |spec|
+            # Gem::Specification#matches_for_glob wasn't added until RubyGems 1.8
+            if spec.respond_to? :matches_for_glob
+              spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
+            else
+              check_spec_for_glob(spec, glob)
+            end
+          end.flatten
+
+          files.concat gem_files
+          files.uniq! if check_load_path
+
+          return files
+        end
+
+        def latest_gem_specs
+          @latest_gem_specs ||= if Gem::Specification.respond_to? :latest_specs
+                                  Gem::Specification.latest_specs(true) # find prerelease gems
+                                else
+                                  Gem.source_index.latest_specs(true)
+                                end
+        end
+
+        def check_spec_for_glob(spec, glob)
+          dirs = if spec.require_paths.size > 1 then
+                   "{#{spec.require_paths.join(',')}}"
+                 else
+                   spec.require_paths.first
+                 end
+
+          glob = File.join(Chef::Util::PathHelper.escape_glob(spec.full_gem_path, dirs), glob)
+
+          Dir[glob].map { |f| f.untaint }
+        end
+
+        def from_different_chef_version?(path)
+          matches_any_chef_gem?(path) && !matches_this_chef_gem?(path)
+        end
+
+        def matches_any_chef_gem?(path)
+          path =~ MATCHES_CHEF_GEM
+        end
+
+        def matches_this_chef_gem?(path)
+          path =~ MATCHES_THIS_CHEF_GEM
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/core/generic_presenter.rb b/lib/chef/knife/core/generic_presenter.rb
index f3ea0f0..bbe0249 100644
--- a/lib/chef/knife/core/generic_presenter.rb
+++ b/lib/chef/knife/core/generic_presenter.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife/core/text_formatter'
+require "chef/knife/core/text_formatter"
 
 class Chef
   class Knife
@@ -32,7 +32,7 @@ class Chef
             option :attribute,
               :short => "-a ATTR1 [-a ATTR2]",
               :long => "--attribute ATTR1 [--attribute ATTR2] ",
-              :proc => lambda {|val| @attrs_to_show << val},
+              :proc => lambda { |val| @attrs_to_show << val },
               :description => "Show one or more attributes"
           end
         end
@@ -80,10 +80,10 @@ class Chef
           when :json
             Chef::JSONCompat.to_json_pretty(data)
           when :yaml
-            require 'yaml'
+            require "yaml"
             YAML::dump(data)
           when :pp
-            require 'stringio'
+            require "stringio"
             # If you were looking for some attribute and there is only one match
             # just dump the attribute value
             if config[:attribute] and data.length == 1
@@ -133,7 +133,7 @@ class Chef
         end
 
         def format_list_for_display(list)
-          config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b }
+          config[:with_uri] ? list : list.keys.sort { |a, b| a <=> b }
         end
 
         def format_for_display(data)
@@ -142,7 +142,7 @@ class Chef
           elsif config[:id_only]
             name_or_id_for(data)
           elsif config[:environment] && data.respond_to?(:chef_environment)
-            {"chef_environment" => data.chef_environment}
+            { "chef_environment" => data.chef_environment }
           else
             data
           end
@@ -150,19 +150,19 @@ class Chef
 
         def format_data_subset_for_display(data)
           subset = if config[:attribute]
-            result = {}
-            Array(config[:attribute]).each do |nested_value_spec|
-              nested_value = extract_nested_value(data, nested_value_spec)
-              result[nested_value_spec] = nested_value
-            end
-            result
-          elsif config[:run_list]
-            run_list = data.run_list.run_list
-            { "run_list" => run_list }
-          else
-            raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set"
-          end
-          {name_or_id_for(data) => subset }
+                     result = {}
+                     Array(config[:attribute]).each do |nested_value_spec|
+                       nested_value = extract_nested_value(data, nested_value_spec)
+                       result[nested_value_spec] = nested_value
+                     end
+                     result
+                   elsif config[:run_list]
+                     run_list = data.run_list.run_list
+                     { "run_list" => run_list }
+                   else
+                     raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set"
+                   end
+          { name_or_id_for(data) => subset }
         end
 
         def name_or_id_for(data)
@@ -173,24 +173,23 @@ class Chef
           config[:attribute] || config[:run_list]
         end
 
-
         def extract_nested_value(data, nested_value_spec)
           nested_value_spec.split(".").each do |attr|
             if data.nil?
               nil # don't get no method error on nil
-            # Must check :[] before attr because spec can include
-            #   `keys` - want the key named `keys`, not a list of
-            #   available keys.
-            elsif data.respond_to?(:[])
+              # Must check :[] before attr because spec can include
+              #   `keys` - want the key named `keys`, not a list of
+              #   available keys.
+            elsif data.respond_to?(:[]) && data.has_key?(attr)
               data = data[attr]
             elsif data.respond_to?(attr.to_sym)
               data = data.send(attr.to_sym)
             else
               data = begin
-                data.send(attr.to_sym)
-              rescue NoMethodError
-                nil
-              end
+                       data.send(attr.to_sym)
+                     rescue NoMethodError
+                       nil
+                     end
             end
           end
           ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
@@ -200,17 +199,17 @@ class Chef
           if config[:with_uri]
             item.inject({}) do |collected, (cookbook, versions)|
               collected[cookbook] = Hash.new
-              versions['versions'].each do |ver|
-                collected[cookbook][ver['version']] = ver['url']
+              versions["versions"].each do |ver|
+                collected[cookbook][ver["version"]] = ver["url"]
               end
               collected
             end
           else
             versions_by_cookbook = item.inject({}) do |collected, ( cookbook, versions )|
-              collected[cookbook] = versions["versions"].map {|v| v['version']}
+              collected[cookbook] = versions["versions"].map { |v| v["version"] }
               collected
             end
-            key_length = versions_by_cookbook.empty? ? 0 : versions_by_cookbook.keys.map {|name| name.size }.max + 2
+            key_length = versions_by_cookbook.empty? ? 0 : versions_by_cookbook.keys.map { |name| name.size }.max + 2
             versions_by_cookbook.sort.map do |cookbook, versions|
               "#{cookbook.ljust(key_length)} #{versions.join('  ')}"
             end
diff --git a/lib/chef/knife/core/hashed_command_loader.rb b/lib/chef/knife/core/hashed_command_loader.rb
new file mode 100644
index 0000000..7b6c1c4
--- /dev/null
+++ b/lib/chef/knife/core/hashed_command_loader.rb
@@ -0,0 +1,80 @@
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/version"
+class Chef
+  class Knife
+    class SubcommandLoader
+      #
+      # Load a subcommand from a pre-computed path
+      # for the given command.
+      #
+      class HashedCommandLoader < Chef::Knife::SubcommandLoader
+        KEY = "_autogenerated_command_paths"
+
+        attr_accessor :manifest
+        def initialize(chef_config_dir, plugin_manifest)
+          super(chef_config_dir)
+          @manifest = plugin_manifest
+        end
+
+        def guess_category(args)
+          category_words = positional_arguments(args)
+          category_words.map! { |w| w.split("-") }.flatten!
+          find_longest_key(manifest[KEY]["plugins_by_category"], category_words, " ")
+        end
+
+        def list_commands(pref_category = nil)
+          if pref_category || manifest[KEY]["plugins_by_category"].key?(pref_category)
+            { pref_category => manifest[KEY]["plugins_by_category"][pref_category] }
+          else
+            manifest[KEY]["plugins_by_category"]
+          end
+        end
+
+        def subcommand_files
+          manifest[KEY]["plugins_paths"].values.flatten
+        end
+
+        def load_command(args)
+          paths = manifest[KEY]["plugins_paths"][subcommand_for_args(args)]
+          if paths.nil? || paths.empty? || (! paths.is_a? Array)
+            false
+          else
+            paths.each do |sc|
+              if File.exists?(sc)
+                Kernel.load sc
+              else
+                Chef::Log.error "The file #{sc} is missing for subcommand '#{subcommand_for_args(args)}'. Please rehash to update the subcommands cache."
+                return false
+              end
+            end
+            true
+          end
+        end
+
+        def subcommand_for_args(args)
+          if manifest[KEY]["plugins_paths"].key?(args)
+            args
+          else
+            find_longest_key(manifest[KEY]["plugins_paths"], args, "_")
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/core/node_editor.rb b/lib/chef/knife/core/node_editor.rb
index fe14e18..9b5f0a4 100644
--- a/lib/chef/knife/core/node_editor.rb
+++ b/lib/chef/knife/core/node_editor.rb
@@ -1,6 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Jordan Running (<jr at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,83 +17,103 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
-require 'chef/node'
-require 'tempfile'
+require "chef/json_compat"
+require "chef/node"
 
 class Chef
   class Knife
     class NodeEditor
+      attr_reader :node, :ui, :config
+      private :node, :ui, :config
 
-      attr_reader :node
-      attr_reader :ui
-      attr_reader :config
-
+      # @param node [Chef::Node]
+      # @param ui [Chef::Knife::UI]
+      # @param config [Hash]
       def initialize(node, ui, config)
         @node, @ui, @config = node, ui, config
       end
 
+      # Opens the node data (as JSON) in the user's editor and returns a new
+      # {Chef::Node} reflecting the user's changes.
+      #
+      # @return [Chef::Node]
       def edit_node
         abort "You specified the --disable_editing option, nothing to edit" if config[:disable_editing]
         assert_editor_set!
 
-        updated_node_data = @ui.edit_data(view)
+        updated_node_data = ui.edit_data(view)
         apply_updates(updated_node_data)
         @updated_node
       end
 
+      # Returns an array of the names of properties that have been changed or
+      # +false+ if none were changed.
+      #
+      # @return [Array<String>] if any properties have been changed.
+      # @return [false] if no properties have been changed.
       def updated?
+        return false if @updated_node.nil?
+
         pristine_copy = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(node))
         updated_copy  = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@updated_node))
-        unless pristine_copy == updated_copy
-          updated_properties = %w{name normal chef_environment run_list default override automatic}.reject do |key|
-             pristine_copy[key] == updated_copy[key]
-          end
+
+        updated_properties = %w{
+          name
+          chef_environment
+          automatic
+          default
+          normal
+          override
+          policy_name
+          policy_group
+          run_list
+        }.reject do |key|
+          pristine_copy[key] == updated_copy[key]
         end
-        ( pristine_copy != updated_copy ) && updated_properties
-      end
 
-      private
+        updated_properties.any? && updated_properties
+      end
 
+      # @api private
       def view
-        result = {}
-        result["name"] = node.name
-        result["chef_environment"] = node.chef_environment
-        result["normal"] = node.normal_attrs
-        result["run_list"] = node.run_list
+        result = {
+          "name" => node.name,
+          "chef_environment" => node.chef_environment,
+          "normal" => node.normal_attrs,
+          "policy_name" => node.policy_name,
+          "policy_group" => node.policy_group,
+          "run_list" => node.run_list,
+        }
 
         if config[:all_attributes]
           result["default"]   = node.default_attrs
           result["override"]  = node.override_attrs
           result["automatic"] = node.automatic_attrs
         end
+
         result
       end
 
+      # @api private
       def apply_updates(updated_data)
         if node.name and node.name != updated_data["name"]
           ui.warn "Changing the name of a node results in a new node being created, #{node.name} will not be modified or removed."
-          confirm = ui.confirm "Proceed with creation of new node"
+          ui.confirm "Proceed with creation of new node"
         end
 
-        @updated_node = Node.new.tap do |n|
-          n.name( updated_data["name"] )
-          n.chef_environment( updated_data["chef_environment"] )
-          n.run_list( updated_data["run_list"])
-          n.normal_attrs = updated_data["normal"]
-
-          if config[:all_attributes]
-            n.default_attrs   = updated_data["default"]
-            n.override_attrs  = updated_data["override"]
-            n.automatic_attrs = updated_data["automatic"]
-          else
-            n.default_attrs   = node.default_attrs
-            n.override_attrs  = node.override_attrs
-            n.automatic_attrs = node.automatic_attrs
-          end
+        data = updated_data.dup
+
+        unless config[:all_attributes]
+          data["automatic"] = node.automatic_attrs
+          data["default"] = node.default_attrs
+          data["override"] = node.override_attrs
         end
+
+        @updated_node = Node.from_hash(data)
       end
 
+      private
+
       def abort(message)
         ui.error(message)
         exit 1
diff --git a/lib/chef/knife/core/node_presenter.rb b/lib/chef/knife/core/node_presenter.rb
index d1aab59..cdb664e 100644
--- a/lib/chef/knife/core/node_presenter.rb
+++ b/lib/chef/knife/core/node_presenter.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife/core/text_formatter'
-require 'chef/knife/core/generic_presenter'
+require "chef/knife/core/text_formatter"
+require "chef/knife/core/generic_presenter"
 
 class Chef
   class Knife
@@ -32,18 +32,18 @@ class Chef
         def self.included(includer)
           includer.class_eval do
             option :medium_output,
-              :short   => '-m',
-              :long    => '--medium',
+              :short   => "-m",
+              :long    => "--medium",
               :boolean => true,
               :default => false,
-              :description => 'Include normal attributes in the output'
+              :description => "Include normal attributes in the output"
 
             option :long_output,
-              :short   => '-l',
-              :long    => '--long',
+              :short   => "-l",
+              :long    => "--long",
               :boolean => true,
               :default => false,
-              :description => 'Include all attributes in the output'
+              :description => "Include all attributes in the output"
           end
         end
       end
@@ -67,7 +67,12 @@ class Chef
             result = {}
 
             result["name"] = node.name
-            result["chef_environment"] = node.chef_environment
+            if node.policy_name.nil? && node.policy_group.nil?
+              result["chef_environment"] = node.chef_environment
+            else
+              result["policy_name"] = node.policy_name
+              result["policy_group"] = node.policy_group
+            end
             result["run_list"] = node.run_list
             result["normal"] = node.normal_attrs
 
@@ -93,25 +98,43 @@ class Chef
             # special case ec2 with their split horizon whatsis.
             ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
 
-            summarized=<<-SUMMARY
+            summarized = <<-SUMMARY
 #{ui.color('Node Name:', :bold)}   #{ui.color(node.name, :bold)}
+SUMMARY
+            show_policy = !(node.policy_name.nil? && node.policy_group.nil?)
+            if show_policy
+              summarized << <<-POLICY
+#{key('Policy Name:')}  #{node.policy_name}
+#{key('Policy Group:')} #{node.policy_group}
+POLICY
+            else
+              summarized << <<-ENV
 #{key('Environment:')} #{node.chef_environment}
+ENV
+            end
+            summarized << <<-SUMMARY
 #{key('FQDN:')}        #{node[:fqdn]}
 #{key('IP:')}          #{ip}
 #{key('Run List:')}    #{node.run_list}
+SUMMARY
+            unless show_policy
+              summarized << <<-ROLES
 #{key('Roles:')}       #{Array(node[:roles]).join(', ')}
+ROLES
+            end
+            summarized << <<-SUMMARY
 #{key('Recipes:')}     #{Array(node[:recipes]).join(', ')}
 #{key('Platform:')}    #{node[:platform]} #{node[:platform_version]}
-#{key('Tags:')}        #{Array(node[:tags]).join(', ')}
+#{key('Tags:')}        #{node.tags.join(', ')}
 SUMMARY
             if config[:medium_output] || config[:long_output]
-              summarized +=<<-MORE
+              summarized += <<-MORE
 #{key('Attributes:')}
 #{text_format(node.normal_attrs)}
 MORE
             end
             if config[:long_output]
-              summarized +=<<-MOST
+              summarized += <<-MOST
 #{key('Default Attributes:')}
 #{text_format(node.default_attrs)}
 #{key('Override Attributes:')}
@@ -134,4 +157,3 @@ MOST
     end
   end
 end
-
diff --git a/lib/chef/knife/core/object_loader.rb b/lib/chef/knife/core/object_loader.rb
index 698b09a..0449693 100644
--- a/lib/chef/knife/core/object_loader.rb
+++ b/lib/chef/knife/core/object_loader.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,9 @@
 # limitations under the License.
 #
 
-require 'ffi_yajl'
-require 'chef/util/path_helper'
+require "ffi_yajl"
+require "chef/util/path_helper"
+require "chef/data_bag_item"
 
 class Chef
   class Knife
@@ -70,14 +71,14 @@ class Chef
         #
         # @api public
         def find_all_objects(path)
-          path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), '*')
-          path << '.{json,rb}'
+          path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), "*")
+          path << ".{json,rb}"
           objects = Dir.glob(path)
           objects.map { |o| File.basename(o) }
         end
 
         def find_all_object_dirs(path)
-          path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), '*')
+          path = File.join(Chef::Util::PathHelper.escape_glob(File.expand_path(path)), "*")
           objects = Dir.glob(path)
           objects.delete_if { |o| !File.directory?(o) }
           objects.map { |o| File.basename(o) }
@@ -92,7 +93,7 @@ class Chef
             if @klass == Chef::DataBagItem
               r
             else
-              @klass.json_create(r)
+              @klass.from_hash(r)
             end
           when /\.rb$/
             r = klass.new
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb
index 9cf839d..68c1acf 100644
--- a/lib/chef/knife/core/status_presenter.rb
+++ b/lib/chef/knife/core/status_presenter.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Nicolas DUPEUX (<nicolas.dupeux at arkea.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife/core/text_formatter'
-require 'chef/knife/core/generic_presenter'
+require "chef/knife/core/text_formatter"
+require "chef/knife/core/generic_presenter"
 
 class Chef
   class Knife
@@ -32,18 +32,18 @@ class Chef
         def self.included(includer)
           includer.class_eval do
             option :medium_output,
-              :short   => '-m',
-              :long    => '--medium',
+              :short   => "-m",
+              :long    => "--medium",
               :boolean => true,
               :default => false,
-              :description => 'Include normal attributes in the output'
+              :description => "Include normal attributes in the output"
 
             option :long_output,
-              :short   => '-l',
-              :long    => '--long',
+              :short   => "-l",
+              :long    => "--long",
               :boolean => true,
               :default => false,
-              :description => 'Include all attributes in the output'
+              :description => "Include all attributes in the output"
           end
         end
       end
@@ -93,15 +93,15 @@ class Chef
         # the volume of output is adjusted accordingly. Uses colors if enabled
         # in the ui object.
         def summarize(list)
-          summarized=''
+          summarized = ""
           list.each do |data|
             node = data
             # special case ec2 with their split horizon whatsis.
             ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress]
             fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
-            name = node['name'] || node.name
+            name = node["name"] || node.name
 
-            hours, minutes, _ = time_difference_in_hms(node["ohai_time"])
+            hours, minutes, = time_difference_in_hms(node["ohai_time"])
             hours_text   = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
             minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
             run_list = "#{node['run_list']}" if config[:run_list]
@@ -117,20 +117,20 @@ class Chef
             end
 
             line_parts = Array.new
-            line_parts << @ui.color(text, color) + ' ago' << name
+            line_parts << @ui.color(text, color) + " ago" << name
             line_parts << fqdn if fqdn
             line_parts << ip if ip
             line_parts << run_list if run_list
 
-            if node['platform']
-              platform = node['platform']
-              if node['platform_version']
+            if node["platform"]
+              platform = node["platform"]
+              if node["platform_version"]
                 platform << " #{node['platform_version']}"
               end
               line_parts << platform
             end
 
-            summarized=summarized + line_parts.join(', ') + ".\n"
+            summarized = summarized + line_parts.join(", ") + ".\n"
           end
           summarized
         end
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index 1f59515..95ab219 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -1,6 +1,6 @@
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2011 Opscode, Inc.
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,207 +16,191 @@
 # limitations under the License.
 #
 
-require 'chef/version'
-require 'chef/util/path_helper'
+require "chef/version"
+require "chef/util/path_helper"
+require "chef/knife/core/gem_glob_loader"
+require "chef/knife/core/hashed_command_loader"
+require "chef/knife/core/custom_manifest_loader"
+
 class Chef
   class Knife
+    #
+    # Public Methods of a Subcommand Loader
+    #
+    # load_commands            - loads all available subcommands
+    # load_command(args)       - loads subcommands for the given args
+    # list_commands(args)      - lists all available subcommands,
+    #                            optionally filtering by category
+    # subcommand_files         - returns an array of all subcommand files
+    #                            that could be loaded
+    # commnad_class_from(args) - returns the subcommand class for the
+    #                            user-requested command
+    #
     class SubcommandLoader
-
-      MATCHES_CHEF_GEM = %r{/chef-[\d]+\.[\d]+\.[\d]+}.freeze
-      MATCHES_THIS_CHEF_GEM = %r{/chef-#{Chef::VERSION}/}.freeze
-
       attr_reader :chef_config_dir
       attr_reader :env
 
-      def initialize(chef_config_dir, env=nil)
+      # A small factory method.  Eventually, this is the only place
+      # where SubcommandLoader should know about its subclasses, but
+      # to maintain backwards compatibility many of the instance
+      # methods in this base class contain default implementations
+      # of the functions sub classes should otherwise provide
+      # or directly instantiate the appropriate subclass
+      def self.for_config(chef_config_dir)
+        if autogenerated_manifest?
+          Chef::Log.debug("Using autogenerated hashed command manifest #{plugin_manifest_path}")
+          Knife::SubcommandLoader::HashedCommandLoader.new(chef_config_dir, plugin_manifest)
+        elsif custom_manifest?
+          Chef.log_deprecation("Using custom manifest #{plugin_manifest_path} is deprecated.  Please use a `knife rehash` autogenerated manifest instead.")
+          Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, plugin_manifest)
+        else
+          Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir)
+        end
+      end
+
+      def self.plugin_manifest?
+        plugin_manifest_path && File.exist?(plugin_manifest_path)
+      end
+
+      def self.autogenerated_manifest?
+        plugin_manifest? && plugin_manifest.key?(HashedCommandLoader::KEY)
+      end
+
+      def self.custom_manifest?
+        plugin_manifest? && plugin_manifest.key?("plugins")
+      end
+
+      def self.plugin_manifest
+        Chef::JSONCompat.from_json(File.read(plugin_manifest_path))
+      end
+
+      def self.plugin_manifest_path
+        Chef::Util::PathHelper.home(".chef", "plugin_manifest.json")
+      end
+
+      def initialize(chef_config_dir, env = nil)
         @chef_config_dir = chef_config_dir
-        @forced_activate = {}
 
         # Deprecated and un-used instance variable.
         @env = env
         unless env.nil?
-          Chef::Log.deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
+          Chef.log_deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
         end
       end
 
       # Load all the sub-commands
       def load_commands
+        return true if @loaded
         subcommand_files.each { |subcommand| Kernel.load subcommand }
-        true
+        @loaded = true
       end
 
-      # Returns an Array of paths to knife commands located in chef_config_dir/plugins/knife/
-      # and ~/.chef/plugins/knife/
-      def site_subcommands
-        user_specific_files = []
-
-        if chef_config_dir
-          user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", Chef::Util::PathHelper.escape_glob(chef_config_dir)))
-        end
-
-        # finally search ~/.chef/plugins/knife/*.rb
-        Chef::Util::PathHelper.home('.chef', 'plugins', 'knife') do |p|
-          user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(p), '*.rb'))
-        end
+      def force_load
+        @loaded = false
+        load_commands
+      end
 
-        user_specific_files
+      def load_command(_command_args)
+        load_commands
       end
 
-      # Returns a Hash of paths to knife commands built-in to chef, or installed via gem.
-      # If rubygems is not installed, falls back to globbing the knife directory.
-      # The Hash is of the form {"relative/path" => "/absolute/path"}
-      #--
-      # Note: the "right" way to load the plugins is to require the relative path, i.e.,
-      #   require 'chef/knife/command'
-      # but we're getting frustrated by bugs at every turn, and it's slow besides. So
-      # subcommand loader has been modified to load the plugins by using Kernel.load
-      # with the absolute path.
-      def gem_and_builtin_subcommands
-        if have_plugin_manifest?
-          find_subcommands_via_manifest
+      def list_commands(pref_cat = nil)
+        load_commands
+        if pref_cat && Chef::Knife.subcommands_by_category.key?(pref_cat)
+          { pref_cat => Chef::Knife.subcommands_by_category[pref_cat] }
         else
-          # search all gems for chef/knife/*.rb
-          require 'rubygems'
-          find_subcommands_via_rubygems
+          Chef::Knife.subcommands_by_category
         end
-      rescue LoadError
-        find_subcommands_via_dirglob
       end
 
-      def subcommand_files
-        @subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq
+      def command_class_from(args)
+        cmd_words = positional_arguments(args)
+        load_command(cmd_words)
+        result = Chef::Knife.subcommands[find_longest_key(Chef::Knife.subcommands,
+                                                          cmd_words, "_")]
+        result || Chef::Knife.subcommands[args.first.gsub("-", "_")]
       end
 
-      # If the user has created a ~/.chef/plugin_manifest.json file, we'll use
-      # that instead of inspecting the on-system gems to find the plugins. The
-      # file format is expected to look like:
-      #
-      #   { "plugins": {
-      #       "knife-ec2": {
-      #         "paths": [
-      #           "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_create.rb",
-      #           "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_delete.rb"
-      #         ]
-      #       }
-      #     }
-      #   }
-      #
-      # Extraneous content in this file is ignored. This intentional so that we
-      # can adapt the file format for potential behavior changes to knife in
-      # the future.
-      def find_subcommands_via_manifest
-        # Format of subcommand_files is "relative_path" (something you can
-        # Kernel.require()) => full_path. The relative path isn't used
-        # currently, so we just map full_path => full_path.
-        subcommand_files = {}
-        plugin_manifest["plugins"].each do |plugin_name, plugin_manifest|
-          plugin_manifest["paths"].each do |cmd_path|
-            subcommand_files[cmd_path] = cmd_path
-          end
-        end
-        subcommand_files.merge(find_subcommands_via_dirglob)
+      def guess_category(args)
+        category_words = positional_arguments(args)
+        category_words.map! { |w| w.split("-") }.flatten!
+        find_longest_key(Chef::Knife.subcommands_by_category,
+                         category_words, " ")
       end
 
+      #
+      # This is shared between the custom_manifest_loader and the gem_glob_loader
+      #
       def find_subcommands_via_dirglob
         # The "require paths" of the core knife subcommands bundled with chef
-        files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path('../../../knife', __FILE__)), '*.rb')]
+        files = Dir[File.join(Chef::Util::PathHelper.escape_glob(File.expand_path("../../../knife", __FILE__)), "*.rb")]
         subcommand_files = {}
         files.each do |knife_file|
-          rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1]
+          rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/, 1]
           subcommand_files[rel_path] = knife_file
         end
         subcommand_files
       end
 
-      def find_subcommands_via_rubygems
-        files = find_files_latest_gems 'chef/knife/*.rb'
-        subcommand_files = {}
-        files.each do |file|
-          rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1]
-
-          # When not installed as a gem (ChefDK/appbundler in particular), AND
-          # a different version of Chef is installed via gems, `files` will
-          # include some files from the 'other' Chef install. If this contains
-          # a knife command that doesn't exist in this version of Chef, we will
-          # get a LoadError later when we try to require it.
-          next if from_different_chef_version?(file)
-
-          subcommand_files[rel_path] = file
-        end
-
-        subcommand_files.merge(find_subcommands_via_dirglob)
-      end
-
-      def have_plugin_manifest?
-        plugin_manifest_path && File.exist?(plugin_manifest_path)
-      end
-
-      def plugin_manifest
-        Chef::JSONCompat.from_json(File.read(plugin_manifest_path))
-      end
-
-      def plugin_manifest_path
-        Chef::Util::PathHelper.home('.chef', 'plugin_manifest.json')
+      #
+      # Subclassses should define this themselves.  Eventually, this will raise a
+      # NotImplemented error, but for now, we mimic the behavior the user was likely
+      # to get in the past.
+      #
+      def subcommand_files
+        Chef.log_deprecation "Using Chef::Knife::SubcommandLoader directly is deprecated.
+Please use Chef::Knife::SubcommandLoader.for_config(chef_config_dir, env)"
+        @subcommand_files ||= if Chef::Knife::SubcommandLoader.plugin_manifest?
+                                Chef::Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, env).subcommand_files
+                              else
+                                Chef::Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir, env).subcommand_files
+                              end
       end
 
-      private
-
-      def find_files_latest_gems(glob, check_load_path=true)
-        files = []
-
-        if check_load_path
-          files = $LOAD_PATH.map { |load_path|
-            Dir["#{File.expand_path glob, Chef::Util::PathHelper.escape_glob(load_path)}#{Gem.suffix_pattern}"]
-          }.flatten.select { |file| File.file? file.untaint }
-        end
-
-        gem_files = latest_gem_specs.map do |spec|
-          # Gem::Specification#matches_for_glob wasn't added until RubyGems 1.8
-          if spec.respond_to? :matches_for_glob
-            spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}")
+      #
+      # Utility function for finding an element in a hash given an array
+      # of words and a separator.  We find the the longest key in the
+      # hash composed of the given words joined by the separator.
+      #
+      def find_longest_key(hash, words, sep = "_")
+        match = nil
+        until match || words.empty?
+          candidate = words.join(sep)
+          if hash.key?(candidate)
+            match = candidate
           else
-            check_spec_for_glob(spec, glob)
+            words.pop
           end
-        end.flatten
-
-        files.concat gem_files
-        files.uniq! if check_load_path
-
-        return files
-      end
-
-      def latest_gem_specs
-        @latest_gem_specs ||= if Gem::Specification.respond_to? :latest_specs
-          Gem::Specification.latest_specs(true)  # find prerelease gems
-        else
-          Gem.source_index.latest_specs(true)
         end
+        match
       end
 
-      def check_spec_for_glob(spec, glob)
-        dirs = if spec.require_paths.size > 1 then
-          "{#{spec.require_paths.join(',')}}"
-        else
-          spec.require_paths.first
-        end
-
-        glob = File.join(Chef::Util::PathHelper.escape_glob(spec.full_gem_path, dirs), glob)
-
-        Dir[glob].map { |f| f.untaint }
+      #
+      # The positional arguments from the argument list provided by the
+      # users. Used to search for subcommands and categories.
+      #
+      # @return [Array<String>]
+      #
+      def positional_arguments(args)
+        args.select { |arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ }
       end
 
-      def from_different_chef_version?(path)
-        matches_any_chef_gem?(path) && !matches_this_chef_gem?(path)
-      end
+      # Returns an Array of paths to knife commands located in
+      # chef_config_dir/plugins/knife/ and ~/.chef/plugins/knife/
+      def site_subcommands
+        user_specific_files = []
 
-      def matches_any_chef_gem?(path)
-        path =~ MATCHES_CHEF_GEM
-      end
+        if chef_config_dir
+          user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", Chef::Util::PathHelper.escape_glob(chef_config_dir)))
+        end
 
-      def matches_this_chef_gem?(path)
-        path =~ MATCHES_THIS_CHEF_GEM
-      end
+        # finally search ~/.chef/plugins/knife/*.rb
+        Chef::Util::PathHelper.home(".chef", "plugins", "knife") do |p|
+          user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(p), "*.rb"))
+        end
 
+        user_specific_files
+      end
     end
   end
 end
diff --git a/lib/chef/knife/core/text_formatter.rb b/lib/chef/knife/core/text_formatter.rb
index 6032848..8775e2e 100644
--- a/lib/chef/knife/core/text_formatter.rb
+++ b/lib/chef/knife/core/text_formatter.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,14 +27,14 @@ class Chef
         def initialize(data, ui)
           @ui = ui
           @data = if data.respond_to?(:display_hash)
-            data.display_hash
-          elsif data.kind_of?(Array)
-            data
-          elsif data.respond_to?(:to_hash)
-            data.to_hash
-          else
-            data
-          end
+                    data.display_hash
+                  elsif data.kind_of?(Array)
+                    data
+                  elsif data.respond_to?(:to_hash)
+                    data.to_hash
+                  else
+                    data
+                  end
         end
 
         def formatted_data
@@ -42,10 +42,10 @@ class Chef
         end
 
         def text_format(data)
-          buffer = ''
+          buffer = ""
 
           if data.respond_to?(:keys)
-            justify_width = data.keys.map {|k| k.to_s.size }.max.to_i + 1
+            justify_width = data.keys.map { |k| k.to_s.size }.max.to_i + 1
             data.sort.each do |key, value|
               # key: ['value'] should be printed as key: value
               if value.kind_of?(Array) && value.size == 1 && is_singleton(value[0])
@@ -68,7 +68,7 @@ class Chef
               buffer << text_format(data[index])
               # Separate items with newlines if it's an array of hashes or an
               # array of arrays
-              buffer << "\n" if !is_singleton(data[index]) && index != data.size-1
+              buffer << "\n" if !is_singleton(data[index]) && index != data.size - 1
             end
           else
             buffer << "#{data}\n"
@@ -83,4 +83,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index a54f14a..ee92127 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
 # limitations under the License.
 #
 
-require 'forwardable'
-require 'chef/platform/query_helpers'
-require 'chef/knife/core/generic_presenter'
-require 'tempfile'
+require "forwardable"
+require "chef/platform/query_helpers"
+require "chef/knife/core/generic_presenter"
+require "tempfile"
 
 class Chef
   class Knife
@@ -57,7 +57,7 @@ class Chef
 
       def highline
         @highline ||= begin
-          require 'highline'
+          require "highline"
           HighLine.new
         end
       end
@@ -137,7 +137,7 @@ class Chef
         @presenter.interchange?
       end
 
-      def ask_question(question, opts={})
+      def ask_question(question, opts = {})
         question = question + "[#{opts[:default]}] " if opts[:default]
 
         if opts[:default] and config[:defaults]
@@ -163,7 +163,6 @@ class Chef
         end
       end
 
-
       # Hash -> Hash
       # Works the same as edit_data but
       # returns a hash rather than a JSON string/Fully infated object
@@ -172,10 +171,10 @@ class Chef
         Chef::JSONCompat.parse(raw)
       end
 
-      def edit_data(data, parse_output=true)
+      def edit_data(data, parse_output = true)
         output = Chef::JSONCompat.to_json_pretty(data)
         if (!config[:disable_editing])
-          Tempfile.open([ 'knife-edit-', '.json' ]) do |tf|
+          Tempfile.open([ "knife-edit-", ".json" ]) do |tf|
             tf.sync = true
             tf.puts output
             tf.close
@@ -217,16 +216,16 @@ class Chef
       def confirmation_instructions(default_choice)
         case default_choice
         when true
-          '? (Y/n) '
+          "? (Y/n) "
         when false
-          '? (y/N) '
+          "? (y/N) "
         else
-          '? (Y/N) '
+          "? (Y/N) "
         end
       end
 
       # See confirm method for argument information
-      def confirm_without_exit(question, append_instructions=true, default_choice=nil)
+      def confirm_without_exit(question, append_instructions = true, default_choice = nil)
         return true if config[:yes]
 
         stdout.print question
@@ -264,7 +263,7 @@ class Chef
       # append_instructions => Should print '? (Y/N)' as instructions
       # default_choice => Set to true for 'Y', and false for 'N' as default answer
       #
-      def confirm(question, append_instructions=true, default_choice=nil)
+      def confirm(question, append_instructions = true, default_choice = nil)
         unless confirm_without_exit(question, append_instructions, default_choice)
           exit 3
         end
diff --git a/lib/chef/knife/data_bag_create.rb b/lib/chef/knife/data_bag_create.rb
index f8a7619..196278b 100644
--- a/lib/chef/knife/data_bag_create.rb
+++ b/lib/chef/knife/data_bag_create.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
 
 class Chef
   class Knife
@@ -26,8 +26,8 @@ class Chef
       include DataBagSecretOptions
 
       deps do
-        require 'chef/data_bag'
-        require 'chef/encrypted_data_bag_item'
+        require "chef/data_bag"
+        require "chef/encrypted_data_bag_item"
       end
 
       banner "knife data bag create BAG [ITEM] (options)"
@@ -51,7 +51,7 @@ class Chef
 
         # create the data bag
         begin
-          rest.post_rest("data", { "name" => @data_bag_name })
+          rest.post("data", { "name" => @data_bag_name })
           ui.info("Created data_bag[#{@data_bag_name}]")
         rescue Net::HTTPServerException => e
           raise unless e.to_s =~ /^409/
@@ -66,9 +66,10 @@ class Chef
                 Chef::EncryptedDataBagItem.encrypt_data_bag_item(output, read_secret)
               else
                 output
-            end)
+              end
+            )
             item.data_bag(@data_bag_name)
-            rest.post_rest("data/#{@data_bag_name}", item)
+            rest.post("data/#{@data_bag_name}", item)
           end
         end
       end
diff --git a/lib/chef/knife/data_bag_delete.rb b/lib/chef/knife/data_bag_delete.rb
index 575e9d6..c1ea201 100644
--- a/lib/chef/knife/data_bag_delete.rb
+++ b/lib/chef/knife/data_bag_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class DataBagDelete < Knife
 
       deps do
-        require 'chef/data_bag'
+        require "chef/data_bag"
       end
 
       banner "knife data bag delete BAG [ITEM] (options)"
@@ -32,11 +32,11 @@ class Chef
       def run
         if @name_args.length == 2
           delete_object(Chef::DataBagItem, @name_args[1], "data_bag_item") do
-            rest.delete_rest("data/#{@name_args[0]}/#{@name_args[1]}")
+            rest.delete("data/#{@name_args[0]}/#{@name_args[1]}")
           end
         elsif @name_args.length == 1
           delete_object(Chef::DataBag, @name_args[0], "data_bag") do
-            rest.delete_rest("data/#{@name_args[0]}")
+            rest.delete("data/#{@name_args[0]}")
           end
         else
           show_usage
@@ -47,5 +47,3 @@ class Chef
     end
   end
 end
-
-
diff --git a/lib/chef/knife/data_bag_edit.rb b/lib/chef/knife/data_bag_edit.rb
index 6ef4b33..ba39207 100644
--- a/lib/chef/knife/data_bag_edit.rb
+++ b/lib/chef/knife/data_bag_edit.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
 
 class Chef
   class Knife
@@ -26,8 +26,8 @@ class Chef
       include DataBagSecretOptions
 
       deps do
-        require 'chef/data_bag_item'
-        require 'chef/encrypted_data_bag_item'
+        require "chef/data_bag_item"
+        require "chef/encrypted_data_bag_item"
       end
 
       banner "knife data bag edit BAG ITEM (options)"
@@ -65,13 +65,10 @@ class Chef
           item_to_save = edited_item
         end
 
-        rest.put_rest("data/#{@name_args[0]}/#{@name_args[1]}", item_to_save)
+        rest.put("data/#{@name_args[0]}/#{@name_args[1]}", item_to_save)
         stdout.puts("Saved data_bag_item[#{@name_args[1]}]")
         ui.output(edited_item) if config[:print_after]
       end
     end
   end
 end
-
-
-
diff --git a/lib/chef/knife/data_bag_from_file.rb b/lib/chef/knife/data_bag_from_file.rb
index d1b7daa..e029ec4 100644
--- a/lib/chef/knife/data_bag_from_file.rb
+++ b/lib/chef/knife/data_bag_from_file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/util/path_helper'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/util/path_helper"
+require "chef/knife/data_bag_secret_options"
 
 class Chef
   class Knife
@@ -27,11 +27,11 @@ class Chef
       include DataBagSecretOptions
 
       deps do
-        require 'chef/data_bag'
-        require 'chef/data_bag_item'
-        require 'chef/knife/core/object_loader'
-        require 'chef/json_compat'
-        require 'chef/encrypted_data_bag_item'
+        require "chef/data_bag"
+        require "chef/data_bag_item"
+        require "chef/knife/core/object_loader"
+        require "chef/json_compat"
+        require "chef/encrypted_data_bag_item"
       end
 
       banner "knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)"
@@ -60,6 +60,7 @@ class Chef
       end
 
       private
+
       def data_bags_path
         @data_bag_path ||= "data_bags"
       end
diff --git a/lib/chef/knife/data_bag_list.rb b/lib/chef/knife/data_bag_list.rb
index 5e556b6..d507925 100644
--- a/lib/chef/knife/data_bag_list.rb
+++ b/lib/chef/knife/data_bag_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class DataBagList < Knife
 
       deps do
-        require 'chef/data_bag'
+        require "chef/data_bag"
       end
 
       banner "knife data bag list (options)"
@@ -40,7 +40,3 @@ class Chef
     end
   end
 end
-
-
-
-
diff --git a/lib/chef/knife/data_bag_secret_options.rb b/lib/chef/knife/data_bag_secret_options.rb
index 7660060..7e45800 100644
--- a/lib/chef/knife/data_bag_secret_options.rb
+++ b/lib/chef/knife/data_bag_secret_options.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'mixlib/cli'
-require 'chef/config'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "mixlib/cli"
+require "chef/config"
+require "chef/encrypted_data_bag_item/check_encrypted"
 
 class Chef
   class Knife
@@ -65,7 +65,7 @@ class Chef
       def read_secret
         # Moving the non 'compile-time' requires into here to speed up knife command loading
         # IE, if we are not running 'knife data bag *' we don't need to load 'chef/encrypted_data_bag_item'
-        require 'chef/encrypted_data_bag_item'
+        require "chef/encrypted_data_bag_item"
 
         if has_cl_secret?
           config[:secret]
diff --git a/lib/chef/knife/data_bag_show.rb b/lib/chef/knife/data_bag_show.rb
index 3671528..5052355 100644
--- a/lib/chef/knife/data_bag_show.rb
+++ b/lib/chef/knife/data_bag_show.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/data_bag_secret_options'
+require "chef/knife"
+require "chef/knife/data_bag_secret_options"
 
 class Chef
   class Knife
@@ -26,8 +26,8 @@ class Chef
       include DataBagSecretOptions
 
       deps do
-        require 'chef/data_bag'
-        require 'chef/encrypted_data_bag_item'
+        require "chef/data_bag"
+        require "chef/encrypted_data_bag_item"
       end
 
       banner "knife data bag show BAG [ITEM] (options)"
@@ -35,32 +35,32 @@ class Chef
 
       def run
         display = case @name_args.length
-        when 2 # Bag and Item names provided
-          secret = encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil
-          raw_data = Chef::DataBagItem.load(@name_args[0], @name_args[1]).raw_data
-          encrypted = encrypted?(raw_data)
+                  when 2 # Bag and Item names provided
+                    secret = encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil
+                    raw_data = Chef::DataBagItem.load(@name_args[0], @name_args[1]).raw_data
+                    encrypted = encrypted?(raw_data)
 
-          if encrypted && secret
-            # Users do not need to pass --encrypt to read data, we simply try to use the provided secret
-            ui.info("Encrypted data bag detected, decrypting with provided secret.")
-            raw = Chef::EncryptedDataBagItem.load(@name_args[0],
-                                                  @name_args[1],
-                                                  secret)
-            format_for_display(raw.to_hash)
-          elsif encrypted && !secret
-            ui.warn("Encrypted data bag detected, but no secret provided for decoding.  Displaying encrypted data.")
-            format_for_display(raw_data)
-          else
-            ui.info("Unencrypted data bag detected, ignoring any provided secret options.")
-            format_for_display(raw_data)
-          end
+                    if encrypted && secret
+                      # Users do not need to pass --encrypt to read data, we simply try to use the provided secret
+                      ui.info("Encrypted data bag detected, decrypting with provided secret.")
+                      raw = Chef::EncryptedDataBagItem.load(@name_args[0],
+                                                            @name_args[1],
+                                                            secret)
+                      format_for_display(raw.to_hash)
+                    elsif encrypted && !secret
+                      ui.warn("Encrypted data bag detected, but no secret provided for decoding.  Displaying encrypted data.")
+                      format_for_display(raw_data)
+                    else
+                      ui.info("Unencrypted data bag detected, ignoring any provided secret options.")
+                      format_for_display(raw_data)
+                    end
 
-        when 1 # Only Bag name provided
-          format_list_for_display(Chef::DataBag.load(@name_args[0]))
-        else
-          stdout.puts opt_parser
-          exit(1)
-        end
+                  when 1 # Only Bag name provided
+                    format_list_for_display(Chef::DataBag.load(@name_args[0]))
+                  else
+                    stdout.puts opt_parser
+                    exit(1)
+                  end
         output(display)
       end
 
diff --git a/lib/chef/knife/delete.rb b/lib/chef/knife/delete.rb
index 0030c45..d5d4a4c 100644
--- a/lib/chef/knife/delete.rb
+++ b/lib/chef/knife/delete.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,22 +8,22 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
+        require "chef/chef_fs/file_system"
       end
 
       option :recurse,
-        :short => '-r',
-        :long => '--[no-]recurse',
+        :short => "-r",
+        :long => "--[no-]recurse",
         :boolean => true,
         :default => false,
         :description => "Delete directories recursively."
       option :both,
-        :long => '--both',
+        :long => "--both",
         :boolean => true,
         :default => false,
         :description => "Delete both the local and remote copies."
       option :local,
-        :long => '--local',
+        :long => "--local",
         :boolean => true,
         :default => false,
         :description => "Delete the local copy (leave the remote copy)."
@@ -105,4 +105,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/deps.rb b/lib/chef/knife/deps.rb
index 4b23468..99a24e4 100644
--- a/lib/chef/knife/deps.rb
+++ b/lib/chef/knife/deps.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,20 +8,20 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
-        require 'chef/run_list'
+        require "chef/chef_fs/file_system"
+        require "chef/run_list"
       end
 
       option :recurse,
-        :long => '--[no-]recurse',
+        :long => "--[no-]recurse",
         :boolean => true,
         :description => "List dependencies recursively (default: true).  Only works with --tree."
       option :tree,
-        :long => '--tree',
+        :long => "--tree",
         :boolean => true,
         :description => "Show dependencies in a visual tree.  May show duplicates."
       option :remote,
-        :long => '--remote',
+        :long => "--remote",
         :boolean => true,
         :description => "List dependencies on the server instead of the local filesystem"
 
@@ -61,42 +61,42 @@ class Chef
 
       def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0)
         dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path]
-        output "#{'  '*depth}#{format_path(entry)}"
+        output "#{'  ' * depth}#{format_path(entry)}"
         if !printed[entry.path] && (config[:recurse] || depth == 0)
           printed[entry.path] = true
           dependencies[entry.path].each do |child|
             child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child)
-            print_dependencies_tree(child_entry, dependencies, printed, depth+1)
+            print_dependencies_tree(child_entry, dependencies, printed, depth + 1)
           end
         end
       end
 
       def get_dependencies(entry)
         begin
-          if entry.parent && entry.parent.path == '/cookbooks'
+          if entry.parent && entry.parent.path == "/cookbooks"
             return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" }
 
-          elsif entry.parent && entry.parent.path == '/nodes'
+          elsif entry.parent && entry.parent.path == "/nodes"
             node = Chef::JSONCompat.parse(entry.read)
             result = []
-            if node['chef_environment'] && node['chef_environment'] != '_default'
+            if node["chef_environment"] && node["chef_environment"] != "_default"
               result << "/environments/#{node['chef_environment']}.json"
             end
-            if node['run_list']
-              result += dependencies_from_runlist(node['run_list'])
+            if node["run_list"]
+              result += dependencies_from_runlist(node["run_list"])
             end
             result
 
-          elsif entry.parent && entry.parent.path == '/roles'
+          elsif entry.parent && entry.parent.path == "/roles"
             role = Chef::JSONCompat.parse(entry.read)
             result = []
-            if role['run_list']
-              dependencies_from_runlist(role['run_list']).each do |dependency|
+            if role["run_list"]
+              dependencies_from_runlist(role["run_list"]).each do |dependency|
                 result << dependency if !result.include?(dependency)
               end
             end
-            if role['env_run_lists']
-              role['env_run_lists'].each_pair do |env,run_list|
+            if role["env_run_lists"]
+              role["env_run_lists"].each_pair do |env, run_list|
                 dependencies_from_runlist(run_list).each do |dependency|
                   result << dependency if !result.include?(dependency)
                 end
diff --git a/lib/chef/knife/diff.rb b/lib/chef/knife/diff.rb
index e5eda52..d965490 100644
--- a/lib/chef/knife/diff.rb
+++ b/lib/chef/knife/diff.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,33 +8,33 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/command_line'
+        require "chef/chef_fs/command_line"
       end
 
       option :recurse,
-        :long => '--[no-]recurse',
+        :long => "--[no-]recurse",
         :boolean => true,
         :default => true,
         :description => "List directories recursively."
 
       option :name_only,
-        :long => '--name-only',
+        :long => "--name-only",
         :boolean => true,
         :description => "Only show names of modified files."
 
       option :name_status,
-        :long => '--name-status',
+        :long => "--name-status",
         :boolean => true,
         :description => "Only show names and statuses of modified files: Added, Deleted, Modified, and Type Changed."
 
       option :diff_filter,
-        :long => '--diff-filter=[(A|D|M|T)...[*]]',
+        :long => "--diff-filter=[(A|D|M|T)...[*]]",
         :description => "Select only files that are Added (A), Deleted (D), Modified (M), or have their type (i.e. regular file, directory) changed (T). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if
            there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected."
 
       option :cookbook_version,
-        :long => '--cookbook-version VERSION',
-        :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+        :long => "--cookbook-version VERSION",
+        :description => "Version of cookbook to download (if there are multiple versions and cookbook_versions is false)"
 
       def run
         if config[:name_only]
@@ -66,4 +66,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/download.rb b/lib/chef/knife/download.rb
index 5a432af..c609760 100644
--- a/lib/chef/knife/download.rb
+++ b/lib/chef/knife/download.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,43 +8,43 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/command_line'
+        require "chef/chef_fs/command_line"
       end
 
       option :recurse,
-        :long => '--[no-]recurse',
+        :long => "--[no-]recurse",
         :boolean => true,
         :default => true,
         :description => "List directories recursively."
 
       option :purge,
-        :long => '--[no-]purge',
+        :long => "--[no-]purge",
         :boolean => true,
         :default => false,
         :description => "Delete matching local files and directories that do not exist remotely."
 
       option :force,
-        :long => '--[no-]force',
+        :long => "--[no-]force",
         :boolean => true,
         :default => false,
         :description => "Force upload of files even if they match (quicker and harmless, but doesn't print out what it changed)"
 
       option :dry_run,
-        :long => '--dry-run',
-        :short => '-n',
+        :long => "--dry-run",
+        :short => "-n",
         :boolean => true,
         :default => false,
         :description => "Don't take action, only print what would happen"
 
       option :diff,
-        :long => '--[no-]diff',
+        :long => "--[no-]diff",
         :boolean => true,
         :default => true,
-        :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff'
+        :description => "Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff"
 
       option :cookbook_version,
-        :long => '--cookbook-version VERSION',
-        :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+        :long => "--cookbook-version VERSION",
+        :description => "Version of cookbook to download (if there are multiple versions and cookbook_versions is false)"
 
       def run
         if name_args.length == 0
@@ -66,4 +66,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/edit.rb b/lib/chef/knife/edit.rb
index 7408179..00358b2 100644
--- a/lib/chef/knife/edit.rb
+++ b/lib/chef/knife/edit.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,12 +8,12 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
-        require 'chef/chef_fs/file_system/not_found_error'
+        require "chef/chef_fs/file_system"
+        require "chef/chef_fs/file_system/not_found_error"
       end
 
       option :local,
-        :long => '--local',
+        :long => "--local",
         :boolean => true,
         :description => "Show local files instead of remote"
 
@@ -51,7 +51,7 @@ class Chef
 
       def edit_text(text, extension)
         if (!config[:disable_editing])
-          Tempfile.open([ 'knife-edit-', extension ]) do |file|
+          Tempfile.open([ "knife-edit-", extension ]) do |file|
             # Write the text to a temporary file
             file.write(text)
             file.close
@@ -70,4 +70,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/environment_compare.rb b/lib/chef/knife/environment_compare.rb
index 792ec44..8a2ef85 100644
--- a/lib/chef/knife/environment_compare.rb
+++ b/lib/chef/knife/environment_compare.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Sander Botman (<sbotman at schubergphilis.com>)
-# Copyright:: Copyright (c) 2013 Sander Botman.
+# Copyright:: Copyright 2013-2016, Sander Botman.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,37 +15,37 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
- 
-require 'chef/knife'
- 
+
+require "chef/knife"
+
 class Chef
   class Knife
     class EnvironmentCompare < Knife
- 
+
       deps do
-        require 'chef/environment'
+        require "chef/environment"
       end
- 
+
       banner "knife environment compare [ENVIRONMENT..] (options)"
 
       option :all,
         :short => "-a",
         :long => "--all",
         :description => "Show all cookbooks",
-        :boolean => true 
+        :boolean => true
 
       option :mismatch,
         :short => "-m",
         :long => "--mismatch",
         :description => "Only show mismatching versions",
         :boolean => true
- 
+
       def run
         # Get the commandline environments or all if none are provided.
-        environments = environment_list     
+        environments = environment_list
 
         # Get a list of all cookbooks that have constraints and their environment.
-        constraints = constraint_list(environments) 
+        constraints = constraint_list(environments)
 
         # Get the total list of cookbooks that have constraints
         cookbooks = cookbook_list(constraints)
@@ -55,12 +55,12 @@ class Chef
           ui.error "Cannot find any environment cookbook constraints"
           exit 1
         end
-     
+
         # Get all cookbooks so we can compare them all
-        cookbooks = rest.get_rest("/cookbooks?num_versions=1") if config[:all]
+        cookbooks = rest.get("/cookbooks?num_versions=1") if config[:all]
 
         # display matrix view of in the requested format.
-        if config[:format] == 'summary'
+        if config[:format] == "summary"
           matrix = matrix_output(cookbooks, constraints)
           ui.output(matrix)
         else
@@ -77,11 +77,11 @@ class Chef
         else
           environments = Chef::Environment.list
         end
-      end 
+      end
 
       def constraint_list(environments)
         constraints = {}
-        environments.each do |env,url|
+        environments.each do |env, url|
           # Because you cannot modify the default environment I filter it out here.
           unless env == "_default"
             envdata = Chef::Environment.load(env)
@@ -91,22 +91,22 @@ class Chef
         end
         constraints
       end
- 
+
       def cookbook_list(constraints)
         result = {}
         constraints.each { |env, cb| result.merge!(cb) }
         result
-      end      
+      end
 
       def matrix_output(cookbooks, constraints)
-        rows = [ '' ]
+        rows = [ "" ]
         environments = []
-        constraints.each { |e,v| environments << e.to_s }
+        constraints.each { |e, v| environments << e.to_s }
         columns = environments.count + 1
         environments.each { |env| rows << ui.color(env, :bold) }
-        cookbooks.each do |c,v|
+        cookbooks.each do |c, v|
           total = []
-          environments.each { |n| total << constraints[n][c]}
+          environments.each { |n| total << constraints[n][c] }
           if total.uniq.count == 1
             next if config[:mismatch]
             color = :white
@@ -116,7 +116,7 @@ class Chef
           rows << ui.color(c, :bold)
           environments.each do |e|
             tag = constraints[e][c] || "latest"
-            rows << ui.color(tag, color)   
+            rows << ui.color(tag, color)
           end
         end
         ui.list(rows, :uneven_columns_across, columns)
diff --git a/lib/chef/knife/environment_create.rb b/lib/chef/knife/environment_create.rb
index 6bc00d5..9f022bb 100644
--- a/lib/chef/knife/environment_create.rb
+++ b/lib/chef/knife/environment_create.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class EnvironmentCreate < Knife
 
       deps do
-        require 'chef/environment'
-        require 'chef/json_compat'
+        require "chef/environment"
+        require "chef/json_compat"
       end
 
       banner "knife environment create ENVIRONMENT (options)"
diff --git a/lib/chef/knife/environment_delete.rb b/lib/chef/knife/environment_delete.rb
index e17841f..869d1c7 100644
--- a/lib/chef/knife/environment_delete.rb
+++ b/lib/chef/knife/environment_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class EnvironmentDelete < Knife
 
       deps do
-        require 'chef/environment'
-        require 'chef/json_compat'
+        require "chef/environment"
+        require "chef/json_compat"
       end
 
       banner "knife environment delete ENVIRONMENT (options)"
diff --git a/lib/chef/knife/environment_edit.rb b/lib/chef/knife/environment_edit.rb
index 54962ac..43f0b06 100644
--- a/lib/chef/knife/environment_edit.rb
+++ b/lib/chef/knife/environment_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class EnvironmentEdit < Knife
 
       deps do
-        require 'chef/environment'
-        require 'chef/json_compat'
+        require "chef/environment"
+        require "chef/json_compat"
       end
 
       banner "knife environment edit ENVIRONMENT (options)"
diff --git a/lib/chef/knife/environment_from_file.rb b/lib/chef/knife/environment_from_file.rb
index 3812024..5272c89 100644
--- a/lib/chef/knife/environment_from_file.rb
+++ b/lib/chef/knife/environment_from_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@ class Chef
     class EnvironmentFromFile < Knife
 
       deps do
-        require 'chef/environment'
-        require 'chef/knife/core/object_loader'
+        require "chef/environment"
+        require "chef/knife/core/object_loader"
       end
 
       banner "knife environment from file FILE [FILE..] (options)"
@@ -62,7 +62,6 @@ class Chef
         ui.info("Updated Environment #{updated.name}")
       end
 
-
       def run
         if config[:all] == true
           load_all_environments
diff --git a/lib/chef/knife/environment_list.rb b/lib/chef/knife/environment_list.rb
index 4e70818..f278046 100644
--- a/lib/chef/knife/environment_list.rb
+++ b/lib/chef/knife/environment_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class EnvironmentList < Knife
 
       deps do
-        require 'chef/environment'
-        require 'chef/json_compat'
+        require "chef/environment"
+        require "chef/json_compat"
       end
 
       banner "knife environment list (options)"
diff --git a/lib/chef/knife/environment_show.rb b/lib/chef/knife/environment_show.rb
index 2dd07fe..6d260ad 100644
--- a/lib/chef/knife/environment_show.rb
+++ b/lib/chef/knife/environment_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,8 +25,8 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/environment'
-        require 'chef/json_compat'
+        require "chef/environment"
+        require "chef/json_compat"
       end
 
       banner "knife environment show ENVIRONMENT (options)"
diff --git a/lib/chef/knife/exec.rb b/lib/chef/knife/exec.rb
index ace4ee2..0aa8ea2 100644
--- a/lib/chef/knife/exec.rb
+++ b/lib/chef/knife/exec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/util/path_helper'
+require "chef/knife"
+require "chef/util/path_helper"
 
 class Chef::Knife::Exec < Chef::Knife
 
@@ -35,15 +35,15 @@ class Chef::Knife::Exec < Chef::Knife
     :proc => lambda { |o| o.split(":") }
 
   deps do
-    require 'chef/shell/ext'
+    require "chef/shell/ext"
   end
 
   def run
     config[:script_path] ||= Array(Chef::Config[:script_path])
 
     # Default script paths are chef-repo/.chef/scripts and ~/.chef/scripts
-    config[:script_path] << File.join(Chef::Knife.chef_config_dir, 'scripts') if Chef::Knife.chef_config_dir
-    Chef::Util::PathHelper.home('.chef', 'scripts') { |p| config[:script_path] << p }
+    config[:script_path] << File.join(Chef::Knife.chef_config_dir, "scripts") if Chef::Knife.chef_config_dir
+    Chef::Util::PathHelper.home(".chef", "scripts") { |p| config[:script_path] << p }
 
     scripts = Array(name_args)
     context = Object.new
diff --git a/lib/chef/knife/help.rb b/lib/chef/knife/help.rb
index 13fe674..e45b54e 100644
--- a/lib/chef/knife/help.rb
+++ b/lib/chef/knife/help.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,17 +40,15 @@ class Chef
 MOAR_HELP
           exit 1
         else
-          @query = name_args.join('-')
+          @query = name_args.join("-")
         end
 
-
-
         case @query
-        when 'topics', 'list'
+        when "topics", "list"
           print_help_topics
           exit 1
-        when 'intro', 'knife'
-          @topic = 'knife'
+        when "intro", "knife"
+          @topic = "knife"
         else
           @topic = find_manpages_for_query(@query)
         end
@@ -67,7 +65,7 @@ MOAR_HELP
 
       def print_help_topics
         ui.info "Available help topics are: "
-        help_topics.collect {|t| t.gsub(/knife-/, '') }.sort.each do |topic|
+        help_topics.collect { |t| t.gsub(/knife-/, "") }.sort.each do |topic|
           ui.msg "  #{topic}"
         end
       end
diff --git a/lib/chef/knife/index_rebuild.rb b/lib/chef/knife/index_rebuild.rb
index 4b9fcdd..eb85b8d 100644
--- a/lib/chef/knife/index_rebuild.rb
+++ b/lib/chef/knife/index_rebuild.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -38,9 +38,8 @@ class Chef
         else
           deprecated_server_message
           nag
-          output rest.post_rest("/search/reindex", {})
+          output rest.post("/search/reindex", {})
         end
-
       end
 
       def grab_api_info
@@ -50,7 +49,7 @@ class Chef
         # for a node we know won't exist; the 404 response that comes
         # back will give us what we want
         dummy_node = "knife_index_rebuild_test_#{rand(1000000)}"
-        rest.get_rest("/nodes/#{dummy_node}")
+        rest.get("/nodes/#{dummy_node}")
       rescue Net::HTTPServerException => exception
         r = exception.response
         parse_api_info(r)
diff --git a/lib/chef/knife/key_create.rb b/lib/chef/knife/key_create.rb
new file mode 100644
index 0000000..55c4f4e
--- /dev/null
+++ b/lib/chef/knife/key_create.rb
@@ -0,0 +1,108 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
+
+class Chef
+  class Knife
+    # Service class for UserKeyCreate and ClientKeyCreate,
+    # Implements common functionality of knife [user | org client] key create.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_accessor [Hash] cli input, see UserKeyCreate and ClientKeyCreate for what could populate it
+    class KeyCreate
+
+      attr_accessor :config
+
+      def initialize(actor, actor_field_name, ui, config)
+        @actor = actor
+        @actor_field_name = actor_field_name
+        @ui = ui
+        @config = config
+      end
+
+      def public_key_or_key_name_error_msg
+        <<EOS
+You must pass either --public-key or --key-name, or both.
+If you only pass --public-key, a key name will be generated from the fingerprint of your key.
+If you only pass --key-name, a key pair will be generated by the server.
+EOS
+      end
+
+      def edit_data(key)
+        @ui.edit_data(key)
+      end
+
+      def display_info(input)
+        @ui.info(input)
+      end
+
+      def display_private_key(private_key)
+        @ui.msg(private_key)
+      end
+
+      def output_private_key_to_file(private_key)
+        File.open(@config[:file], "w") do |f|
+          f.print(private_key)
+        end
+      end
+
+      def create_key_from_hash(output)
+        Chef::Key.from_hash(output).create
+      end
+
+      def run
+        key = Chef::Key.new(@actor, @actor_field_name)
+        if !@config[:public_key] && !@config[:key_name]
+          raise Chef::Exceptions::KeyCommandInputError, public_key_or_key_name_error_msg
+        elsif !@config[:public_key]
+          key.create_key(true)
+        end
+
+        if @config[:public_key]
+          key.public_key(File.read(File.expand_path(@config[:public_key])))
+        end
+
+        if @config[:key_name]
+          key.name(@config[:key_name])
+        end
+
+        if @config[:expiration_date]
+          key.expiration_date(@config[:expiration_date])
+        else
+          key.expiration_date("infinity")
+        end
+
+        output = edit_data(key)
+        key = create_key_from_hash(output)
+
+        display_info("Created key: #{key.name}")
+        if key.private_key
+          if @config[:file]
+            output_private_key_to_file(key.private_key)
+          else
+            display_private_key(key.private_key)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/key_create_base.rb b/lib/chef/knife/key_create_base.rb
new file mode 100644
index 0000000..d02d5ee
--- /dev/null
+++ b/lib/chef/knife/key_create_base.rb
@@ -0,0 +1,50 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  class Knife
+    # Extendable module that class_eval's common options into UserKeyCreate and ClientKeyCreate
+    #
+    # @author Tyler Cloke
+    module KeyCreateBase
+      def self.included(includer)
+        includer.class_eval do
+          option :public_key,
+                 :short => "-p FILENAME",
+                 :long => "--public-key FILENAME",
+                 :description => "Public key for newly created key. If not passed, the server will create a key pair for you, but you must pass --key-name NAME in that case."
+
+          option :file,
+                 :short => "-f FILE",
+                 :long  => "--file FILE",
+                 :description => "Write the private key to a file, if you requested the server to create one."
+
+          option :key_name,
+                 :short => "-k NAME",
+                 :long  => "--key-name NAME",
+                 :description => "The name for your key. If you do not pass a name, you must pass --public-key, and the name will default to the fingerprint of the public key passed."
+
+          option :expiration_date,
+                 :short => "-e DATE",
+                 :long  => "--expiration-date DATE",
+                 :description => "Optionally pass the expiration date for the key in ISO 8601 fomatted string: YYYY-MM-DDTHH:MM:SSZ e.g. 2013-12-24T21:00:00Z. Defaults to infinity if not passed. UTC timezone assumed."
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/key_delete.rb b/lib/chef/knife/key_delete.rb
new file mode 100644
index 0000000..b97d70d
--- /dev/null
+++ b/lib/chef/knife/key_delete.rb
@@ -0,0 +1,55 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/key"
+
+class Chef
+  class Knife
+    # Service class for UserKeyDelete and ClientKeyDelete, used to delete keys.
+    # Implements common functionality of knife [user | org client] key delete.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_accessor [Hash] cli input, see UserKeyDelete and ClientKeyDelete for what could populate it
+    class KeyDelete
+      def initialize(name, actor, actor_field_name, ui)
+        @name = name
+        @actor = actor
+        @actor_field_name = actor_field_name
+        @ui = ui
+      end
+
+      def confirm!
+        @ui.confirm("Do you really want to delete the key named #{@name} for the #{@actor_field_name} named #{@actor}")
+      end
+
+      def print_destroyed
+        @ui.info("Destroyed key named #{@name} for the #{@actor_field_name} named #{@actor}")
+      end
+
+      def run
+        key = Chef::Key.new(@actor, @actor_field_name)
+        key.name(@name)
+        confirm!
+        key.destroy
+        print_destroyed
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/knife/key_edit.rb b/lib/chef/knife/key_edit.rb
new file mode 100644
index 0000000..cd54e61
--- /dev/null
+++ b/lib/chef/knife/key_edit.rb
@@ -0,0 +1,114 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
+
+class Chef
+  class Knife
+    # Service class for UserKeyEdit and ClientKeyEdit,
+    # Implements common functionality of knife [user | org client] key edit.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_accessor [Hash] cli input, see UserKeyEdit and ClientKeyEdit for what could populate it
+    class KeyEdit
+
+      attr_accessor :config
+
+      def initialize(original_name, actor, actor_field_name, ui, config)
+        @original_name = original_name
+        @actor = actor
+        @actor_field_name = actor_field_name
+        @ui = ui
+        @config = config
+      end
+
+      def public_key_and_create_key_error_msg
+        <<EOS
+You passed both --public-key and --create-key. Only pass one, or the other, or neither.
+Do not pass either if you do not want to change the public_key field of your key.
+Pass --public-key if you want to update the public_key field of your key from a specific public key.
+Pass --create-key if you want the server to generate a new key and use that to update the public_key field of your key.
+EOS
+      end
+
+      def edit_data(key)
+        @ui.edit_data(key)
+      end
+
+      def display_info(input)
+        @ui.info(input)
+      end
+
+      def display_private_key(private_key)
+        @ui.msg(private_key)
+      end
+
+      def output_private_key_to_file(private_key)
+        File.open(@config[:file], "w") do |f|
+          f.print(private_key)
+        end
+      end
+
+      def update_key_from_hash(output)
+        Chef::Key.from_hash(output).update(@original_name)
+      end
+
+      def run
+        key = Chef::Key.new(@actor, @actor_field_name)
+        if @config[:public_key] && @config[:create_key]
+          raise Chef::Exceptions::KeyCommandInputError, public_key_and_create_key_error_msg
+        end
+
+        if @config[:create_key]
+          key.create_key(true)
+        end
+
+        if @config[:public_key]
+          key.public_key(File.read(File.expand_path(@config[:public_key])))
+        end
+
+        if @config[:key_name]
+          key.name(@config[:key_name])
+        else
+          key.name(@original_name)
+        end
+
+        if @config[:expiration_date]
+          key.expiration_date(@config[:expiration_date])
+        end
+
+        output = edit_data(key)
+        key = update_key_from_hash(output)
+
+        to_display = "Updated key: #{key.name}"
+        to_display << " (formally #{@original_name})" if key.name != @original_name
+        display_info(to_display)
+        if key.private_key
+          if @config[:file]
+            output_private_key_to_file(key.private_key)
+          else
+            display_private_key(key.private_key)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/key_edit_base.rb b/lib/chef/knife/key_edit_base.rb
new file mode 100644
index 0000000..1a613ef
--- /dev/null
+++ b/lib/chef/knife/key_edit_base.rb
@@ -0,0 +1,55 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  class Knife
+    # Extendable module that class_eval's common options into UserKeyEdit and ClientKeyEdit
+    #
+    # @author Tyler Cloke
+    module KeyEditBase
+      def self.included(includer)
+        includer.class_eval do
+          option :public_key,
+                 :short => "-p FILENAME",
+                 :long => "--public-key FILENAME",
+                 :description => "Replace the public_key field from a file on disk. If not passed, the public_key field will not change."
+
+          option :create_key,
+                 :short => "-c",
+                 :long => "--create-key",
+                 :description => "Replace the public_key field with a key generated by the server. The private key will be returned."
+
+          option :file,
+                 :short => "-f FILE",
+                 :long  => "--file FILE",
+                 :description => "Write the private key to a file, if you requested the server to create one via --create-key."
+
+          option :key_name,
+                 :short => "-k NAME",
+                 :long  => "--key-name NAME",
+                 :description => "The new name for your key. Pass if you wish to update the name field of your key."
+
+          option :expiration_date,
+                 :short => "-e DATE",
+                 :long  => "--expiration-date DATE",
+                 :description => "Updates the expiration_date field of your key if passed. Pass in ISO 8601 fomatted string: YYYY-MM-DDTHH:MM:SSZ e.g. 2013-12-24T21:00:00Z or infinity. UTC timezone assumed."
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/key_list.rb b/lib/chef/knife/key_list.rb
new file mode 100644
index 0000000..9a820b7
--- /dev/null
+++ b/lib/chef/knife/key_list.rb
@@ -0,0 +1,88 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
+
+class Chef
+  class Knife
+    # Service class for UserKeyList and ClientKeyList, used to list keys.
+    # Implements common functionality of knife [user | org client] key list.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_accessor [Hash] cli input, see UserKeyList and ClientKeyList for what could populate it
+    class KeyList
+
+      attr_accessor :config
+
+      def initialize(actor, list_method, ui, config)
+        @actor = actor
+        @list_method = list_method
+        @ui = ui
+        @config = config
+      end
+
+      def expired_and_non_expired_msg
+        <<EOS
+You cannot pass both --only-expired and --only-non-expired.
+Please pass one or none.
+EOS
+      end
+
+      def display_info(string)
+        @ui.output(string)
+      end
+
+      def colorize(string)
+        @ui.color(string, :cyan)
+      end
+
+      def run
+        if @config[:only_expired] && @config[:only_non_expired]
+          raise Chef::Exceptions::KeyCommandInputError, expired_and_non_expired_msg
+        end
+
+        # call proper list function
+        keys = Chef::Key.send(@list_method, @actor)
+        if @config[:with_details]
+          max_length = 0
+          keys.each do |key|
+            key["name"] = key["name"] + ":"
+            max_length = key["name"].length if key["name"].length > max_length
+          end
+          keys.each do |key|
+            next if !key["expired"] && @config[:only_expired]
+            next if key["expired"] && @config[:only_non_expired]
+            display = "#{colorize(key['name'].ljust(max_length))} #{key['uri']}"
+            display = "#{display} (expired)" if key["expired"]
+            display_info(display)
+          end
+        else
+          keys.each do |key|
+            next if !key["expired"] && @config[:only_expired]
+            next if key["expired"] && @config[:only_non_expired]
+            display_info(key["name"])
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/knife/key_list_base.rb b/lib/chef/knife/key_list_base.rb
new file mode 100644
index 0000000..95858e9
--- /dev/null
+++ b/lib/chef/knife/key_list_base.rb
@@ -0,0 +1,45 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  class Knife
+    # Extendable module that class_eval's common options into UserKeyList and ClientKeyList
+    #
+    # @author Tyler Cloke
+    module KeyListBase
+      def self.included(includer)
+        includer.class_eval do
+          option :with_details,
+                 :short => "-w",
+                 :long => "--with-details",
+                 :description => "Show corresponding URIs and whether the key has expired or not."
+
+          option :only_expired,
+                 :short => "-e",
+                 :long => "--only-expired",
+                 :description => "Only show expired keys."
+
+          option :only_non_expired,
+                 :short => "-n",
+                 :long => "--only-non-expired",
+                 :description => "Only show non-expired keys."
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/key_show.rb b/lib/chef/knife/key_show.rb
new file mode 100644
index 0000000..851db72
--- /dev/null
+++ b/lib/chef/knife/key_show.rb
@@ -0,0 +1,53 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/key"
+require "chef/json_compat"
+require "chef/exceptions"
+
+class Chef
+  class Knife
+    # Service class for UserKeyShow and ClientKeyShow, used to show keys.
+    # Implements common functionality of knife [user | org client] key show.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_accessor [Hash] cli input, see UserKeyShow and ClientKeyShow for what could populate it
+    class KeyShow
+
+      attr_accessor :config
+
+      def initialize(name, actor, load_method, ui)
+        @name = name
+        @actor = actor
+        @load_method = load_method
+        @ui = ui
+      end
+
+      def display_output(key)
+        @ui.output(@ui.format_for_display(key))
+      end
+
+      def run
+        key = Chef::Key.send(@load_method, @actor, @name)
+        key.public_key(key.public_key.strip)
+        display_output(key)
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/list.rb b/lib/chef/knife/list.rb
index 137d61f..3d1583b 100644
--- a/lib/chef/knife/list.rb
+++ b/lib/chef/knife/list.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,33 +8,33 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
-        require 'highline'
+        require "chef/chef_fs/file_system"
+        require "highline"
       end
 
       option :recursive,
-        :short => '-R',
+        :short => "-R",
         :boolean => true,
         :description => "List directories recursively"
       option :bare_directories,
-        :short => '-d',
+        :short => "-d",
         :boolean => true,
         :description => "When directories match the pattern, do not show the directories' children"
       option :local,
-        :long => '--local',
+        :long => "--local",
         :boolean => true,
         :description => "List local directory instead of remote"
       option :flat,
-        :short => '-f',
-        :long => '--flat',
+        :short => "-f",
+        :long => "--flat",
         :boolean => true,
         :description => "Show a list of filenames rather than the prettified ls-like output normally produced"
       option :one_column,
-        :short => '-1',
+        :short => "-1",
         :boolean => true,
         :description => "Show only one column of results"
       option :trailing_slashes,
-        :short => '-p',
+        :short => "-p",
         :boolean => true,
         :description => "Show trailing slashes after directories"
 
@@ -47,6 +47,7 @@ class Chef
         args = pattern_args_from(patterns)
         all_results = parallelize(pattern_args_from(patterns)) do |pattern|
           pattern_results = Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).to_a
+
           if pattern_results.first && !pattern_results.first.exists? && pattern.exact_path
             ui.error "#{format_path(pattern_results.first)}: No such file or directory"
             self.exit_code = 1
@@ -129,17 +130,17 @@ class Chef
         else
           columns = HighLine::SystemExtensions.terminal_size[0]
         end
-        current_line = ''
+        current_line = ""
         results.each do |result|
           if current_line.length > 0 && current_line.length + print_space > columns
             output current_line.rstrip
-            current_line = ''
+            current_line = ""
           end
           if current_line.length == 0
             current_line << indent
           end
           current_line << result
-          current_line << (' ' * (print_space - result.length))
+          current_line << (" " * (print_space - result.length))
         end
         output current_line.rstrip if current_line.length > 0
       end
diff --git a/lib/chef/knife/node_bulk_delete.rb b/lib/chef/knife/node_bulk_delete.rb
index 89b2abe..2ca63da 100644
--- a/lib/chef/knife/node_bulk_delete.rb
+++ b/lib/chef/knife/node_bulk_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeBulkDelete < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node bulk delete REGEX (options)"
@@ -35,7 +35,6 @@ class Chef
           exit 42
         end
 
-
         nodes_to_delete = {}
         matcher = /#{name_args[0]}/
 
@@ -55,7 +54,6 @@ class Chef
         ui.msg("")
         ui.confirm("Are you sure you want to delete these nodes")
 
-
         nodes_to_delete.sort.each do |name, node|
           node.destroy
           ui.msg("Deleted node #{name}")
@@ -66,7 +64,7 @@ class Chef
         node_uris_by_name = Chef::Node.list
 
         node_uris_by_name.keys.inject({}) do |nodes_by_name, name|
-          nodes_by_name[name] = Chef::Node.new.tap {|n| n.name(name)}
+          nodes_by_name[name] = Chef::Node.new.tap { |n| n.name(name) }
           nodes_by_name
         end
       end
@@ -74,7 +72,3 @@ class Chef
     end
   end
 end
-
-
-
-
diff --git a/lib/chef/knife/node_create.rb b/lib/chef/knife/node_create.rb
index 7f50a30..21d67f1 100644
--- a/lib/chef/knife/node_create.rb
+++ b/lib/chef/knife/node_create.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeCreate < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node create NODE (options)"
@@ -45,6 +45,3 @@ class Chef
     end
   end
 end
-
-
-
diff --git a/lib/chef/knife/node_delete.rb b/lib/chef/knife/node_delete.rb
index a645d32..4dd7d76 100644
--- a/lib/chef/knife/node_delete.rb
+++ b/lib/chef/knife/node_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeDelete < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node delete NODE (options)"
@@ -44,4 +44,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/node_edit.rb b/lib/chef/knife/node_edit.rb
index 0d6b8fc..4632c0a 100644
--- a/lib/chef/knife/node_edit.rb
+++ b/lib/chef/knife/node_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -24,9 +24,9 @@ class Chef
     class NodeEdit < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
-        require 'chef/knife/core/node_editor'
+        require "chef/node"
+        require "chef/json_compat"
+        require "chef/knife/core/node_editor"
       end
 
       banner "knife node edit NODE (options)"
@@ -68,5 +68,3 @@ class Chef
     end
   end
 end
-
-
diff --git a/lib/chef/knife/node_environment_set.rb b/lib/chef/knife/node_environment_set.rb
index da72aea..ecba01b 100644
--- a/lib/chef/knife/node_environment_set.rb
+++ b/lib/chef/knife/node_environment_set.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jimmy McCrory (<jimmy.mccrory at gmail.com>)
-# Copyright:: Copyright (c) 2014 Jimmy McCrory
+# Copyright:: Copyright 2014-2016, Jimmy McCrory
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeEnvironmentSet < Knife
 
       deps do
-        require 'chef/node'
+        require "chef/node"
       end
 
       banner "knife node environment set NODE ENVIRONMENT"
@@ -46,7 +46,7 @@ class Chef
 
         config[:attribute] = "chef_environment"
 
-        output(format_for_display(node))   
+        output(format_for_display(node))
       end
 
     end
diff --git a/lib/chef/knife/node_from_file.rb b/lib/chef/knife/node_from_file.rb
index 66f2a46..8e05e27 100644
--- a/lib/chef/knife/node_from_file.rb
+++ b/lib/chef/knife/node_from_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeFromFile < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
-        require 'chef/knife/core/object_loader'
+        require "chef/node"
+        require "chef/json_compat"
+        require "chef/knife/core/object_loader"
       end
 
       banner "knife node from file FILE (options)"
@@ -36,12 +36,12 @@ class Chef
 
       def run
         @name_args.each do |arg|
-          updated = loader.load_from('nodes', arg)
-  
+          updated = loader.load_from("nodes", arg)
+
           updated.save
-  
+
           output(format_for_display(updated)) if config[:print_after]
-  
+
           ui.info("Updated Node #{updated.name}!")
         end
       end
diff --git a/lib/chef/knife/node_list.rb b/lib/chef/knife/node_list.rb
index 3926d10..4885208 100644
--- a/lib/chef/knife/node_list.rb
+++ b/lib/chef/knife/node_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeList < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node list (options)"
@@ -42,5 +42,3 @@ class Chef
     end
   end
 end
-
-
diff --git a/lib/chef/knife/node_run_list_add.rb b/lib/chef/knife/node_run_list_add.rb
index 519c280..f8d40c8 100644
--- a/lib/chef/knife/node_run_list_add.rb
+++ b/lib/chef/knife/node_run_list_add.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeRunListAdd < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)"
@@ -44,11 +44,11 @@ class Chef
         if @name_args.size > 2
           # Check for nested lists and create a single plain one
           entries = @name_args[1..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[1].split(',').map { |e| e.strip }
+          entries = @name_args[1].split(",").map { |e| e.strip }
         end
 
         if config[:after] && config[:before]
@@ -73,7 +73,7 @@ class Chef
 
       private
 
-      def add_to_run_list_after(node, entries, after=nil)
+      def add_to_run_list_after(node, entries, after = nil)
         if after
           nlist = []
           node.run_list.each do |entry|
diff --git a/lib/chef/knife/node_run_list_remove.rb b/lib/chef/knife/node_run_list_remove.rb
index 4b8953a..3f9cdab 100644
--- a/lib/chef/knife/node_run_list_remove.rb
+++ b/lib/chef/knife/node_run_list_remove.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeRunListRemove < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node run_list remove [NODE] [ENTRY[,ENTRY]] (options)"
@@ -35,14 +35,25 @@ class Chef
         if @name_args.size > 2
           # Check for nested lists and create a single plain one
           entries = @name_args[1..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[1].split(',').map { |e| e.strip }
+          entries = @name_args[1].split(",").map { |e| e.strip }
         end
 
-        entries.each { |e| node.run_list.remove(e) }
+        # iterate over the list of things to remove,
+        # warning if one of them was not found
+        entries.each do |e|
+          if node.run_list.find { |rli| e == rli.to_s }
+            node.run_list.remove(e)
+          else
+            ui.warn "#{e} is not in the run list"
+            unless e =~ /^(recipe|role)\[/
+              ui.warn "(did you forget recipe[] or role[] around it?)"
+            end
+          end
+        end
 
         node.save
 
diff --git a/lib/chef/knife/node_run_list_set.rb b/lib/chef/knife/node_run_list_set.rb
index e327d2a..2d68c88 100644
--- a/lib/chef/knife/node_run_list_set.rb
+++ b/lib/chef/knife/node_run_list_set.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class NodeRunListSet < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node run_list set NODE ENTRIES (options)"
@@ -37,11 +37,11 @@ class Chef
         elsif @name_args.size > 2
           # Check for nested lists and create a single plain one
           entries = @name_args[1..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[1].split(',').map { |e| e.strip }
+          entries = @name_args[1].split(",").map { |e| e.strip }
         end
         node = Chef::Node.load(@name_args[0])
 
diff --git a/lib/chef/knife/node_show.rb b/lib/chef/knife/node_show.rb
index dc47da1..c616b8a 100644
--- a/lib/chef/knife/node_show.rb
+++ b/lib/chef/knife/node_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/node_presenter"
 
 class Chef
   class Knife
@@ -27,8 +27,8 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife node show NODE (options)"
@@ -64,4 +64,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/null.rb b/lib/chef/knife/null.rb
new file mode 100644
index 0000000..0b5058e
--- /dev/null
+++ b/lib/chef/knife/null.rb
@@ -0,0 +1,10 @@
+class Chef
+  class Knife
+    class Null < Chef::Knife
+      banner "knife null"
+
+      def run
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_create.rb b/lib/chef/knife/osc_user_create.rb
new file mode 100644
index 0000000..3d879fd
--- /dev/null
+++ b/lib/chef/knife/osc_user_create.rb
@@ -0,0 +1,97 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_create.rb.
+class Chef
+  class Knife
+    class OscUserCreate < Knife
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      option :file,
+        :short => "-f FILE",
+        :long  => "--file FILE",
+        :description => "Write the private key to a file"
+
+      option :admin,
+        :short => "-a",
+        :long  => "--admin",
+        :description => "Create the user as an admin",
+        :boolean => true
+
+      option :user_password,
+        :short => "-p PASSWORD",
+        :long => "--password PASSWORD",
+        :description => "Password for newly created user",
+        :default => ""
+
+      option :user_key,
+        :long => "--user-key FILENAME",
+        :description => "Public key for newly created user.  By default a key will be created for you."
+
+      banner "knife osc_user create USER (options)"
+
+      def run
+        @user_name = @name_args[0]
+
+        if @user_name.nil?
+          show_usage
+          ui.fatal("You must specify a user name")
+          exit 1
+        end
+
+        if config[:user_password].length == 0
+          show_usage
+          ui.fatal("You must specify a non-blank password")
+          exit 1
+        end
+
+        user = Chef::User.new
+        user.name(@user_name)
+        user.admin(config[:admin])
+        user.password config[:user_password]
+
+        if config[:user_key]
+          user.public_key File.read(File.expand_path(config[:user_key]))
+        end
+
+        output = edit_data(user)
+        user = Chef::User.from_hash(output).create
+
+        ui.info("Created #{user}")
+        if user.private_key
+          if config[:file]
+            File.open(config[:file], "w") do |f|
+              f.print(user.private_key)
+            end
+          else
+            ui.msg user.private_key
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_delete.rb b/lib/chef/knife/osc_user_delete.rb
new file mode 100644
index 0000000..51abc1c
--- /dev/null
+++ b/lib/chef/knife/osc_user_delete.rb
@@ -0,0 +1,51 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in the user_delete.rb.
+
+class Chef
+  class Knife
+    class OscUserDelete < Knife
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      banner "knife osc_user delete USER (options)"
+
+      def run
+        @user_name = @name_args[0]
+
+        if @user_name.nil?
+          show_usage
+          ui.fatal("You must specify a user name")
+          exit 1
+        end
+
+        delete_object(Chef::User, @user_name)
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_edit.rb b/lib/chef/knife/osc_user_edit.rb
new file mode 100644
index 0000000..b0c691d
--- /dev/null
+++ b/lib/chef/knife/osc_user_edit.rb
@@ -0,0 +1,58 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_edit.rb.
+
+class Chef
+  class Knife
+    class OscUserEdit < Knife
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      banner "knife osc_user edit USER (options)"
+
+      def run
+        @user_name = @name_args[0]
+
+        if @user_name.nil?
+          show_usage
+          ui.fatal("You must specify a user name")
+          exit 1
+        end
+
+        original_user = Chef::User.load(@user_name).to_hash
+        edited_user = edit_data(original_user)
+        if original_user != edited_user
+          user = Chef::User.from_hash(edited_user)
+          user.update
+          ui.msg("Saved #{user}.")
+        else
+          ui.msg("User unchaged, not saving.")
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_list.rb b/lib/chef/knife/osc_user_list.rb
new file mode 100644
index 0000000..f1002c4
--- /dev/null
+++ b/lib/chef/knife/osc_user_list.rb
@@ -0,0 +1,47 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_list.rb.
+
+class Chef
+  class Knife
+    class OscUserList < Knife
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      banner "knife osc_user list (options)"
+
+      option :with_uri,
+        :short => "-w",
+        :long => "--with-uri",
+        :description => "Show corresponding URIs"
+
+      def run
+        output(format_list_for_display(Chef::User.list))
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_reregister.rb b/lib/chef/knife/osc_user_reregister.rb
new file mode 100644
index 0000000..b513f31
--- /dev/null
+++ b/lib/chef/knife/osc_user_reregister.rb
@@ -0,0 +1,64 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_reregister.rb.
+
+class Chef
+  class Knife
+    class OscUserReregister < Knife
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      banner "knife osc_user reregister USER (options)"
+
+      option :file,
+        :short => "-f FILE",
+        :long  => "--file FILE",
+        :description => "Write the private key to a file"
+
+      def run
+        @user_name = @name_args[0]
+
+        if @user_name.nil?
+          show_usage
+          ui.fatal("You must specify a user name")
+          exit 1
+        end
+
+        user = Chef::User.load(@user_name).reregister
+        Chef::Log.debug("Updated user data: #{user.inspect}")
+        key = user.private_key
+        if config[:file]
+          File.open(config[:file], "w") do |f|
+            f.print(key)
+          end
+        else
+          ui.msg key
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/osc_user_show.rb b/lib/chef/knife/osc_user_show.rb
new file mode 100644
index 0000000..22e9bf4
--- /dev/null
+++ b/lib/chef/knife/osc_user_show.rb
@@ -0,0 +1,54 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_show.rb.
+
+class Chef
+  class Knife
+    class OscUserShow < Knife
+
+      include Knife::Core::MultiAttributeReturnOption
+
+      deps do
+        require "chef/user"
+        require "chef/json_compat"
+      end
+
+      banner "knife osc_user show USER (options)"
+
+      def run
+        @user_name = @name_args[0]
+
+        if @user_name.nil?
+          show_usage
+          ui.fatal("You must specify a user name")
+          exit 1
+        end
+
+        user = Chef::User.load(@user_name)
+        output(format_for_display(user))
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb
index 601cfce..56527a0 100644
--- a/lib/chef/knife/raw.rb
+++ b/lib/chef/knife/raw.rb
@@ -1,4 +1,5 @@
-require 'chef/knife'
+require "chef/knife"
+require "chef/http"
 
 class Chef
   class Knife
@@ -6,34 +7,34 @@ class Chef
       banner "knife raw REQUEST_PATH"
 
       deps do
-        require 'chef/json_compat'
-        require 'chef/config'
-        require 'chef/http'
-        require 'chef/http/authenticator'
-        require 'chef/http/cookie_manager'
-        require 'chef/http/decompressor'
-        require 'chef/http/json_output'
+        require "chef/json_compat"
+        require "chef/config"
+        require "chef/http"
+        require "chef/http/authenticator"
+        require "chef/http/cookie_manager"
+        require "chef/http/decompressor"
+        require "chef/http/json_output"
       end
 
       option :method,
-        :long => '--method METHOD',
-        :short => '-m METHOD',
+        :long => "--method METHOD",
+        :short => "-m METHOD",
         :default => "GET",
         :description => "Request method (GET, POST, PUT or DELETE).  Default: GET"
 
       option :pretty,
-        :long => '--[no-]pretty',
+        :long => "--[no-]pretty",
         :boolean => true,
         :default => true,
         :description => "Pretty-print JSON output.  Default: true"
 
       option :input,
-        :long => '--input FILE',
-        :short => '-i FILE',
+        :long => "--input FILE",
+        :short => "-i FILE",
         :description => "Name of file to use for PUT or POST"
 
       option :proxy_auth,
-        :long => '--proxy-auth',
+        :long => "--proxy-auth",
         :boolean => true,
         :default => false,
         :description => "Use webui proxy authentication.  Client key must be the webui key."
@@ -70,10 +71,10 @@ class Chef
         begin
           method = config[:method].to_sym
 
-          headers = {'Content-Type' => 'application/json'}
+          headers = { "Content-Type" => "application/json" }
 
           if config[:proxy_auth]
-            headers['x-ops-request-source'] = 'web'
+            headers["x-ops-request-source"] = "web"
           end
 
           if config[:pretty]
@@ -92,7 +93,7 @@ class Chef
           exit 1
         rescue Net::HTTPServerException => e
           ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\""
-          ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ''
+          ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != ""
           exit 1
         end
       end
diff --git a/lib/chef/knife/recipe_list.rb b/lib/chef/knife/recipe_list.rb
index ed7d2a9..8f76e49 100644
--- a/lib/chef/knife/recipe_list.rb
+++ b/lib/chef/knife/recipe_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 class Chef::Knife::RecipeList < Chef::Knife
 
   banner "knife recipe list [PATTERN]"
 
   def run
-    recipes = rest.get_rest('cookbooks/_recipes')
+    recipes = rest.get("cookbooks/_recipes")
     if pattern = @name_args.first
       recipes = recipes.grep(Regexp.new(pattern))
     end
diff --git a/lib/chef/knife/rehash.rb b/lib/chef/knife/rehash.rb
new file mode 100644
index 0000000..3e7bab7
--- /dev/null
+++ b/lib/chef/knife/rehash.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Steven Danna <steve at chef.io>
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/core/subcommand_loader"
+
+class Chef
+  class Knife
+    class Rehash < Chef::Knife
+      banner "knife rehash"
+
+      def run
+        if ! Chef::Knife::SubcommandLoader.autogenerated_manifest?
+          ui.msg "Using knife-rehash will speed up knife's load time by caching the location of subcommands on disk."
+          ui.msg "However, you will need to update the cache by running `knife rehash` anytime you install a new knife plugin."
+        else
+          reload_plugins
+        end
+        write_hash(generate_hash)
+      end
+
+      def reload_plugins
+        Chef::Knife::SubcommandLoader::GemGlobLoader.new(@@chef_config_dir).load_commands
+      end
+
+      def generate_hash
+        output = if Chef::Knife::SubcommandLoader.plugin_manifest?
+                   Chef::Knife::SubcommandLoader.plugin_manifest
+                 else
+                   { Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY => {} }
+                 end
+        output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]["plugins_paths"] = Chef::Knife.subcommand_files
+        output[Chef::Knife::SubcommandLoader::HashedCommandLoader::KEY]["plugins_by_category"] = Chef::Knife.subcommands_by_category
+        output
+      end
+
+      def write_hash(data)
+        plugin_manifest_dir = File.expand_path("..", Chef::Knife::SubcommandLoader.plugin_manifest_path)
+        FileUtils.mkdir_p(plugin_manifest_dir) unless File.directory?(plugin_manifest_dir)
+        File.open(Chef::Knife::SubcommandLoader.plugin_manifest_path, "w") do |f|
+          f.write(Chef::JSONCompat.to_json_pretty(data))
+          ui.msg "Knife subcommands are cached in #{Chef::Knife::SubcommandLoader.plugin_manifest_path}. Delete this file to disable the caching."
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/role_bulk_delete.rb b/lib/chef/knife/role_bulk_delete.rb
index 8b24f55..0726454 100644
--- a/lib/chef/knife/role_bulk_delete.rb
+++ b/lib/chef/knife/role_bulk_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleBulkDelete < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role bulk delete REGEX (options)"
@@ -63,8 +63,3 @@ class Chef
     end
   end
 end
-
-
-
-
-
diff --git a/lib/chef/knife/role_create.rb b/lib/chef/knife/role_create.rb
index e9e363e..7e581f4 100644
--- a/lib/chef/knife/role_create.rb
+++ b/lib/chef/knife/role_create.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleCreate < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role create ROLE (options)"
@@ -51,5 +51,3 @@ class Chef
     end
   end
 end
-
-
diff --git a/lib/chef/knife/role_delete.rb b/lib/chef/knife/role_delete.rb
index b823f37..5c10a05 100644
--- a/lib/chef/knife/role_delete.rb
+++ b/lib/chef/knife/role_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleDelete < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role delete ROLE (options)"
@@ -44,4 +44,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/role_edit.rb b/lib/chef/knife/role_edit.rb
index b058098..d369784 100644
--- a/lib/chef/knife/role_edit.rb
+++ b/lib/chef/knife/role_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEdit < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role edit ROLE (options)"
@@ -43,6 +43,3 @@ class Chef
     end
   end
 end
-
-
-
diff --git a/lib/chef/knife/role_env_run_list_add.rb b/lib/chef/knife/role_env_run_list_add.rb
index faf84cc..61aec50 100644
--- a/lib/chef/knife/role_env_run_list_add.rb
+++ b/lib/chef/knife/role_env_run_list_add.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEnvRunListAdd < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY[,ENTRY]] (options)"
@@ -34,13 +34,13 @@ class Chef
         :long  => "--after ITEM",
         :description => "Place the ENTRY in the run list after ITEM"
 
-      def add_to_env_run_list(role, environment, entries, after=nil)
+      def add_to_env_run_list(role, environment, entries, after = nil)
         if after
           nlist = []
           unless role.env_run_lists.key?(environment)
             role.env_run_lists_add(environment => nlist)
           end
-          role.run_list_for(environment).each do |entry| 
+          role.run_list_for(environment).each do |entry|
             nlist << entry
             if entry == after
               entries.each { |e| nlist << e }
@@ -68,11 +68,11 @@ class Chef
         if @name_args.size > 2
           # Check for nested lists and create a single plain one
           entries = @name_args[2..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[2].split(',').map { |e| e.strip }
+          entries = @name_args[2].split(",").map { |e| e.strip }
         end
 
         add_to_env_run_list(role, environment, entries, config[:after])
diff --git a/lib/chef/knife/role_env_run_list_clear.rb b/lib/chef/knife/role_env_run_list_clear.rb
index 4304f29..d9dc96c 100644
--- a/lib/chef/knife/role_env_run_list_clear.rb
+++ b/lib/chef/knife/role_env_run_list_clear.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEnvRunListClear < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role env_run_list clear [ROLE] [ENVIRONMENT]"
diff --git a/lib/chef/knife/role_env_run_list_remove.rb b/lib/chef/knife/role_env_run_list_remove.rb
index 9ffc3f5..576e32e 100644
--- a/lib/chef/knife/role_env_run_list_remove.rb
+++ b/lib/chef/knife/role_env_run_list_remove.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,28 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEnvRunListRemove < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role env_run_list remove [ROLE] [ENVIRONMENT] [ENTRIES]"
 
       def remove_from_env_run_list(role, environment, item_to_remove)
-          nlist = []
-          role.run_list_for(environment).each do |entry|
-            nlist << entry unless entry == item_to_remove
-            #unless entry == @name_args[2]
-            #  nlist << entry
-            #end
-          end
-          role.env_run_lists_add(environment => nlist)
+        nlist = []
+        role.run_list_for(environment).each do |entry|
+          nlist << entry unless entry == item_to_remove
+          #unless entry == @name_args[2]
+          #  nlist << entry
+          #end
+        end
+        role.env_run_lists_add(environment => nlist)
       end
 
       def run
diff --git a/lib/chef/knife/role_env_run_list_replace.rb b/lib/chef/knife/role_env_run_list_replace.rb
index 146d0c4..e84e351 100644
--- a/lib/chef/knife/role_env_run_list_replace.rb
+++ b/lib/chef/knife/role_env_run_list_replace.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEnvRunListReplace < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role env_run_list replace [ROLE] [ENVIRONMENT] [OLD_ENTRY] [NEW_ENTRY] "
 
       def replace_in_env_run_list(role, environment, old_entry, new_entry)
         nlist = []
-        role.run_list_for(environment).each do |entry| 
+        role.run_list_for(environment).each do |entry|
           if entry == old_entry
             nlist << new_entry
           else
diff --git a/lib/chef/knife/role_env_run_list_set.rb b/lib/chef/knife/role_env_run_list_set.rb
index a161851..f53616e 100644
--- a/lib/chef/knife/role_env_run_list_set.rb
+++ b/lib/chef/knife/role_env_run_list_set.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleEnvRunListSet < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role env_run_list set [ROLE] [ENVIRONMENT] [ENTRIES]"
@@ -52,11 +52,11 @@ class Chef
         elsif @name_args.size > 2
           # Check for nested lists and create a single plain one
           entries = @name_args[2..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[2].split(',').map { |e| e.strip }
+          entries = @name_args[2].split(",").map { |e| e.strip }
         end
 
         set_env_run_list(role, environment, entries )
diff --git a/lib/chef/knife/role_from_file.rb b/lib/chef/knife/role_from_file.rb
index c80218b..e1f4737 100644
--- a/lib/chef/knife/role_from_file.rb
+++ b/lib/chef/knife/role_from_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleFromFile < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/knife/core/object_loader'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/knife/core/object_loader"
+        require "chef/json_compat"
       end
 
       banner "knife role from file FILE [FILE..] (options)"
@@ -49,8 +49,3 @@ class Chef
     end
   end
 end
-
-
-
-
-
diff --git a/lib/chef/knife/role_list.rb b/lib/chef/knife/role_list.rb
index 0f105b2..1247478 100644
--- a/lib/chef/knife/role_list.rb
+++ b/lib/chef/knife/role_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleList < Knife
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife role list (options)"
@@ -40,4 +40,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/role_run_list_add.rb b/lib/chef/knife/role_run_list_add.rb
index c9d7785..6aa92d3 100644
--- a/lib/chef/knife/role_run_list_add.rb
+++ b/lib/chef/knife/role_run_list_add.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleRunListAdd < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role run_list add [ROLE] [ENTRY[,ENTRY]] (options)"
@@ -34,13 +34,13 @@ class Chef
         :long  => "--after ITEM",
         :description => "Place the ENTRY in the run list after ITEM"
 
-      def add_to_env_run_list(role, environment, entries, after=nil)
+      def add_to_env_run_list(role, environment, entries, after = nil)
         if after
           nlist = []
           unless role.env_run_lists.key?(environment)
             role.env_run_lists_add(environment => nlist)
           end
-          role.run_list_for(environment).each do |entry| 
+          role.run_list_for(environment).each do |entry|
             nlist << entry
             if entry == after
               entries.each { |e| nlist << e }
@@ -68,11 +68,11 @@ class Chef
         if @name_args.size > 1
           # Check for nested lists and create a single plain one
           entries = @name_args[1..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[1].split(',').map { |e| e.strip }
+          entries = @name_args[1].split(",").map { |e| e.strip }
         end
 
         add_to_env_run_list(role, environment, entries, config[:after])
diff --git a/lib/chef/knife/role_run_list_clear.rb b/lib/chef/knife/role_run_list_clear.rb
index ed6225d..81678d3 100644
--- a/lib/chef/knife/role_run_list_clear.rb
+++ b/lib/chef/knife/role_run_list_clear.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleRunListClear < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role run_list clear [ROLE]"
diff --git a/lib/chef/knife/role_run_list_remove.rb b/lib/chef/knife/role_run_list_remove.rb
index d783b34..0dacfee 100644
--- a/lib/chef/knife/role_run_list_remove.rb
+++ b/lib/chef/knife/role_run_list_remove.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,28 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleRunListRemove < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role run_list remove [ROLE] [ENTRY]"
 
       def remove_from_env_run_list(role, environment, item_to_remove)
-          nlist = []
-          role.run_list_for(environment).each do |entry|
-            nlist << entry unless entry == item_to_remove
-            #unless entry == @name_args[2]
-            #  nlist << entry
-            #end
-          end
-          role.env_run_lists_add(environment => nlist)
+        nlist = []
+        role.run_list_for(environment).each do |entry|
+          nlist << entry unless entry == item_to_remove
+          #unless entry == @name_args[2]
+          #  nlist << entry
+          #end
+        end
+        role.env_run_lists_add(environment => nlist)
       end
 
       def run
diff --git a/lib/chef/knife/role_run_list_replace.rb b/lib/chef/knife/role_run_list_replace.rb
index 1ab94df..3e7bc2d 100644
--- a/lib/chef/knife/role_run_list_replace.rb
+++ b/lib/chef/knife/role_run_list_replace.rb
@@ -1,6 +1,6 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleRunListReplace < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role run_list replace [ROLE] [OLD_ENTRY] [NEW_ENTRY] "
 
       def replace_in_env_run_list(role, environment, old_entry, new_entry)
         nlist = []
-        role.run_list_for(environment).each do |entry| 
+        role.run_list_for(environment).each do |entry|
           if entry == old_entry
             nlist << new_entry
           else
diff --git a/lib/chef/knife/role_run_list_set.rb b/lib/chef/knife/role_run_list_set.rb
index b9675c7..644af1c 100644
--- a/lib/chef/knife/role_run_list_set.rb
+++ b/lib/chef/knife/role_run_list_set.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
 # Author:: William Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class RoleRunListSet < Knife
 
       deps do
-        require 'chef/role'
-        require 'chef/json_compat'
+        require "chef/role"
+        require "chef/json_compat"
       end
 
       banner "knife role run_list set [ROLE] [ENTRIES]"
@@ -52,11 +52,11 @@ class Chef
         elsif @name_args.size > 1
           # Check for nested lists and create a single plain one
           entries = @name_args[1..-1].map do |entry|
-            entry.split(',').map { |e| e.strip }
+            entry.split(",").map { |e| e.strip }
           end.flatten
         else
           # Convert to array and remove the extra spaces
-          entries = @name_args[1].split(',').map { |e| e.strip }
+          entries = @name_args[1].split(",").map { |e| e.strip }
         end
 
         set_env_run_list(role, environment, entries )
diff --git a/lib/chef/knife/role_show.rb b/lib/chef/knife/role_show.rb
index 159571f..9968476 100644
--- a/lib/chef/knife/role_show.rb
+++ b/lib/chef/knife/role_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,13 +25,12 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/node'
-        require 'chef/json_compat'
+        require "chef/node"
+        require "chef/json_compat"
       end
 
       banner "knife role show ROLE (options)"
 
-
       def run
         @role_name = @name_args[0]
 
@@ -48,5 +47,3 @@ class Chef
     end
   end
 end
-
-
diff --git a/lib/chef/knife/search.rb b/lib/chef/knife/search.rb
index 9319d30..30a3db3 100644
--- a/lib/chef/knife/search.rb
+++ b/lib/chef/knife/search.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/node_presenter"
 
 class Chef
   class Knife
@@ -26,10 +26,10 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/node'
-        require 'chef/environment'
-        require 'chef/api_client'
-        require 'chef/search/query'
+        require "chef/node"
+        require "chef/environment"
+        require "chef/api_client"
+        require "chef/search/query"
       end
 
       include Knife::Core::NodeFormattingOptions
@@ -80,7 +80,7 @@ class Chef
         read_cli_args
         fuzzify_query
 
-        if @type == 'node'
+        if @type == "node"
           ui.use_presenter Knife::Core::NodePresenter
         end
 
@@ -106,7 +106,7 @@ class Chef
             formatted_item = Hash.new
             if item.is_a?(Hash)
               # doing a little magic here to set the correct name
-              formatted_item[item["__display_name"]] = item.reject{|k| k == "__display_name"}
+              formatted_item[item["__display_name"]] = item.reject { |k| k == "__display_name" }
             else
               formatted_item = format_for_display(item)
             end
@@ -120,7 +120,7 @@ class Chef
         end
 
         if ui.interchange?
-          output({:results => result_count, :rows => result_items})
+          output({ :results => result_count, :rows => result_items })
         else
           ui.log "#{result_count} items found"
           ui.log("\n")
@@ -136,7 +136,7 @@ class Chef
       def read_cli_args
         if config[:query]
           if @name_args[1]
-            ui.error "please specify query as an argument or an option via -q, not both"
+            ui.error "Please specify query as an argument or an option via -q, not both"
             ui.msg opt_parser
             exit 1
           end
@@ -145,7 +145,7 @@ class Chef
         else
           case name_args.size
           when 0
-            ui.error "no query specified"
+            ui.error "No query specified"
             ui.msg opt_parser
             exit 1
           when 1
@@ -160,7 +160,7 @@ class Chef
 
       def fuzzify_query
         if @query !~ /:/
-          @query = "tags:*#{@query}* OR roles:*#{@query}* OR fqdn:*#{@query}* OR addresses:*#{@query}*"
+          @query = "tags:*#{@query}* OR roles:*#{@query}* OR fqdn:*#{@query}* OR addresses:*#{@query}* OR policy_name:*#{@query}* OR policy_group:*#{@query}*"
         end
       end
 
diff --git a/lib/chef/knife/serve.rb b/lib/chef/knife/serve.rb
index 84918e2..f74a5c1 100644
--- a/lib/chef/knife/serve.rb
+++ b/lib/chef/knife/serve.rb
@@ -1,23 +1,23 @@
-require 'chef/knife'
-require 'chef/local_mode'
+require "chef/knife"
+require "chef/local_mode"
 
 class Chef
   class Knife
     class Serve < Knife
-      
-      banner 'knife serve (options)'
+
+      banner "knife serve (options)"
 
       option :repo_mode,
-        :long => '--repo-mode MODE',
+        :long => "--repo-mode MODE",
         :description => "Specifies the local repository layout.  Values: static (only environments/roles/data_bags/cookbooks), everything (includes nodes/clients/users), hosted_everything (includes acls/groups/etc. for Enterprise/Hosted Chef).  Default: everything/hosted_everything"
 
       option :chef_repo_path,
-        :long => '--chef-repo-path PATH',
-        :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+        :long => "--chef-repo-path PATH",
+        :description => "Overrides the location of chef repo. Default is specified by chef_repo_path in the config"
 
       option :chef_zero_host,
-        :long => '--chef-zero-host IP',
-        :description => 'Overrides the host upon which chef-zero listens. Default is 127.0.0.1.'
+        :long => "--chef-zero-host IP",
+        :description => "Overrides the host upon which chef-zero listens. Default is 127.0.0.1."
 
       def configure_chef
         super
@@ -27,7 +27,7 @@ class Chef
         # --chef-repo-path forcibly overrides all other paths
         if config[:chef_repo_path]
           Chef::Config.chef_repo_path = config[:chef_repo_path]
-          %w(acl client cookbook container data_bag environment group node role user).each do |variable_name|
+          %w{acl client cookbook container data_bag environment group node role user}.each do |variable_name|
             Chef::Config.delete("#{variable_name}_path".to_sym)
           end
         end
diff --git a/lib/chef/knife/show.rb b/lib/chef/knife/show.rb
index 4684a6a..88a1929 100644
--- a/lib/chef/knife/show.rb
+++ b/lib/chef/knife/show.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,12 +8,12 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
-        require 'chef/chef_fs/file_system/not_found_error'
+        require "chef/chef_fs/file_system"
+        require "chef/chef_fs/file_system/not_found_error"
       end
 
       option :local,
-        :long => '--local',
+        :long => "--local",
         :boolean => true,
         :description => "Show local files instead of remote"
 
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 656baf5..728ee67 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,23 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/mixin/shell_out"
+require "chef/knife"
 
 class Chef
   class Knife
     class Ssh < Knife
 
       deps do
-        require 'net/ssh'
-        require 'net/ssh/multi'
-        require 'chef/monkey_patches/net-ssh-multi'
-        require 'readline'
-        require 'chef/exceptions'
-        require 'chef/search/query'
-        require 'chef/mixin/shell_out'
-        require 'chef/mixin/command'
-        require 'chef/util/path_helper'
-        require 'mixlib/shellout'
+        require "net/ssh"
+        require "net/ssh/multi"
+        require "chef/monkey_patches/net-ssh-multi"
+        require "readline"
+        require "chef/exceptions"
+        require "chef/search/query"
+        require "chef/mixin/command"
+        require "chef/util/path_helper"
+        require "mixlib/shellout"
       end
 
       include Chef::Mixin::ShellOut
@@ -72,7 +72,7 @@ class Chef
         :description => "The ssh password - will prompt if flag is specified but no password is given",
         # default to a value that can not be a password (boolean)
         # so we can effectively test if this parameter was specified
-        # without a vlaue
+        # without a value
         :default => false
 
       option :ssh_port,
@@ -94,8 +94,12 @@ class Chef
         :boolean => true
 
       option :identity_file,
-        :short => "-i IDENTITY_FILE",
         :long => "--identity-file IDENTITY_FILE",
+        :description => "The SSH identity file used for authentication. [DEPRECATED] Use --ssh-identity-file instead."
+
+      option :ssh_identity_file,
+        :short => "-i IDENTITY_FILE",
+        :long => "--ssh-identity-file IDENTITY_FILE",
         :description => "The SSH identity file used for authentication"
 
       option :host_key_verify,
@@ -105,12 +109,18 @@ class Chef
         :default => true
 
       option :on_error,
-        :short => '-e',
-        :long => '--exit-on-error',
+        :short => "-e",
+        :long => "--exit-on-error",
         :description => "Immediately exit if an error is encountered",
         :boolean => true,
         :proc => Proc.new { :raise }
 
+      option :tmux_split,
+        :long => "--tmux-split",
+        :description => "Split tmux window.",
+        :boolean => true,
+        :default => false
+
       def session
         config[:on_error] ||= :skip
         ssh_error_handler = Proc.new do |server|
@@ -130,17 +140,21 @@ class Chef
       def configure_gateway
         config[:ssh_gateway] ||= Chef::Config[:knife][:ssh_gateway]
         if config[:ssh_gateway]
-          gw_host, gw_user = config[:ssh_gateway].split('@').reverse
-          gw_host, gw_port = gw_host.split(':')
-          gw_opts = gw_port ? { :port => gw_port } : {}
+          gw_host, gw_user = config[:ssh_gateway].split("@").reverse
+          gw_host, gw_port = gw_host.split(":")
+          gw_opts = session_options(gw_host, gw_port, gw_user)
+          user = gw_opts.delete(:user)
 
-          session.via(gw_host, gw_user || config[:ssh_user], gw_opts)
+          begin
+            # Try to connect with a key.
+            session.via(gw_host, user, gw_opts)
+          rescue Net::SSH::AuthenticationFailed
+            prompt = "Enter the password for #{user}@#{gw_host}: "
+            gw_opts[:password] = prompt_for_password(prompt)
+            # Try again with a password.
+            session.via(gw_host, user, gw_opts)
+          end
         end
-      rescue Net::SSH::AuthenticationFailed
-        user = gw_user || config[:ssh_user]
-        prompt = "Enter the password for #{user}@#{gw_host}: "
-        gw_opts.merge!(:password => prompt_for_password(prompt))
-        session.via(gw_host, user, gw_opts)
       end
 
       def configure_session
@@ -151,7 +165,7 @@ class Chef
           if @action_nodes.length == 0
             ui.fatal("No nodes returned from search!")
           else
-            ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " +
+            ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes" : "node"} found, " +
                      "but does not have the required attribute to establish the connection. " +
                      "Try setting another attribute to open the connection using --attribute.")
           end
@@ -160,6 +174,31 @@ class Chef
         session_from_list(list)
       end
 
+      def get_ssh_attribute(node)
+        # Order of precedence for ssh target
+        # 1) command line attribute
+        # 2) configuration file
+        # 3) cloud attribute
+        # 4) fqdn
+        if config[:attribute]
+          Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target")
+          attribute = config[:attribute]
+        elsif Chef::Config[:knife][:ssh_attribute]
+          Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}")
+          attribute = Chef::Config[:knife][:ssh_attribute]
+        elsif node[:cloud] &&
+              node[:cloud][:public_hostname] &&
+              !node[:cloud][:public_hostname].empty?
+          Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target")
+          attribute = "cloud.public_hostname"
+        else
+          # falling back to default of fqdn
+          Chef::Log.debug("Using node attribute 'fqdn' as the ssh target")
+          attribute = "fqdn"
+        end
+        attribute
+      end
+
       def search_nodes
         list = Array.new
         query = Chef::Search::Query.new
@@ -168,25 +207,9 @@ class Chef
           # we should skip the loop to next iteration if the item
           # returned by the search is nil
           next if item.nil?
-          # if a command line attribute was not passed, and we have a
-          # cloud public_hostname, use that.  see #configure_attribute
-          # for the source of config[:attribute] and
-          # config[:attribute_from_cli]
-          if config[:attribute_from_cli]
-            Chef::Log.debug("Using node attribute '#{config[:attribute_from_cli]}' from the command line as the ssh target")
-            host = extract_nested_value(item, config[:attribute_from_cli])
-          elsif item[:cloud] &&
-                item[:cloud][:public_hostname] &&
-                !item[:cloud][:public_hostname].empty?
-            Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target")
-            host = item[:cloud][:public_hostname]
-          else
-            # ssh attribute from a configuration file or the default will land here
-            Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target")
-            host = extract_nested_value(item, config[:attribute])
-          end
           # next if we couldn't find the specified attribute in the
           # returned node object
+          host = extract_nested_value(item, get_ssh_attribute(item))
           next if host.nil?
           ssh_port = item[:cloud].nil? ? nil : item[:cloud][:public_ssh_port]
           srv = [host, ssh_port]
@@ -195,32 +218,50 @@ class Chef
         list
       end
 
-      def session_from_list(list)
-        list.each do |item|
-          host, ssh_port = item
-          Chef::Log.debug("Adding #{host}")
-          session_opts = {}
-
-          ssh_config = Net::SSH.configuration_for(host)
-
+      # Net::SSH session options hash for global options. These should be
+      # options that will apply to the gateway connection in addition to the
+      # main one.
+      #
+      # @since 12.5.0
+      # @param host [String] Hostname for this session.
+      # @param port [String] SSH port for this session.
+      # @param user [String] Optional username for this session.
+      # @return [Hash<Symbol, Object>]
+      def session_options(host, port, user = nil)
+        ssh_config = Net::SSH.configuration_for(host)
+        {}.tap do |opts|
           # Chef::Config[:knife][:ssh_user] is parsed in #configure_user and written to config[:ssh_user]
-          user = config[:ssh_user] || ssh_config[:user]
-          hostspec = user ? "#{user}@#{host}" : host
-          session_opts[:keys] = File.expand_path(config[:identity_file]) if config[:identity_file]
-          session_opts[:keys_only] = true if config[:identity_file]
-          session_opts[:password] = config[:ssh_password] if config[:ssh_password]
-          session_opts[:forward_agent] = config[:forward_agent]
-          session_opts[:port] = config[:ssh_port] ||
-                                ssh_port || # Use cloud port if available
-                                Chef::Config[:knife][:ssh_port] ||
-                                ssh_config[:port]
-          session_opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
-
+          opts[:user] = user || config[:ssh_user] || ssh_config[:user]
+          if config[:ssh_identity_file]
+            opts[:keys] = File.expand_path(config[:ssh_identity_file])
+            opts[:keys_only] = true
+          elsif config[:ssh_password]
+            opts[:password] = config[:ssh_password]
+          end
+          # Don't set the keys to nil if we don't have them.
+          forward_agent = config[:forward_agent] || ssh_config[:forward_agent]
+          opts[:forward_agent] = forward_agent unless forward_agent.nil?
+          port ||= ssh_config[:port]
+          opts[:port] = port unless port.nil?
+          opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
           if !config[:host_key_verify]
-            session_opts[:paranoid] = false
-            session_opts[:user_known_hosts_file] = "/dev/null"
+            opts[:paranoid] = false
+            opts[:user_known_hosts_file] = "/dev/null"
           end
+        end
+      end
 
+      def session_from_list(list)
+        list.each do |item|
+          host, ssh_port = item
+          Chef::Log.debug("Adding #{host}")
+          session_opts = session_options(host, ssh_port)
+          # Handle port overrides for the main connection.
+          session_opts[:port] = Chef::Config[:knife][:ssh_port] if Chef::Config[:knife][:ssh_port]
+          session_opts[:port] = config[:ssh_port] if config[:ssh_port]
+          # Create the hostspec.
+          hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host
+          # Connect a new session on the multi.
           session.use(hostspec, session_opts)
 
           @longest = host.length if host.length > @longest
@@ -256,11 +297,11 @@ class Chef
         ui.msg(str)
       end
 
-      def ssh_command(command, subsession=nil)
+      def ssh_command(command, subsession = nil)
         exit_status = 0
         subsession ||= session
         command = fixup_sudo(command)
-        command.force_encoding('binary') if command.respond_to?(:force_encoding)
+        command.force_encoding("binary") if command.respond_to?(:force_encoding)
         subsession.open_channel do |ch|
           ch.request_pty
           ch.exec command do |ch, success|
@@ -326,8 +367,8 @@ class Chef
         loop do
           command = read_line
           case command
-          when 'quit!'
-            puts 'Bye!'
+          when "quit!"
+            puts "Bye!"
             break
           when /^on (.+?); (.+)$/
             raw_list = $1.split(" ")
@@ -345,7 +386,7 @@ class Chef
 
       def screen
         tf = Tempfile.new("knife-ssh-screen")
-        Chef::Util::PathHelper.home('.screenrc') do |screenrc_path|
+        Chef::Util::PathHelper.home(".screenrc") do |screenrc_path|
           if File.exist? screenrc_path
             tf.puts("source #{screenrc_path}")
           end
@@ -355,7 +396,7 @@ class Chef
         window = 0
         session.servers_for.each do |server|
           tf.print("screen -t \"#{server.host}\" #{window} ssh ")
-          tf.print("-i #{config[:identity_file]} ") if config[:identity_file]
+          tf.print("-i #{config[:ssh_identity_file]} ") if config[:ssh_identity_file]
           server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host)
           window += 1
         end
@@ -365,7 +406,7 @@ class Chef
 
       def tmux
         ssh_dest = lambda do |server|
-          identity = "-i #{config[:identity_file]} " if config[:identity_file]
+          identity = "-i #{config[:ssh_identity_file]} " if config[:ssh_identity_file]
           prefix = server.user ? "#{server.user}@" : ""
           "'ssh #{identity}#{prefix}#{server.host}'"
         end
@@ -373,14 +414,18 @@ class Chef
         new_window_cmds = lambda do
           if session.servers_for.size > 1
             [""] + session.servers_for[1..-1].map do |server|
-              "new-window -a -n '#{server.host}' #{ssh_dest.call(server)}"
+              if config[:tmux_split]
+                "split-window #{ssh_dest.call(server)}; tmux select-layout tiled"
+              else
+                "new-window -a -n '#{server.host}' #{ssh_dest.call(server)}"
+              end
             end
           else
             []
           end.join(" \\; ")
         end
 
-        tmux_name = "'knife ssh #{@name_args[0].gsub(/:/,'=')}'"
+        tmux_name = "'knife ssh #{@name_args[0].gsub(/:/, '=')}'"
         begin
           server = session.servers_for.first
           cmd = ["tmux new-session -d -s #{tmux_name}",
@@ -394,41 +439,31 @@ class Chef
 
       def macterm
         begin
-          require 'appscript'
+          require "appscript"
         rescue LoadError
-          STDERR.puts "you need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install"
+          STDERR.puts "You need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install"
           raise
         end
 
         Appscript.app("/Applications/Utilities/Terminal.app").windows.first.activate
-        Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", :using=>:command_down)
-        term = Appscript.app('Terminal')
+        Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", :using => :command_down)
+        term = Appscript.app("Terminal")
         window = term.windows.first.get
 
         (session.servers_for.size - 1).times do |i|
           window.activate
-          Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", :using=>:command_down)
+          Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", :using => :command_down)
         end
 
         session.servers_for.each_with_index do |server, tab_number|
           cmd = "unset PROMPT_COMMAND; echo -e \"\\033]0;#{server.host}\\007\"; ssh #{server.user ? "#{server.user}@#{server.host}" : server.host}"
-          Appscript.app('Terminal').do_script(cmd, :in => window.tabs[tab_number + 1].get)
+          Appscript.app("Terminal").do_script(cmd, :in => window.tabs[tab_number + 1].get)
         end
       end
 
-      def configure_attribute
-        # Setting 'knife[:ssh_attribute] = "foo"' in knife.rb => Chef::Config[:knife][:ssh_attribute] == 'foo'
-        # Running 'knife ssh -a foo' => both Chef::Config[:knife][:ssh_attribute] && config[:attribute] == foo
-        # Thus we can differentiate between a config file value and a command line override at this point by checking config[:attribute]
-        # We can tell here if fqdn was passed from the command line, rather than being the default, by checking config[:attribute]
-        # However, after here, we cannot tell these things, so we must preserve config[:attribute]
-        config[:attribute_from_cli] = config[:attribute]
-        config[:attribute] = (config[:attribute_from_cli] || Chef::Config[:knife][:ssh_attribute] || "fqdn").strip
-      end
-
       def cssh
         cssh_cmd = nil
-        %w[csshX cssh].each do |cmd|
+        %w{csshX cssh}.each do |cmd|
           begin
             # Unix and Mac only
             cssh_cmd = shell_out!("which #{cmd}").stdout.strip
@@ -438,15 +473,15 @@ class Chef
         end
         raise Chef::Exceptions::Exec, "no command found for cssh" unless cssh_cmd
 
-        # pass in the consolidated itentity file option to cssh(X)
-        if config[:identity_file]
-          cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:identity_file])}'"
+        # pass in the consolidated identity file option to cssh(X)
+        if config[:ssh_identity_file]
+          cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:ssh_identity_file])}'"
         end
 
         session.servers_for.each do |server|
           cssh_cmd << " #{server.user ? "#{server.user}@#{server.host}" : server.host}"
         end
-        Chef::Log.debug("starting cssh session with command: #{cssh_cmd}")
+        Chef::Log.debug("Starting cssh session with command: #{cssh_cmd}")
         exec(cssh_cmd)
       end
 
@@ -485,9 +520,9 @@ class Chef
         end
       end
 
-      def configure_identity_file
-        config[:identity_file] = get_stripped_unfrozen_value(config[:identity_file] ||
-                             Chef::Config[:knife][:ssh_identity_file])
+      def configure_ssh_identity_file
+        # config[:identity_file] is DEPRECATED in favor of :ssh_identity_file
+        config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || config[:identity_file] || Chef::Config[:knife][:ssh_identity_file])
       end
 
       def extract_nested_value(data_structure, path_spec)
@@ -499,10 +534,9 @@ class Chef
 
         @longest = 0
 
-        configure_attribute
         configure_user
         configure_password
-        configure_identity_file
+        configure_ssh_identity_file
         configure_gateway
         configure_session
 
diff --git a/lib/chef/knife/ssl_check.rb b/lib/chef/knife/ssl_check.rb
index c5fe4fc..6dac06b 100644
--- a/lib/chef/knife/ssl_check.rb
+++ b/lib/chef/knife/ssl_check.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,21 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/config'
+require "chef/knife"
+require "chef/config"
 
 class Chef
   class Knife
     class SslCheck < Chef::Knife
 
       deps do
-        require 'pp'
-        require 'socket'
-        require 'uri'
-        require 'chef/http/ssl_policies'
-        require 'openssl'
+        require "pp"
+        require "socket"
+        require "uri"
+        require "chef/http/ssl_policies"
+        require "openssl"
+        require "chef/mixin/proxified_socket"
+        include Chef::Mixin::ProxifiedSocket
       end
 
       banner "knife ssl check [URL] (options)"
@@ -73,11 +75,12 @@ class Chef
         exit 1
       end
 
-
       def verify_peer_socket
         @verify_peer_socket ||= begin
-          tcp_connection = TCPSocket.new(host, port)
-          OpenSSL::SSL::SSLSocket.new(tcp_connection, verify_peer_ssl_context)
+          tcp_connection = proxified_socket(host, port)
+          ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_connection, verify_peer_ssl_context)
+          ssl_client.hostname = host
+          ssl_client
         end
       end
 
@@ -92,7 +95,7 @@ class Chef
 
       def noverify_socket
         @noverify_socket ||= begin
-          tcp_connection = TCPSocket.new(host, port)
+          tcp_connection = proxified_socket(host, port)
           OpenSSL::SSL::SSLSocket.new(tcp_connection, noverify_peer_ssl_context)
         end
       end
@@ -203,7 +206,7 @@ ADVICE
       def debug_invalid_host
         noverify_socket.connect
         subject = noverify_socket.peer_cert.subject
-        cn_field_tuple = subject.to_a.find {|field| field[0] == "CN" }
+        cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
         cn = cn_field_tuple[1]
 
         ui.error("You are attempting to connect to:   '#{host}'")
@@ -250,6 +253,7 @@ ADVICE
       end
 
       private
+
       def trusted_certificates
         if configuration.trusted_certs_dir && Dir.exist?(configuration.trusted_certs_dir)
           Dir.glob(File.join(configuration.trusted_certs_dir, "*.{crt,pem}"))
diff --git a/lib/chef/knife/ssl_fetch.rb b/lib/chef/knife/ssl_fetch.rb
index fd7d101..f694a46 100644
--- a/lib/chef/knife/ssl_fetch.rb
+++ b/lib/chef/knife/ssl_fetch.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,20 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/config'
+require "chef/knife"
+require "chef/config"
 
 class Chef
   class Knife
     class SslFetch < Chef::Knife
 
       deps do
-        require 'pp'
-        require 'socket'
-        require 'uri'
-        require 'openssl'
+        require "pp"
+        require "socket"
+        require "uri"
+        require "openssl"
+        require "chef/mixin/proxified_socket"
+        include Chef::Mixin::ProxifiedSocket
       end
 
       banner "knife ssl fetch [URL] (options)"
@@ -71,7 +73,7 @@ class Chef
       end
 
       def remote_cert_chain
-        tcp_connection = TCPSocket.new(host, port)
+        tcp_connection = proxified_socket(host, port)
         shady_ssl_connection = OpenSSL::SSL::SSLSocket.new(tcp_connection, noverify_peer_ssl_context)
         shady_ssl_connection.connect
         shady_ssl_connection.peer_cert_chain
@@ -85,10 +87,9 @@ class Chef
         end
       end
 
-
       def cn_of(certificate)
         subject = certificate.subject
-        cn_field_tuple = subject.to_a.find {|field| field[0] == "CN" }
+        cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
         cn_field_tuple[1]
       end
 
@@ -102,7 +103,7 @@ class Chef
       # practice.
       # https://tools.ietf.org/html/rfc6125#section-6.4.2
       def normalize_cn(cn)
-        cn.gsub("*", "wildcard").gsub(/[^[:alnum:]\-]/, '_')
+        cn.gsub("*", "wildcard").gsub(/[^[:alnum:]\-]/, "_")
       end
 
       def configuration
@@ -118,7 +119,7 @@ class Chef
         cn = cn_of(cert)
         filename = File.join(trusted_certs_dir, "#{normalize_cn(cn)}.crt")
         ui.msg("Adding certificate for #{cn} in #{filename}")
-        File.open(filename, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f|
+        File.open(filename, File::CREAT | File::TRUNC | File::RDWR, 0644) do |f|
           f.print(cert.to_s)
         end
       end
@@ -145,14 +146,12 @@ TRUST_TRUST
         ui.error("The service at the given URI (#{uri}) does not accept SSL connections")
 
         if uri.scheme == "http"
-          https_uri = uri.to_s.sub(/^http/, 'https')
+          https_uri = uri.to_s.sub(/^http/, "https")
           ui.error("Perhaps you meant to connect to '#{https_uri}'?")
         end
         exit 1
       end
 
-
     end
   end
 end
-
diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb
index 95f2c72..7bf9abb 100644
--- a/lib/chef/knife/status.rb
+++ b/lib/chef/knife/status.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Ian Meyer (<ianmmeyer at gmail.com>)
-# Copyright:: Copyright (c) 2010 Ian Meyer
+# Copyright:: Copyright 2010-2016, Ian Meyer
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/knife/core/status_presenter'
-require 'chef/knife/core/node_presenter'
+require "chef/knife"
+require "chef/knife/core/status_presenter"
+require "chef/knife/core/node_presenter"
 
 class Chef
   class Knife
@@ -26,7 +26,7 @@ class Chef
       include Knife::Core::NodeFormattingOptions
 
       deps do
-        require 'chef/search/query'
+        require "chef/search/query"
       end
 
       banner "knife status QUERY (options)"
@@ -44,7 +44,11 @@ class Chef
       option :hide_healthy,
         :short => "-H",
         :long => "--hide-healthy",
-        :description => "Hide nodes that have run chef in the last hour"
+        :description => "Hide nodes that have run chef in the last hour. [DEPRECATED] Use --hide-by-mins MINS instead"
+
+      option :hide_by_mins,
+        :long => "--hide-by-mins MINS",
+        :description => "Hide nodes that have run chef in the last MINS minutes"
 
       def append_to_query(term)
         @query << " AND " unless @query.empty?
@@ -57,10 +61,10 @@ class Chef
         if config[:long_output]
           opts = {}
         else
-          opts = {filter_result:
+          opts = { filter_result:
                  { name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
-                  ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
-                  platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}
+                   ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
+                   platform_version: ["platform_version"], chef_environment: ["chef_environment"] } }
         end
 
         @query ||= ""
@@ -68,10 +72,19 @@ class Chef
         append_to_query("chef_environment:#{config[:environment]}") if config[:environment]
 
         if config[:hide_healthy]
+          ui.warn("-H / --hide-healthy is deprecated. Use --hide-by-mins MINS instead")
+          time = Time.now.to_i
+          # AND NOT is not valid lucene syntax, so don't use append_to_query
+          @query << " " unless @query.empty?
+          @query << "NOT ohai_time:[#{(time - 60 * 60)} TO #{time}]"
+        end
+
+        if config[:hide_by_mins]
+          hidemins = config[:hide_by_mins].to_i
           time = Time.now.to_i
           # AND NOT is not valid lucene syntax, so don't use append_to_query
           @query << " " unless @query.empty?
-          @query << "NOT ohai_time:[#{(time - 60*60).to_s} TO #{time.to_s}]"
+          @query << "NOT ohai_time:[#{(time - hidemins * 60)} TO #{time}]"
         end
 
         @query = @query.empty? ? "*:*" : @query
diff --git a/lib/chef/knife/tag_create.rb b/lib/chef/knife/tag_create.rb
index d3ca952..e8cfe11 100644
--- a/lib/chef/knife/tag_create.rb
+++ b/lib/chef/knife/tag_create.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Ryan Davis (<ryand-ruby at zenspider.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class TagCreate < Knife
 
       deps do
-        require 'chef/node'
+        require "chef/node"
       end
 
       banner "knife tag create NODE TAG ..."
diff --git a/lib/chef/knife/tag_delete.rb b/lib/chef/knife/tag_delete.rb
index 10751db..d00ec2f 100644
--- a/lib/chef/knife/tag_delete.rb
+++ b/lib/chef/knife/tag_delete.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Ryan Davis (<ryand-ruby at zenspider.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class TagDelete < Knife
 
       deps do
-        require 'chef/node'
+        require "chef/node"
       end
 
       banner "knife tag delete NODE TAG ..."
diff --git a/lib/chef/knife/tag_list.rb b/lib/chef/knife/tag_list.rb
index 499eb85..2665e53 100644
--- a/lib/chef/knife/tag_list.rb
+++ b/lib/chef/knife/tag_list.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Ryan Davis (<ryand-ruby at zenspider.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2011-2016, Ryan Davis and Opscode, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class TagList < Knife
 
       deps do
-        require 'chef/node'
+        require "chef/node"
       end
 
       banner "knife tag list NODE"
diff --git a/lib/chef/knife/upload.rb b/lib/chef/knife/upload.rb
index 8abd22b..d0bf89f 100644
--- a/lib/chef/knife/upload.rb
+++ b/lib/chef/knife/upload.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,45 +8,45 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/command_line'
+        require "chef/chef_fs/command_line"
       end
 
       option :recurse,
-        :long => '--[no-]recurse',
+        :long => "--[no-]recurse",
         :boolean => true,
         :default => true,
         :description => "List directories recursively."
 
       option :purge,
-        :long => '--[no-]purge',
+        :long => "--[no-]purge",
         :boolean => true,
         :default => false,
         :description => "Delete matching local files and directories that do not exist remotely."
 
       option :force,
-        :long => '--[no-]force',
+        :long => "--[no-]force",
         :boolean => true,
         :default => false,
         :description => "Force upload of files even if they match (quicker for many files).  Will overwrite frozen cookbooks."
 
       option :freeze,
-        :long => '--[no-]freeze',
+        :long => "--[no-]freeze",
         :boolean => true,
         :default => false,
         :description => "Freeze cookbooks that get uploaded."
 
       option :dry_run,
-        :long => '--dry-run',
-        :short => '-n',
+        :long => "--dry-run",
+        :short => "-n",
         :boolean => true,
         :default => false,
         :description => "Don't take action, only print what would happen"
 
       option :diff,
-        :long => '--[no-]diff',
+        :long => "--[no-]diff",
         :boolean => true,
         :default => true,
-        :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff'
+        :description => "Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff"
 
       def run
         if name_args.length == 0
@@ -68,4 +68,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/knife/user_create.rb b/lib/chef/knife/user_create.rb
index 4130f06..5a9589a 100644
--- a/lib/chef/knife/user_create.rb
+++ b/lib/chef/knife/user_create.rb
@@ -1,6 +1,7 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,75 +17,131 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
+require "chef/knife/osc_user_create"
 
 class Chef
   class Knife
     class UserCreate < Knife
 
+      attr_accessor :user_field
+
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       option :file,
         :short => "-f FILE",
         :long  => "--file FILE",
-        :description => "Write the private key to a file"
+        :description => "Write the private key to a file if the server generated one."
+
+      option :user_key,
+        :long => "--user-key FILENAME",
+        :description =>  "Set the initial default key for the user from a file on disk (cannot pass with --prevent-keygen)."
+
+      option :prevent_keygen,
+        :short => "-k",
+        :long  => "--prevent-keygen",
+        :description => "API V1 only. Prevent server from generating a default key pair for you. Cannot be passed with --user-key.",
+        :boolean => true
 
       option :admin,
         :short => "-a",
         :long  => "--admin",
-        :description => "Create the user as an admin",
+        :description => "DEPRECATED: Open Source Chef 11 only. Create the user as an admin.",
         :boolean => true
 
       option :user_password,
         :short => "-p PASSWORD",
         :long => "--password PASSWORD",
-        :description => "Password for newly created user",
+        :description => "DEPRECATED: Open Source Chef 11 only. Password for newly created user.",
         :default => ""
 
-      option :user_key,
-        :long => "--user-key FILENAME",
-        :description => "Public key for newly created user.  By default a key will be created for you."
+      banner "knife user create USERNAME DISPLAY_NAME FIRST_NAME LAST_NAME EMAIL PASSWORD (options)"
+
+      def user
+        @user_field ||= Chef::UserV1.new
+      end
+
+      def create_user_from_hash(hash)
+        Chef::UserV1.from_hash(hash).create
+      end
+
+      def osc_11_warning
+        <<-EOF
+IF YOU ARE USING CHEF SERVER 12+, PLEASE FOLLOW THE INSTRUCTIONS UNDER knife user create --help.
+You only passed a single argument to knife user create.
+For backwards compatibility, when only a single argument is passed,
+knife user create assumes you want Open Source 11 Server user creation.
+knife user create for Open Source 11 Server is being deprecated.
+Open Source 11 Server user commands now live under the knife osc_user namespace.
+For backwards compatibility, we will forward this request to knife osc_user create.
+If you are using an Open Source 11 Server, please use that command to avoid this warning.
+EOF
+      end
 
-      banner "knife user create USER (options)"
+      def run_osc_11_user_create
+        # run osc_user_create with our input
+        ARGV.delete("user")
+        ARGV.unshift("osc_user")
+        Chef::Knife.run(ARGV, Chef::Application::Knife.options)
+      end
 
       def run
-        @user_name = @name_args[0]
+        # DEPRECATION NOTE
+        # Remove this if statement and corrosponding code post OSC 11 support.
+        #
+        # If only 1 arg is passed, assume OSC 11 case.
+        if @name_args.length == 1
+          ui.warn(osc_11_warning)
+          run_osc_11_user_create
+        else # EC / CS 12 user create
 
-        if @user_name.nil?
-          show_usage
-          ui.fatal("You must specify a user name")
-          exit 1
-        end
+          test_mandatory_field(@name_args[0], "username")
+          user.username @name_args[0]
 
-        if config[:user_password].length == 0
-          show_usage
-          ui.fatal("You must specify a non-blank password")
-          exit 1
-        end
+          test_mandatory_field(@name_args[1], "display name")
+          user.display_name @name_args[1]
 
-        user = Chef::User.new
-        user.name(@user_name)
-        user.admin(config[:admin])
-        user.password config[:user_password]
+          test_mandatory_field(@name_args[2], "first name")
+          user.first_name @name_args[2]
 
-        if config[:user_key]
-          user.public_key File.read(File.expand_path(config[:user_key]))
-        end
+          test_mandatory_field(@name_args[3], "last name")
+          user.last_name @name_args[3]
+
+          test_mandatory_field(@name_args[4], "email")
+          user.email @name_args[4]
+
+          test_mandatory_field(@name_args[5], "password")
+          user.password @name_args[5]
+
+          if config[:user_key] && config[:prevent_keygen]
+            show_usage
+            ui.fatal("You cannot pass --user-key and --prevent-keygen")
+            exit 1
+          end
+
+          if !config[:prevent_keygen] && !config[:user_key]
+            user.create_key(true)
+          end
+
+          if config[:user_key]
+            user.public_key File.read(File.expand_path(config[:user_key]))
+          end
 
-        output = edit_data(user)
-        user = Chef::User.from_hash(output).create
+          output = edit_data(user)
+          final_user = create_user_from_hash(output)
 
-        ui.info("Created #{user}")
-        if user.private_key
-          if config[:file]
-            File.open(config[:file], "w") do |f|
-              f.print(user.private_key)
+          ui.info("Created #{user}")
+          if final_user.private_key
+            if config[:file]
+              File.open(config[:file], "w") do |f|
+                f.print(final_user.private_key)
+              end
+            else
+              ui.msg final_user.private_key
             end
-          else
-            ui.msg user.private_key
           end
         end
       end
diff --git a/lib/chef/knife/user_delete.rb b/lib/chef/knife/user_delete.rb
index b7af11b..ce4575c 100644
--- a/lib/chef/knife/user_delete.rb
+++ b/lib/chef/knife/user_delete.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,53 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class UserDelete < Knife
 
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       banner "knife user delete USER (options)"
 
+      def osc_11_warning
+        <<-EOF
+The Chef Server you are using does not support the username field.
+This means it is an Open Source 11 Server.
+knife user delete for Open Source 11 Server is being deprecated.
+Open Source 11 Server user commands now live under the knife osc_user namespace.
+For backwards compatibility, we will forward this request to knife osc_user delete.
+If you are using an Open Source 11 Server, please use that command to avoid this warning.
+EOF
+      end
+
+      def run_osc_11_user_delete
+        # run osc_user_delete with our input
+        ARGV.delete("user")
+        ARGV.unshift("osc_user")
+        Chef::Knife.run(ARGV, Chef::Application::Knife.options)
+      end
+
+      # DEPRECATION NOTE
+      # Delete this override method after OSC 11 support is dropped
+      def delete_object(user_name)
+        confirm("Do you really want to delete #{user_name}")
+
+        if Kernel.block_given?
+          object = block.call
+        else
+          object = Chef::UserV1.load(user_name)
+          object.destroy
+        end
+
+        output(format_for_display(object)) if config[:print_after]
+        self.msg("Deleted #{user_name}")
+      end
+
       def run
         @user_name = @name_args[0]
 
@@ -38,9 +72,24 @@ class Chef
           exit 1
         end
 
-        delete_object(Chef::User, @user_name)
-      end
+        # DEPRECATION NOTE
+        #
+        # Below is modification of Chef::Knife.delete_object to detect OSC 11 server.
+        # When OSC 11 is deprecated, simply delete all this and go back to:
+        #
+        # delete_object(Chef::UserV1, @user_name)
+        #
+        # Also delete our override of delete_object above
+        object = Chef::UserV1.load(@user_name)
 
+        # OSC 11 case
+        if object.username.nil?
+          ui.warn(osc_11_warning)
+          run_osc_11_user_delete
+        else # proceed with EC / CS delete
+          delete_object(@user_name)
+        end
+      end
     end
   end
 end
diff --git a/lib/chef/knife/user_edit.rb b/lib/chef/knife/user_edit.rb
index ae319c8..9564a31 100644
--- a/lib/chef/knife/user_edit.rb
+++ b/lib/chef/knife/user_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,37 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class UserEdit < Knife
 
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       banner "knife user edit USER (options)"
 
+      def osc_11_warning
+        <<-EOF
+The Chef Server you are using does not support the username field.
+This means it is an Open Source 11 Server.
+knife user edit for Open Source 11 Server is being deprecated.
+Open Source 11 Server user commands now live under the knife oc_user namespace.
+For backwards compatibility, we will forward this request to knife osc_user edit.
+If you are using an Open Source 11 Server, please use that command to avoid this warning.
+EOF
+      end
+
+      def run_osc_11_user_edit
+        # run osc_user_create with our input
+        ARGV.delete("user")
+        ARGV.unshift("osc_user")
+        Chef::Knife.run(ARGV, Chef::Application::Knife.options)
+      end
+
       def run
         @user_name = @name_args[0]
 
@@ -38,14 +56,24 @@ class Chef
           exit 1
         end
 
-        original_user = Chef::User.load(@user_name).to_hash
-        edited_user = edit_data(original_user)
-        if original_user != edited_user
-          user = Chef::User.from_hash(edited_user)
-          user.update
-          ui.msg("Saved #{user}.")
-        else
-          ui.msg("User unchaged, not saving.")
+        original_user = Chef::UserV1.load(@user_name).to_hash
+        # DEPRECATION NOTE
+        # Remove this if statement and corrosponding code post OSC 11 support.
+        #
+        # if username is nil, we are in the OSC 11 case,
+        # forward to deprecated command
+        if original_user["username"].nil?
+          ui.warn(osc_11_warning)
+          run_osc_11_user_edit
+        else # EC / CS 12 user create
+          edited_user = edit_data(original_user)
+          if original_user != edited_user
+            user = Chef::UserV1.from_hash(edited_user)
+            user.update
+            ui.msg("Saved #{user}.")
+          else
+            ui.msg("User unchanged, not saving.")
+          end
         end
       end
     end
diff --git a/lib/chef/knife/user_key_create.rb b/lib/chef/knife/user_key_create.rb
new file mode 100644
index 0000000..95a98a2
--- /dev/null
+++ b/lib/chef/knife/user_key_create.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_create_base"
+
+class Chef
+  class Knife
+    # Implements knife user key create using Chef::Knife::KeyCreate
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the user that this key is for
+    class UserKeyCreate < Knife
+      include Chef::Knife::KeyCreateBase
+
+      banner "knife user key create USER (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "user"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyCreate.new(@actor, actor_field_name, ui, config)
+      end
+
+      def actor_missing_error
+        "You must specify a user name"
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/user_key_delete.rb b/lib/chef/knife/user_key_delete.rb
new file mode 100644
index 0000000..1c559f2
--- /dev/null
+++ b/lib/chef/knife/user_key_delete.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+class Chef
+  class Knife
+    # Implements knife user key delete using Chef::Knife::KeyDelete
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class UserKeyDelete < Knife
+      banner "knife user key delete USER KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "user"
+      end
+
+      def actor_missing_error
+        "You must specify a user name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyDelete.new(@name, @actor, actor_field_name, ui)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/user_key_edit.rb b/lib/chef/knife/user_key_edit.rb
new file mode 100644
index 0000000..561af8e
--- /dev/null
+++ b/lib/chef/knife/user_key_edit.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_edit_base"
+
+class Chef
+  class Knife
+    # Implements knife user key edit using Chef::Knife::KeyEdit
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the user that this key is for
+    class UserKeyEdit < Knife
+      include Chef::Knife::KeyEditBase
+
+      banner "knife user key edit USER KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def actor_field_name
+        "user"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyEdit.new(@name, @actor, actor_field_name, ui, config)
+      end
+
+      def actor_missing_error
+        "You must specify a user name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/user_key_list.rb b/lib/chef/knife/user_key_list.rb
new file mode 100644
index 0000000..799c069
--- /dev/null
+++ b/lib/chef/knife/user_key_list.rb
@@ -0,0 +1,69 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/key_list_base"
+
+class Chef
+  class Knife
+    # Implements knife user key list using Chef::Knife::KeyList
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class UserKeyList < Knife
+      include Chef::Knife::KeyListBase
+
+      banner "knife user key list USER (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def list_method
+        :list_by_user
+      end
+
+      def actor_missing_error
+        "You must specify a user name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyList.new(@actor, list_method, ui, config)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/user_key_show.rb b/lib/chef/knife/user_key_show.rb
new file mode 100644
index 0000000..e09d5e0
--- /dev/null
+++ b/lib/chef/knife/user_key_show.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+class Chef
+  class Knife
+    # Implements knife user key show using Chef::Knife::KeyShow
+    # as a service class.
+    #
+    # @author Tyler Cloke
+    #
+    # @attr_reader [String] actor the name of the client that this key is for
+    class UserKeyShow < Knife
+      banner "knife user key show USER KEYNAME (options)"
+
+      attr_reader :actor
+
+      def initialize(argv = [])
+        super(argv)
+        @service_object = nil
+      end
+
+      def run
+        apply_params!(@name_args)
+        service_object.run
+      end
+
+      def load_method
+        :load_by_user
+      end
+
+      def actor_missing_error
+        "You must specify a user name"
+      end
+
+      def keyname_missing_error
+        "You must specify a key name"
+      end
+
+      def service_object
+        @service_object ||= Chef::Knife::KeyShow.new(@name, @actor, load_method, ui)
+      end
+
+      def apply_params!(params)
+        @actor = params[0]
+        if @actor.nil?
+          show_usage
+          ui.fatal(actor_missing_error)
+          exit 1
+        end
+        @name = params[1]
+        if @name.nil?
+          show_usage
+          ui.fatal(keyname_missing_error)
+          exit 1
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/knife/user_list.rb b/lib/chef/knife/user_list.rb
index 5d2e735..88e8340 100644
--- a/lib/chef/knife/user_list.rb
+++ b/lib/chef/knife/user_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,17 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
+# NOTE: only knife user command that is backwards compatible with OSC 11,
+# so no deprecation warnings are necessary.
 class Chef
   class Knife
     class UserList < Knife
 
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       banner "knife user list (options)"
@@ -35,8 +37,9 @@ class Chef
         :description => "Show corresponding URIs"
 
       def run
-        output(format_list_for_display(Chef::User.list))
+        output(format_list_for_display(Chef::UserV1.list))
       end
+
     end
   end
 end
diff --git a/lib/chef/knife/user_reregister.rb b/lib/chef/knife/user_reregister.rb
index 946150e..8d2f2c1 100644
--- a/lib/chef/knife/user_reregister.rb
+++ b/lib/chef/knife/user_reregister.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,37 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
     class UserReregister < Knife
 
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       banner "knife user reregister USER (options)"
 
+      def osc_11_warning
+        <<-EOF
+The Chef Server you are using does not support the username field.
+This means it is an Open Source 11 Server.
+knife user reregister for Open Source 11 Server is being deprecated.
+Open Source 11 Server user commands now live under the knife osc_user namespace.
+For backwards compatibility, we will forward this request to knife osc_user reregister.
+If you are using an Open Source 11 Server, please use that command to avoid this warning.
+EOF
+      end
+
+      def run_osc_11_user_reregister
+        # run osc_user_edit with our input
+        ARGV.delete("user")
+        ARGV.unshift("osc_user")
+        Chef::Knife.run(ARGV, Chef::Application::Knife.options)
+      end
+
       option :file,
         :short => "-f FILE",
         :long  => "--file FILE",
@@ -43,15 +61,27 @@ class Chef
           exit 1
         end
 
-        user = Chef::User.load(@user_name).reregister
-        Chef::Log.debug("Updated user data: #{user.inspect}")
-        key = user.private_key
-        if config[:file]
-          File.open(config[:file], "w") do |f|
-            f.print(key)
+        user = Chef::UserV1.load(@user_name)
+
+        # DEPRECATION NOTE
+        # Remove this if statement and corrosponding code post OSC 11 support.
+        #
+        # if username is nil, we are in the OSC 11 case,
+        # forward to deprecated command
+        if user.username.nil?
+          ui.warn(osc_11_warning)
+          run_osc_11_user_reregister
+        else # EC / CS 12 case
+          user.reregister
+          Chef::Log.debug("Updated user data: #{user.inspect}")
+          key = user.private_key
+          if config[:file]
+            File.open(config[:file], "w") do |f|
+              f.print(key)
+            end
+          else
+            ui.msg key
           end
-        else
-          ui.msg key
         end
       end
     end
diff --git a/lib/chef/knife/user_show.rb b/lib/chef/knife/user_show.rb
index 61ea101..04251c0 100644
--- a/lib/chef/knife/user_show.rb
+++ b/lib/chef/knife/user_show.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
+require "chef/knife"
 
 class Chef
   class Knife
@@ -25,12 +25,30 @@ class Chef
       include Knife::Core::MultiAttributeReturnOption
 
       deps do
-        require 'chef/user'
-        require 'chef/json_compat'
+        require "chef/user_v1"
+        require "chef/json_compat"
       end
 
       banner "knife user show USER (options)"
 
+      def osc_11_warning
+        <<-EOF
+The Chef Server you are using does not support the username field.
+This means it is an Open Source 11 Server.
+knife user show for Open Source 11 Server is being deprecated.
+Open Source 11 Server user commands now live under the knife osc_user namespace.
+For backwards compatibility, we will forward this request to knife osc_user show.
+If you are using an Open Source 11 Server, please use that command to avoid this warning.
+EOF
+      end
+
+      def run_osc_11_user_show
+        # run osc_user_edit with our input
+        ARGV.delete("user")
+        ARGV.unshift("osc_user")
+        Chef::Knife.run(ARGV, Chef::Application::Knife.options)
+      end
+
       def run
         @user_name = @name_args[0]
 
@@ -40,8 +58,19 @@ class Chef
           exit 1
         end
 
-        user = Chef::User.load(@user_name)
-        output(format_for_display(user))
+        user = Chef::UserV1.load(@user_name)
+
+        # DEPRECATION NOTE
+        # Remove this if statement and corrosponding code post OSC 11 support.
+        #
+        # if username is nil, we are in the OSC 11 case,
+        # forward to deprecated command
+        if user.username.nil?
+          ui.warn(osc_11_warning)
+          run_osc_11_user_show
+        else
+          output(format_for_display(user))
+        end
       end
 
     end
diff --git a/lib/chef/knife/xargs.rb b/lib/chef/knife/xargs.rb
index dd8e848..10e15a4 100644
--- a/lib/chef/knife/xargs.rb
+++ b/lib/chef/knife/xargs.rb
@@ -1,4 +1,4 @@
-require 'chef/chef_fs/knife'
+require "chef/chef_fs/knife"
 
 class Chef
   class Knife
@@ -8,65 +8,65 @@ class Chef
       category "path-based"
 
       deps do
-        require 'chef/chef_fs/file_system'
-        require 'chef/chef_fs/file_system/not_found_error'
+        require "chef/chef_fs/file_system"
+        require "chef/chef_fs/file_system/not_found_error"
       end
 
       # TODO modify to remote-only / local-only pattern (more like delete)
       option :local,
-        :long => '--local',
+        :long => "--local",
         :boolean => true,
         :description => "Xargs local files instead of remote"
 
       option :patterns,
-        :long => '--pattern [PATTERN]',
-        :short => '-p [PATTERN]',
+        :long => "--pattern [PATTERN]",
+        :short => "-p [PATTERN]",
         :description => "Pattern on command line (if these are not specified, a list of patterns is expected on standard input).  Multiple patterns may be passed in this way.",
-        :arg_arity => [1,-1]
+        :arg_arity => [1, -1]
 
       option :diff,
-        :long => '--[no-]diff',
+        :long => "--[no-]diff",
         :default => true,
         :boolean => true,
         :description => "Whether to show a diff when files change (default: true)"
 
       option :dry_run,
-        :long => '--dry-run',
+        :long => "--dry-run",
         :boolean => true,
         :description => "Prevents changes from actually being uploaded to the server."
 
       option :force,
-        :long => '--[no-]force',
+        :long => "--[no-]force",
         :boolean => true,
         :default => false,
         :description => "Force upload of files even if they are not changed (quicker and harmless, but doesn't print out what it changed)"
 
       option :replace_first,
-        :long => '--replace-first REPLACESTR',
-        :short => '-J REPLACESTR',
+        :long => "--replace-first REPLACESTR",
+        :short => "-J REPLACESTR",
         :description => "String to replace with filenames.  -J will only replace the FIRST occurrence of the replacement string."
 
       option :replace_all,
-        :long => '--replace REPLACESTR',
-        :short => '-I REPLACESTR',
+        :long => "--replace REPLACESTR",
+        :short => "-I REPLACESTR",
         :description => "String to replace with filenames.  -I will replace ALL occurrence of the replacement string."
 
       option :max_arguments_per_command,
-        :long => '--max-args MAXARGS',
-        :short => '-n MAXARGS',
+        :long => "--max-args MAXARGS",
+        :short => "-n MAXARGS",
         :description => "Maximum number of arguments per command line."
 
       option :max_command_line,
-        :long => '--max-chars LENGTH',
-        :short => '-s LENGTH',
+        :long => "--max-chars LENGTH",
+        :short => "-s LENGTH",
         :description => "Maximum size of command line, in characters"
 
       option :verbose_commands,
-        :short => '-t',
+        :short => "-t",
         :description => "Print command to be run on the command line"
 
       option :null_separator,
-        :short => '-0',
+        :short => "-0",
         :boolean => true,
         :description => "Use the NULL character (\0) as a separator, instead of whitespace"
 
@@ -151,7 +151,7 @@ class Chef
       end
 
       def create_command(files)
-        command = name_args.join(' ')
+        command = name_args.join(" ")
 
         # Create the (empty) tempfiles
         tempfiles = {}
@@ -167,7 +167,7 @@ class Chef
         end
 
         # Create the command
-        paths = tempfiles.keys.map { |tempfile| tempfile.path }.join(' ')
+        paths = tempfiles.keys.map { |tempfile| tempfile.path }.join(" ")
         if config[:replace_all]
           final_command = command.gsub(config[:replace_all], paths)
         elsif config[:replace_first]
@@ -264,4 +264,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/local_mode.rb b/lib/chef/local_mode.rb
index 79fb750..5ce17e6 100644
--- a/lib/chef/local_mode.rb
+++ b/lib/chef/local_mode.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at getchef.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,12 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-require 'chef/config'
+require "chef/config"
+if Chef::Platform.windows?
+  if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1")
+    require "chef/monkey_patches/webrick-utils"
+  end
+end
 
 class Chef
   module LocalMode
@@ -49,17 +54,19 @@ class Chef
       if Chef::Config.chef_zero.enabled
         destroy_server_connectivity
 
-        require 'chef_zero/server'
-        require 'chef/chef_fs/chef_fs_data_store'
-        require 'chef/chef_fs/config'
+        require "chef_zero/server"
+        require "chef/chef_fs/chef_fs_data_store"
+        require "chef/chef_fs/config"
 
         @chef_fs = Chef::ChefFS::Config.new.local_fs
         @chef_fs.write_pretty_json = true
         data_store = Chef::ChefFS::ChefFSDataStore.new(@chef_fs)
-        data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, 'chef')
+        data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, "chef")
         server_options = {}
         server_options[:data_store] = data_store
         server_options[:log_level] = Chef::Log.level
+        server_options[:osc_compat] = Chef::Config.chef_zero.osc_compat
+        server_options[:single_org] = Chef::Config.chef_zero.single_org
 
         server_options[:host] = Chef::Config.chef_zero.host
         server_options[:port] = parse_port(Chef::Config.chef_zero.port)
@@ -98,9 +105,9 @@ class Chef
 
     def self.parse_port(port)
       if port.is_a?(String)
-        parts = port.split(',')
+        parts = port.split(",")
         if parts.size == 1
-          a,b = parts[0].split('-',2)
+          a, b = parts[0].split("-", 2)
           if b
             a.to_i.upto(b.to_i)
           else
diff --git a/lib/chef/log.rb b/lib/chef/log.rb
index 682afce..8d4fed5 100644
--- a/lib/chef/log.rb
+++ b/lib/chef/log.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: AJ Christensen (<@aj at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Christopher Brown (<cb at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'logger'
-require 'chef/monologger'
-require 'chef/exceptions'
-require 'mixlib/log'
+require "logger"
+require "chef/monologger"
+require "chef/exceptions"
+require "mixlib/log"
+require "chef/log/syslog" unless (RUBY_PLATFORM =~ /mswin|mingw|windows/)
+require "chef/log/winevt"
 
 class Chef
   class Log
@@ -35,7 +37,25 @@ class Chef
       end
     end
 
-    def self.deprecation(msg=nil, &block)
+    #
+    # Get the location of the caller (from the recipe). Grabs the first caller
+    # that is *not* in the chef gem proper (allowing us to weed out internal
+    # calls and give the user a more useful perspective).
+    #
+    # @return [String] The location of the caller (file:line#) from caller(0..20), or nil if no non-chef caller is found.
+    #
+    def self.caller_location
+      # Pick the first caller that is *not* part of the Chef gem, that's the
+      # thing the user wrote.
+      chef_gem_path = File.expand_path("../..", __FILE__)
+      caller(0..20).select { |c| !c.start_with?(chef_gem_path) }.first
+    end
+
+    def self.deprecation(msg = nil, location = caller(2..2)[0], &block)
+      if msg
+        msg << " at #{Array(location).join("\n")}"
+        msg = msg.join("") if msg.respond_to?(:join)
+      end
       if Chef::Config[:treat_deprecation_warnings_as_errors]
         error(msg, &block)
         raise Chef::Exceptions::DeprecatedFeatureError.new(msg)
diff --git a/lib/chef/log/syslog.rb b/lib/chef/log/syslog.rb
new file mode 100644
index 0000000..58d6671
--- /dev/null
+++ b/lib/chef/log/syslog.rb
@@ -0,0 +1,45 @@
+#
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Author:: SAWANOBORI Yukihiko (<sawanoboriyu at higanworks.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "logger"
+require "syslog-logger"
+require "chef/mixin/unformatter"
+
+class Chef
+  class Log
+    #
+    # Chef::Log::Syslog class.
+    # usage in client.rb:
+    #  log_location Chef::Log::Syslog.new("chef-client", ::Syslog::LOG_DAEMON)
+    #
+    class Syslog < Logger::Syslog
+      include Chef::Mixin::Unformatter
+
+      attr_accessor :sync, :formatter
+
+      def initialize(program_name = "chef-client", facility = ::Syslog::LOG_DAEMON, logopts = nil)
+        super
+        return if defined? ::Logger::Syslog::SYSLOG
+        ::Logger::Syslog.const_set :SYSLOG, SYSLOG
+      end
+
+      def close
+      end
+    end
+  end
+end
diff --git a/lib/chef/log/winevt.rb b/lib/chef/log/winevt.rb
new file mode 100644
index 0000000..04e24e3
--- /dev/null
+++ b/lib/chef/log/winevt.rb
@@ -0,0 +1,99 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/event_loggers/base"
+require "chef/platform/query_helpers"
+require "chef/mixin/unformatter"
+
+class Chef
+  class Log
+    #
+    # Chef::Log::WinEvt class.
+    # usage in client.rb:
+    #  log_location Chef::Log::WinEvt.new
+    #
+    class WinEvt
+      # These must match those that are defined in the manifest file
+      INFO_EVENT_ID = 10100
+      WARN_EVENT_ID = 10101
+      DEBUG_EVENT_ID = 10102
+      ERROR_EVENT_ID = 10103
+      FATAL_EVENT_ID = 10104
+
+      # Since we must install the event logger, this is not really configurable
+      SOURCE = "Chef"
+
+      include Chef::Mixin::Unformatter
+
+      attr_accessor :sync, :formatter, :level
+
+      def initialize(eventlog = nil)
+        @eventlog = eventlog || ::Win32::EventLog::open("Application")
+      end
+
+      def close
+      end
+
+      def info(msg)
+        @eventlog.report_event(
+          :event_type => ::Win32::EventLog::INFO_TYPE,
+          :source => SOURCE,
+          :event_id => INFO_EVENT_ID,
+          :data => [msg],
+        )
+      end
+
+      def warn(msg)
+        @eventlog.report_event(
+          :event_type => ::Win32::EventLog::WARN_TYPE,
+          :source => SOURCE,
+          :event_id => WARN_EVENT_ID,
+          :data => [msg],
+        )
+      end
+
+      def debug(msg)
+        @eventlog.report_event(
+          :event_type => ::Win32::EventLog::INFO_TYPE,
+          :source => SOURCE,
+          :event_id => DEBUG_EVENT_ID,
+          :data => [msg],
+        )
+      end
+
+      def error(msg)
+        @eventlog.report_event(
+          :event_type => ::Win32::EventLog::ERROR_TYPE,
+          :source => SOURCE,
+          :event_id => ERROR_EVENT_ID,
+          :data => [msg],
+        )
+      end
+
+      def fatal(msg)
+        @eventlog.report_event(
+          :event_type => ::Win32::EventLog::ERROR_TYPE,
+          :source => SOURCE,
+          :event_id => FATAL_EVENT_ID,
+          :data => [msg],
+        )
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mash.rb b/lib/chef/mash.rb
index edd254c..3858ff0 100644
--- a/lib/chef/mash.rb
+++ b/lib/chef/mash.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 Dan Kubb
+# Copyright 2009-2016, Dan Kubb
 
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
@@ -25,7 +25,7 @@
 # Some portions of blank.rb and mash.rb are verbatim copies of software
 # licensed under the MIT license. That license is included below:
 
-# Copyright (c) 2005-2008 David Heinemeier Hansson
+# Copyright 2005-2016, David Heinemeier Hansson
 
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
@@ -71,7 +71,7 @@ class Mash < Hash
   def initialize_copy(orig)
     super
     # Handle nested values
-    each do |k,v|
+    each do |k, v|
       if v.kind_of?(Mash) || v.is_a?(Array)
         self[k] = v.dup
       end
@@ -142,7 +142,7 @@ class Mash < Hash
   #
   # @return [Array] The values at each of the provided keys
   def values_at(*indices)
-    indices.collect {|key| self[convert_key(key)]}
+    indices.collect { |key| self[convert_key(key)] }
   end
 
   # @param hash<Hash> The hash to merge with the mash.
@@ -166,7 +166,7 @@ class Mash < Hash
   #   { :one => 1, :two => 2, :three => 3 }.except(:one)
   #     #=> { "two" => 2, "three" => 3 }
   def except(*keys)
-    super(*keys.map {|k| convert_key(k)})
+    super(*keys.map { |k| convert_key(k) })
   end
 
   # Used to provide the same interface as Hash.
@@ -195,6 +195,7 @@ class Mash < Hash
   end
 
   protected
+
   # @param key<Object> The key to convert.
   #
   # @param [Object]
diff --git a/lib/chef/mixin/api_version_request_handling.rb b/lib/chef/mixin/api_version_request_handling.rb
new file mode 100644
index 0000000..b91a1df
--- /dev/null
+++ b/lib/chef/mixin/api_version_request_handling.rb
@@ -0,0 +1,66 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module Mixin
+    module ApiVersionRequestHandling
+      # Input:
+      # exeception:
+      #   Net::HTTPServerException that may or may not contain the x-ops-server-api-version header
+      # supported_client_versions:
+      #  An array of Integers that represent the API versions the client supports.
+      #
+      # Output:
+      # nil:
+      #  If the execption was not a 406 or the server does not support versioning
+      # Array of length zero:
+      #  If there was no intersection between supported client versions and supported server versions
+      # Arrary of Integers:
+      #  If there was an intersection of supported versions, the array returns will contain that intersection
+      def server_client_api_version_intersection(exception, supported_client_versions)
+        # return empty array unless 406 Unacceptable with proper header
+        return nil if exception.response.code != "406" || exception.response["x-ops-server-api-version"].nil?
+
+        # intersection of versions the server and client support, will be of length zero if no intersection
+        server_supported_client_versions = Array.new
+
+        header = Chef::JSONCompat.from_json(exception.response["x-ops-server-api-version"])
+        min_server_version = Integer(header["min_version"])
+        max_server_version = Integer(header["max_version"])
+
+        supported_client_versions.each do |version|
+          if version >= min_server_version && version <= max_server_version
+            server_supported_client_versions.push(version)
+          end
+        end
+        server_supported_client_versions
+      end
+
+      def reregister_only_v0_supported_error_msg(max_version, min_version)
+        <<-EOH
+The reregister command only supports server API version 0.
+The server that received the request supports a min version of #{min_version} and a max version of #{max_version}.
+User keys are now managed via the key rotation commmands.
+Please refer to the documentation on how to manage your keys via the key rotation commands:
+https://docs.chef.io/server_security.html#key-rotation
+EOH
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mixin/checksum.rb b/lib/chef/mixin/checksum.rb
index 1d9c99e..f223894 100644
--- a/lib/chef/mixin/checksum.rb
+++ b/lib/chef/mixin/checksum.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'digest/sha2'
-require 'chef/digester'
+require "digest/sha2"
+require "chef/digester"
 
 class Chef
   module Mixin
diff --git a/lib/chef/mixin/command.rb b/lib/chef/mixin/command.rb
index d9a9c4f..257ed11 100644
--- a/lib/chef/mixin/command.rb
+++ b/lib/chef/mixin/command.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/exceptions'
-require 'tmpdir'
-require 'fcntl'
-require 'etc'
+require "chef/log"
+require "chef/exceptions"
+require "tmpdir"
+require "fcntl"
+require "etc"
 
 class Chef
   module Mixin
@@ -50,11 +50,11 @@ class Chef
       # NOTE: run_command is deprecated in favor of using Chef::Shellout which now comes from the mixlib-shellout gem. NOTE #
 
       if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-        require 'chef/mixin/command/windows'
+        require "chef/mixin/command/windows"
         include ::Chef::Mixin::Command::Windows
         extend  ::Chef::Mixin::Command::Windows
       else
-        require 'chef/mixin/command/unix'
+        require "chef/mixin/command/unix"
         include ::Chef::Mixin::Command::Unix
         extend  ::Chef::Mixin::Command::Unix
       end
@@ -75,7 +75,7 @@ class Chef
       #
       # === Returns
       # Returns the exit status of args[:command]
-      def run_command(args={})
+      def run_command(args = {})
         status, stdout, stderr = run_command_and_return_stdout_stderr(args)
 
         status
@@ -84,7 +84,7 @@ class Chef
       # works same as above, except that it returns stdout and stderr
       # requirement => platforms like solaris 9,10 has weird issues where
       # even in command failure the exit code is zero, so we need to lookup stderr.
-      def run_command_and_return_stdout_stderr(args={})
+      def run_command_and_return_stdout_stderr(args = {})
         command_output = ""
 
         args[:ignore_failure] ||= false
@@ -143,7 +143,7 @@ class Chef
         return status, stdout_string, stderr_string
       end
 
-      def handle_command_failures(status, command_output, opts={})
+      def handle_command_failures(status, command_output, opts = {})
         return if opts[:ignore_failure]
         opts[:returns] ||= 0
         return if Array(opts[:returns]).include?(status.exitstatus)
@@ -165,7 +165,7 @@ class Chef
       #
       # === Returns
       # Returns the result of #run_command
-      def run_command_with_systems_locale(args={})
+      def run_command_with_systems_locale(args = {})
         args[:environment] ||= {}
         args[:environment]["LC_ALL"] = ENV["LC_ALL"]
         run_command args
diff --git a/lib/chef/mixin/command/unix.rb b/lib/chef/mixin/command/unix.rb
index 2bad4e6..d930ee3 100644
--- a/lib/chef/mixin/command/unix.rb
+++ b/lib/chef/mixin/command/unix.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ class Chef
         # The original appears in external/open4.rb in its unmodified form.
         #
         # Thanks Ara!
-        def popen4(cmd, args={}, &b)
+        def popen4(cmd, args = {}, &b)
           # Ruby 1.8 suffers from intermittent segfaults believed to be due to GC while IO.select
           # See CHEF-2916 / CHEF-1305
           GC.disable
@@ -89,7 +89,7 @@ class Chef
                 Process.uid = args[:user]
               end
 
-              args[:environment].each do |key,value|
+              args[:environment].each do |key, value|
                 ENV[key] = value
               end
 
@@ -104,7 +104,7 @@ class Chef
                 else
                   Kernel.exec(cmd)
                 end
-                raise 'forty-two'
+                raise "forty-two"
               rescue Exception => e
                 Marshal.dump(e, ps.last)
                 ps.last.flush
@@ -116,7 +116,7 @@ class Chef
             $VERBOSE = verbose
           end
 
-          [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close}
+          [pw.first, pr.last, pe.last, ps.last].each { |fd| fd.close }
 
           begin
             e = Marshal.load ps.first
@@ -205,7 +205,7 @@ class Chef
                 results.last
               end
             ensure
-              pi.each{|fd| fd.close unless fd.closed?}
+              pi.each { |fd| fd.close unless fd.closed? }
             end
           else
             [cid, pw.last, pr.first, pe.first]
diff --git a/lib/chef/mixin/command/windows.rb b/lib/chef/mixin/command/windows.rb
index 0147d58..fd45ab0 100644
--- a/lib/chef/mixin/command/windows.rb
+++ b/lib/chef/mixin/command/windows.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,20 +18,19 @@
 # limitations under the License.
 #
 
-require 'open3'
+require "open3"
 
 class Chef
   module Mixin
     module Command
       module Windows
-        def popen4(cmd, args={}, &b)
-
+        def popen4(cmd, args = {}, &b)
           # By default, we are waiting before we yield the block.
           args[:waitlast] ||= false
 
           #XXX :user, :group, :environment support?
 
-          Open3.popen3(cmd) do |stdin,stdout,stderr,cid|
+          Open3.popen3(cmd) do |stdin, stdout, stderr, cid|
             if b
               if args[:waitlast]
                 b[cid, stdin, stdout, stderr]
diff --git a/lib/chef/mixin/convert_to_class_name.rb b/lib/chef/mixin/convert_to_class_name.rb
index 19f229f..d6bd8a4 100644
--- a/lib/chef/mixin/convert_to_class_name.rb
+++ b/lib/chef/mixin/convert_to_class_name.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,7 @@ class Chef
       extend self
 
       def convert_to_class_name(str)
-        str = str.dup
-        str.gsub!(/[^A-Za-z0-9_]/,'_')
-        str.gsub!(/^(_+)?/,'')
+        str = normalize_snake_case_name(str)
         rname = nil
         regexp = %r{^(.+?)(_(.+))?$}
 
@@ -42,23 +40,31 @@ class Chef
         rname
       end
 
-      def convert_to_snake_case(str, namespace=nil)
+      def convert_to_snake_case(str, namespace = nil)
         str = str.dup
-        str.sub!(/^#{namespace}(\:\:)?/, '') if namespace
-        str.gsub!(/[A-Z]/) {|s| "_" + s}
+        str.sub!(/^#{namespace}(\:\:)?/, "") if namespace
+        str.gsub!(/[A-Z]/) { |s| "_" + s }
         str.downcase!
         str.sub!(/^\_/, "")
         str
       end
 
+      def normalize_snake_case_name(str)
+        str = str.dup
+        str.gsub!(/[^A-Za-z0-9_]/, "_")
+        str.gsub!(/^(_+)?/, "")
+        str
+      end
+
       def snake_case_basename(str)
         with_namespace = convert_to_snake_case(str)
-        with_namespace.split("::").last.sub(/^_/, '')
+        with_namespace.split("::").last.sub(/^_/, "")
       end
 
       def filename_to_qualified_string(base, filename)
         file_base = File.basename(filename, ".rb")
-        base.to_s + (file_base == 'default' ? '' : "_#{file_base}")
+        str = base.to_s + (file_base == "default" ? "" : "_#{file_base}")
+        normalize_snake_case_name(str)
       end
 
       # Copied from rails activesupport.  In ruby >= 2.0 const_get will just do this, so this can
@@ -85,7 +91,7 @@ class Chef
       # NameError is raised when the name is not in CamelCase or the constant is
       # unknown.
       def constantize(camel_cased_word)
-        names = camel_cased_word.split('::')
+        names = camel_cased_word.split("::")
 
         # Trigger a built-in NameError exception including the ill-formed constant in the message.
         Object.const_get(camel_cased_word) if names.empty?
diff --git a/lib/chef/mixin/create_path.rb b/lib/chef/mixin/create_path.rb
index 547224d..233f7b9 100644
--- a/lib/chef/mixin/create_path.rb
+++ b/lib/chef/mixin/create_path.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +35,7 @@ class Chef
 
         if file_path.kind_of?(String)
           file_path = File.expand_path(file_path).split(File::SEPARATOR)
-          file_path.shift if file_path[0] == ''
+          file_path.shift if file_path[0] == ""
           # Check if path starts with a separator or drive letter (Windows)
           unless file_path[0].match("^#{File::SEPARATOR}|^[a-zA-Z]:")
             file_path[0] = "#{File::SEPARATOR}#{file_path[0]}"
diff --git a/lib/chef/mixin/deep_merge.rb b/lib/chef/mixin/deep_merge.rb
index 825406a..c0b2d0d 100644
--- a/lib/chef/mixin/deep_merge.rb
+++ b/lib/chef/mixin/deep_merge.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Steve Midgley (http://www.misuse.org/science)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2008 Steve Midgley
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2008-2016, Steve Midgley
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/mixin/deprecation.rb b/lib/chef/mixin/deprecation.rb
index 489f27c..0f059a2 100644
--- a/lib/chef/mixin/deprecation.rb
+++ b/lib/chef/mixin/deprecation.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,10 +19,9 @@
 class Chef
   module Mixin
 
-
-      def self.deprecated_constants
-        @deprecated_constants ||= {}
-      end
+    def self.deprecated_constants
+      @deprecated_constants ||= {}
+    end
 
       # Add a deprecated constant to the Chef::Mixin namespace.
       # === Arguments
@@ -33,34 +32,34 @@ class Chef
       #   deprecate_constant(:RecipeDefinitionDSLCore, Chef::DSL::Recipe, <<-EOM)
       #     Chef::Mixin::RecipeDefinitionDSLCore is deprecated, use Chef::DSL::Recipe instead.
       #   EOM
-      def self.deprecate_constant(name, replacement, message)
-        deprecated_constants[name] = {:replacement => replacement, :message => message}
-      end
+    def self.deprecate_constant(name, replacement, message)
+      deprecated_constants[name] = { :replacement => replacement, :message => message }
+    end
 
       # Const missing hook to look up deprecated constants defined with
       # deprecate_constant. Emits a warning to the logger and returns the
       # replacement constant. Will call super, most likely causing an exception
       # for the missing constant, if +name+ is not found in the
       # deprecated_constants collection.
-      def self.const_missing(name)
-        if new_const = deprecated_constants[name]
-          Chef::Log.warn(new_const[:message])
-          Chef::Log.warn("Called from: \n#{caller[0...3].map {|l| "\t#{l}"}.join("\n")}")
-          new_const[:replacement]
-        else
-          super
-        end
+    def self.const_missing(name)
+      if new_const = deprecated_constants[name]
+        Chef::Log.warn(new_const[:message])
+        Chef::Log.warn("Called from: \n#{caller[0...3].map { |l| "\t#{l}" }.join("\n")}")
+        new_const[:replacement]
+      else
+        super
       end
+    end
 
     module Deprecation
 
       class DeprecatedObjectProxyBase
         KEEPERS = %w{__id__ __send__ instance_eval == equal? initialize object_id}
-        instance_methods.each { |method_name| undef_method(method_name) unless KEEPERS.include?(method_name.to_s)}
+        instance_methods.each { |method_name| undef_method(method_name) unless KEEPERS.include?(method_name.to_s) }
       end
 
       class DeprecatedInstanceVariable < DeprecatedObjectProxyBase
-        def initialize(target, ivar_name, level=nil)
+        def initialize(target, ivar_name, level = nil)
           @target, @ivar_name = target, ivar_name
           @level ||= :warn
         end
@@ -80,7 +79,7 @@ class Chef
           called_from = called_from.flatten
           log("Accessing #{@ivar_name} by the variable @#{@ivar_name} is deprecated. Support will be removed in a future release.")
           log("Please update your cookbooks to use #{@ivar_name} in place of @#{@ivar_name}. Accessed from:")
-          called_from.each {|l| log(l)}
+          called_from.each { |l| log(l) }
         end
 
         def log(msg)
@@ -91,10 +90,34 @@ class Chef
 
       end
 
-      def deprecated_ivar(obj, name, level=nil)
+      def deprecated_ivar(obj, name, level = nil)
         DeprecatedInstanceVariable.new(obj, name, level)
       end
 
+      def deprecated_attr(name, alternative)
+        deprecated_attr_reader(name, alternative)
+        deprecated_attr_writer(name, alternative)
+      end
+
+      def deprecated_attr_reader(name, alternative, level = :warn)
+        define_method(name) do
+          Chef.log_deprecation("#{self.class}.#{name} is deprecated. Support will be removed in a future release.")
+          Chef.log_deprecation(alternative)
+          Chef.log_deprecation("Called from:")
+          caller[0..3].each { |c| Chef.log_deprecation(c) }
+          instance_variable_get("@#{name}")
+        end
+      end
+
+      def deprecated_attr_writer(name, alternative, level = :warn)
+        define_method("#{name}=") do |value|
+          Chef.log_deprecation("Writing to #{self.class}.#{name} with #{name}= is deprecated. Support will be removed in a future release.")
+          Chef.log_deprecation(alternative)
+          Chef.log_deprecation("Called from:")
+          caller[0..3].each { |c| Chef.log_deprecation(c) }
+          instance_variable_set("@#{name}", value)
+        end
+      end
     end
   end
 end
diff --git a/lib/chef/mixin/descendants_tracker.rb b/lib/chef/mixin/descendants_tracker.rb
index 75d1f62..b0f0ff2 100644
--- a/lib/chef/mixin/descendants_tracker.rb
+++ b/lib/chef/mixin/descendants_tracker.rb
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2005-2012 David Heinemeier Hansson
+# Copyright 2005-2016, David Heinemeier Hansson
 #
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
@@ -21,7 +21,6 @@
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
 
-
 # This is lifted from rails activesupport (note the copyright above):
 # https://github.com/rails/rails/blob/9f84e60ac9d7bf07d6ae1bc94f3941f5b8f1a228/activesupport/lib/active_support/descendants_tracker.rb
 
@@ -42,7 +41,7 @@ class Chef
         end
 
         def find_descendants_by_name(klass, name)
-          descendants(klass).first {|c| c.name == name }
+          descendants(klass).first { |c| c.name == name }
         end
 
         # This is the only method that is not thread safe, but is only ever called
diff --git a/lib/chef/mixin/enforce_ownership_and_permissions.rb b/lib/chef/mixin/enforce_ownership_and_permissions.rb
index 9c1e4dd..e02c347 100644
--- a/lib/chef/mixin/enforce_ownership_and_permissions.rb
+++ b/lib/chef/mixin/enforce_ownership_and_permissions.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/file_access_control'
+require "chef/file_access_control"
 
 class Chef
   module Mixin
diff --git a/lib/chef/mixin/file_class.rb b/lib/chef/mixin/file_class.rb
index f6a663d..166dd57 100644
--- a/lib/chef/mixin/file_class.rb
+++ b/lib/chef/mixin/file_class.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Mark Mzyk <mmzyk at opscode.com>
-# Author:: Seth Chisamore <schisamo at opscode.com>
-# Author:: Bryan McLellan <btm at opscode.com>
-# Copyright:: Copyright (c) 2011-2012 Opscode, Inc.
+# Author:: Mark Mzyk <mmzyk at chef.io>
+# Author:: Seth Chisamore <schisamo at chef.io>
+# Author:: Bryan McLellan <btm at chef.io>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,14 +24,12 @@ class Chef
 
       def file_class
         @host_os_file ||= if Chef::Platform.windows?
-          require 'chef/win32/file'
-          Chef::ReservedNames::Win32::File
-        else
-          ::File
-        end
+                            require "chef/win32/file"
+                            Chef::ReservedNames::Win32::File
+                          else
+                            ::File
+                          end
       end
     end
   end
 end
-
-
diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb
index 0d1ddca..a6692d7 100644
--- a/lib/chef/mixin/from_file.rb
+++ b/lib/chef/mixin/from_file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/mixin/get_source_from_package.rb b/lib/chef/mixin/get_source_from_package.rb
index 2ed2518..555dd63 100644
--- a/lib/chef/mixin/get_source_from_package.rb
+++ b/lib/chef/mixin/get_source_from_package.rb
@@ -1,5 +1,5 @@
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,6 @@
 # limitations under the License.
 #
 
-
 #
 # mixin to make this syntax work without specifying a source:
 #
@@ -27,6 +26,12 @@
 class Chef
   module Mixin
     module GetSourceFromPackage
+      # FIXME:  this is some bad code that I wrote a long time ago.
+      #  - it does too much in the initializer
+      #  - it mutates the new_resource
+      #  - it does not support multipackage arrays
+      # this code is deprecated, check out the :use_package_names_for_source
+      # subclass directive instead
       def initialize(new_resource, run_context)
         super
         return if new_resource.package_name.is_a?(Array)
@@ -40,4 +45,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/mixin/homebrew_user.rb b/lib/chef/mixin/homebrew_user.rb
index ab6fb19..888c1bc 100644
--- a/lib/chef/mixin/homebrew_user.rb
+++ b/lib/chef/mixin/homebrew_user.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
+# Author:: Joshua Timberman (<joshua at chef.io>)
 # Author:: Graeme Mathieson (<mathie at woss.name>)
 #
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal at getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -22,8 +22,8 @@
 # This lives here in Chef::Mixin because Chef's namespacing makes it
 # awkward to use modules elsewhere (e.g., chef/provider/package/homebrew/owner)
 
-require 'chef/mixin/shell_out'
-require 'etc'
+require "chef/mixin/shell_out"
+require "etc"
 
 class Chef
   module Mixin
@@ -48,7 +48,7 @@ class Chef
       private
 
       def calculate_owner
-        default_brew_path = '/usr/local/bin/brew'
+        default_brew_path = "/usr/local/bin/brew"
         if ::File.exist?(default_brew_path)
           # By default, this follows symlinks which is what we want
           owner = ::File.stat(default_brew_path).uid
diff --git a/lib/chef/mixin/language.rb b/lib/chef/mixin/language.rb
index f4df86b..3f53645 100644
--- a/lib/chef/mixin/language.rb
+++ b/lib/chef/mixin/language.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/mixin/deprecation'
+require "chef/dsl/platform_introspection"
+require "chef/dsl/data_query"
+require "chef/mixin/deprecation"
 
 class Chef
   module Mixin
diff --git a/lib/chef/mixin/language_include_attribute.rb b/lib/chef/mixin/language_include_attribute.rb
index 0be2614..7cb66dc 100644
--- a/lib/chef/mixin/language_include_attribute.rb
+++ b/lib/chef/mixin/language_include_attribute.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/dsl/include_attribute'
-require 'chef/mixin/deprecation'
+require "chef/dsl/include_attribute"
+require "chef/mixin/deprecation"
 
 class Chef
   module Mixin
@@ -32,4 +32,3 @@ EOM
 
   end
 end
-
diff --git a/lib/chef/mixin/language_include_recipe.rb b/lib/chef/mixin/language_include_recipe.rb
index d85e5c6..97e384c 100644
--- a/lib/chef/mixin/language_include_recipe.rb
+++ b/lib/chef/mixin/language_include_recipe.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/dsl/include_recipe'
-require 'chef/mixin/deprecation'
+require "chef/dsl/include_recipe"
+require "chef/mixin/deprecation"
 
 class Chef
   module Mixin
@@ -29,4 +29,3 @@ EOM
 
   end
 end
-
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb
index 78d72dc..598c6c3 100644
--- a/lib/chef/mixin/params_validate.rb
+++ b/lib/chef/mixin/params_validate.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+require "chef/constants"
+require "chef/property"
+require "chef/delayed_evaluator"
+
 class Chef
-  class DelayedEvaluator < Proc
-  end
   module Mixin
     module ParamsValidate
-
       # Takes a hash of options, along with a map to validate them.  Returns the original
       # options hash, plus any changes that might have been made (through things like setting
       # default values in the validation map)
@@ -32,20 +33,55 @@ class Chef
       # Would raise an exception if the value of :one above is not a kind_of? string.  Valid
       # map options are:
       #
-      # :default:: Sets the default value for this parameter.
-      # :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
-      #              The key will be inserted into the error message if the Proc does not return true:
-      #                 "Option #{key}'s value #{value} #{message}!"
-      # :kind_of:: Ensure that the value is a kind_of?(Whatever).  If passed an array, it will ensure
-      #            that the value is one of those types.
-      # :respond_to:: Ensure that the value has a given method.  Takes one method name or an array of
-      #               method names.
-      # :required:: Raise an exception if this parameter is missing. Valid values are true or false,
-      #             by default, options are not required.
-      # :regex:: Match the value of the parameter against a regular expression.
-      # :equal_to:: Match the value of the parameter with ==.  An array means it can be equal to any
-      #             of the values.
+      # @param opts [Hash<Symbol,Object>] Validation opts.
+      #   @option opts [Object,Array] :is An object, or list of
+      #     objects, that must match the value using Ruby's `===` operator
+      #     (`opts[:is].any? { |v| v === value }`). (See #_pv_is.)
+      #   @option opts [Object,Array] :equal_to An object, or list
+      #     of objects, that must be equal to the value using Ruby's `==`
+      #     operator (`opts[:is].any? { |v| v == value }`)  (See #_pv_equal_to.)
+      #   @option opts [Regexp,Array<Regexp>] :regex An object, or
+      #     list of objects, that must match the value with `regex.match(value)`.
+      #     (See #_pv_regex)
+      #   @option opts [Class,Array<Class>] :kind_of A class, or
+      #     list of classes, that the value must be an instance of.  (See
+      #     #_pv_kind_of.)
+      #   @option opts [Hash<String,Proc>] :callbacks A hash of
+      #     messages -> procs, all of which match the value. The proc must
+      #     return a truthy or falsey value (true means it matches).  (See
+      #     #_pv_callbacks.)
+      #   @option opts [Symbol,Array<Symbol>] :respond_to A method
+      #     name, or list of method names, the value must respond to.  (See
+      #     #_pv_respond_to.)
+      #   @option opts [Symbol,Array<Symbol>] :cannot_be A property,
+      #     or a list of properties, that the value cannot have (such as `:nil` or
+      #     `:empty`). The method with a questionmark at the end is called on the
+      #     value (e.g. `value.empty?`). If the value does not have this method,
+      #     it is considered valid (i.e. if you don't respond to `empty?` we
+      #     assume you are not empty).  (See #_pv_cannot_be.)
+      #   @option opts [Proc] :coerce A proc which will be called to
+      #     transform the user input to canonical form. The value is passed in,
+      #     and the transformed value returned as output. Lazy values will *not*
+      #     be passed to this method until after they are evaluated. Called in the
+      #     context of the resource (meaning you can access other properties).
+      #     (See #_pv_coerce.) (See #_pv_coerce.)
+      #   @option opts [Boolean] :required `true` if this property
+      #     must be present and not `nil`; `false` otherwise. This is checked
+      #     after the resource is fully initialized. (See #_pv_required.)
+      #   @option opts [Boolean] :name_property `true` if this
+      #     property defaults to the same value as `name`. Equivalent to
+      #     `default: lazy { name }`, except that #property_is_set? will
+      #     return `true` if the property is set *or* if `name` is set. (See
+      #     #_pv_name_property.)
+      #   @option opts [Boolean] :name_attribute Same as `name_property`.
+      #   @option opts [Object] :default The value this property
+      #     will return if the user does not set one. If this is `lazy`, it will
+      #     be run in the context of the instance (and able to access other
+      #     properties).  (See #_pv_default.)
+      #
       def validate(opts, map)
+        map = map.validation_options if map.is_a?(Property)
+
         #--
         # validate works by taking the keys in the validation map, assuming it's a hash, and
         # looking for _pv_:symbol as methods.  Assuming it find them, it calls the right
@@ -65,7 +101,7 @@ class Chef
             true
           when Hash
             validation.each do |check, carg|
-              check_method = "_pv_#{check.to_s}"
+              check_method = "_pv_#{check}"
               if self.respond_to?(check_method, true)
                 self.send(check_method, opts, key, carg)
               else
@@ -81,162 +117,373 @@ class Chef
         DelayedEvaluator.new(&block)
       end
 
-      def set_or_return(symbol, arg, validation)
-        iv_symbol = "@#{symbol.to_s}".to_sym
-        if arg == nil && self.instance_variable_defined?(iv_symbol) == true
-          ivar = self.instance_variable_get(iv_symbol)
-          if(ivar.is_a?(DelayedEvaluator))
-            validate({ symbol => ivar.call }, { symbol => validation })[symbol]
-          else
-            ivar
-          end
-        else
-          if(arg.is_a?(DelayedEvaluator))
-            val = arg
-          else
-            val = validate({ symbol => arg }, { symbol => validation })[symbol]
+      def set_or_return(symbol, value, validation)
+        property = SetOrReturnProperty.new(name: symbol, **validation)
+        property.call(self, value)
+      end
 
-            # Handle the case where the "default" was a DelayedEvaluator. In
-            # this case, the block yields an optional parameter of +self+,
-            # which is the equivalent of "new_resource"
-            if val.is_a?(DelayedEvaluator)
-              val = val.call(self)
-            end
-          end
-          self.instance_variable_set(iv_symbol, val)
+      private
+
+      def explicitly_allows_nil?(key, validation)
+        validation.has_key?(:is) && _pv_is({ key => nil }, key, validation[:is], raise_error: false)
+      end
+
+      # Return the value of a parameter, or nil if it doesn't exist.
+      def _pv_opts_lookup(opts, key)
+        if opts.has_key?(key.to_s)
+          opts[key.to_s]
+        elsif opts.has_key?(key.to_sym)
+          opts[key.to_sym]
+        else
+          nil
         end
       end
 
-      private
+      # Raise an exception if the parameter is not found.
+      def _pv_required(opts, key, is_required = true, explicitly_allows_nil = false)
+        if is_required
+          return true if opts.has_key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?)
+          return true if opts.has_key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?)
+          raise Exceptions::ValidationFailed, "Required argument #{key.inspect} is missing!"
+        end
+        true
+      end
 
-        # Return the value of a parameter, or nil if it doesn't exist.
-        def _pv_opts_lookup(opts, key)
-          if opts.has_key?(key.to_s)
-            opts[key.to_s]
-          elsif opts.has_key?(key.to_sym)
-            opts[key.to_sym]
-          else
-            nil
+      #
+      # List of things values must be equal to.
+      #
+      # Uses Ruby's `==` to evaluate (equal_to == value).  At least one must
+      # match for the value to be valid.
+      #
+      # `nil` passes this validation automatically.
+      #
+      # @return [Array,nil] List of things values must be equal to, or nil if
+      #   equal_to is unspecified.
+      #
+      def _pv_equal_to(opts, key, to_be)
+        value = _pv_opts_lookup(opts, key)
+        unless value.nil?
+          to_be = Array(to_be)
+          to_be.each do |tb|
+            return true if value == tb
           end
+          raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}!  You passed #{value.inspect}."
         end
+      end
 
-        # Raise an exception if the parameter is not found.
-        def _pv_required(opts, key, is_required=true)
-          if is_required
-            if (opts.has_key?(key.to_s) && !opts[key.to_s].nil?) ||
-                (opts.has_key?(key.to_sym) && !opts[key.to_sym].nil?)
-              true
-            else
-              raise Exceptions::ValidationFailed, "Required argument #{key} is missing!"
-            end
+      #
+      # List of things values must be instances of.
+      #
+      # Uses value.kind_of?(kind_of) to evaluate. At least one must match for
+      # the value to be valid.
+      #
+      # `nil` automatically passes this validation.
+      #
+      def _pv_kind_of(opts, key, to_be)
+        value = _pv_opts_lookup(opts, key)
+        unless value.nil?
+          to_be = Array(to_be)
+          to_be.each do |tb|
+            return true if value.kind_of?(tb)
           end
+          raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}!  You passed #{value.inspect}."
         end
+      end
 
-        def _pv_equal_to(opts, key, to_be)
-          value = _pv_opts_lookup(opts, key)
-          unless value.nil?
-            passes = false
-            Array(to_be).each do |tb|
-              passes = true if value == tb
-            end
-            unless passes
-              raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}!  You passed #{value.inspect}."
+      #
+      # List of method names values must respond to.
+      #
+      # Uses value.respond_to?(respond_to) to evaluate. At least one must match
+      # for the value to be valid.
+      #
+      def _pv_respond_to(opts, key, method_name_list)
+        value = _pv_opts_lookup(opts, key)
+        unless value.nil?
+          Array(method_name_list).each do |method_name|
+            unless value.respond_to?(method_name)
+              raise Exceptions::ValidationFailed, "Option #{key} must have a #{method_name} method!"
             end
           end
         end
+      end
 
-        # Raise an exception if the parameter is not a kind_of?(to_be)
-        def _pv_kind_of(opts, key, to_be)
-          value = _pv_opts_lookup(opts, key)
-          unless value.nil?
-            passes = false
-            Array(to_be).each do |tb|
-              passes = true if value.kind_of?(tb)
-            end
-            unless passes
-              raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}!  You passed #{value.inspect}."
+      #
+      # List of things that must not be true about the value.
+      #
+      # Calls `value.<thing>?` All responses must be false for the value to be
+      # valid.
+      # Values which do not respond to <thing>? are considered valid (because if
+      # a value doesn't respond to `:readable?`, then it probably isn't
+      # readable.)
+      #
+      # @example
+      #   ```ruby
+      #   property :x, cannot_be: [ :nil, :empty ]
+      #   x [ 1, 2 ] #=> valid
+      #   x 1        #=> valid
+      #   x []       #=> invalid
+      #   x nil      #=> invalid
+      #   ```
+      #
+      def _pv_cannot_be(opts, key, predicate_method_base_name)
+        value = _pv_opts_lookup(opts, key)
+        if !value.nil?
+          Array(predicate_method_base_name).each do |method_name|
+            predicate_method = :"#{method_name}?"
+
+            if value.respond_to?(predicate_method)
+              if value.send(predicate_method)
+                raise Exceptions::ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
+              end
             end
           end
         end
+      end
 
-        # Raise an exception if the parameter does not respond to a given set of methods.
-        def _pv_respond_to(opts, key, method_name_list)
-          value = _pv_opts_lookup(opts, key)
-          unless value.nil?
-            Array(method_name_list).each do |method_name|
-              unless value.respond_to?(method_name)
-                raise Exceptions::ValidationFailed, "Option #{key} must have a #{method_name} method!"
-              end
-            end
+      #
+      # The default value for a property.
+      #
+      # When the property is not assigned, this will be used.
+      #
+      # If this is a lazy value, it will either be passed the resource as a value,
+      # or if the lazy proc does not take parameters, it will be run in the
+      # context of the instance with instance_eval.
+      #
+      # @example
+      #   ```ruby
+      #   property :x, default: 10
+      #   ```
+      #
+      # @example
+      #   ```ruby
+      #   property :x
+      #   property :y, default: lazy { x+2 }
+      #   ```
+      #
+      # @example
+      #   ```ruby
+      #   property :x
+      #   property :y, default: lazy { |r| r.x+2 }
+      #   ```
+      #
+      def _pv_default(opts, key, default_value)
+        value = _pv_opts_lookup(opts, key)
+        if value.nil?
+          default_value = default_value.freeze if !default_value.is_a?(DelayedEvaluator)
+          opts[key] = default_value
+        end
+      end
+
+      #
+      # List of regexes values that must match.
+      #
+      # Uses regex.match() to evaluate. At least one must match for the value to
+      # be valid.
+      #
+      # `nil` passes regex validation automatically.
+      #
+      # @example
+      #   ```ruby
+      #   property :x, regex: [ /abc/, /xyz/ ]
+      #   ```
+      #
+      def _pv_regex(opts, key, regex)
+        value = _pv_opts_lookup(opts, key)
+        if !value.nil?
+          Array(regex).flatten.each do |r|
+            return true if r.match(value.to_s)
           end
+          raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
         end
+      end
 
-        # Assert that parameter returns false when passed a predicate method.
-        # For example, :cannot_be => :blank will raise a Exceptions::ValidationFailed
-        # error value.blank? returns a 'truthy' (not nil or false) value.
-        #
-        # Note, this will *PASS* if the object doesn't respond to the method.
-        # So, to make sure a value is not nil and not blank, you need to do
-        # both :cannot_be => :blank *and* :cannot_be => :nil (or :required => true)
-        def _pv_cannot_be(opts, key, predicate_method_base_name)
-          value = _pv_opts_lookup(opts, key)
-          predicate_method = (predicate_method_base_name.to_s + "?").to_sym
-
-          if value.respond_to?(predicate_method)
-            if value.send(predicate_method)
-              raise Exceptions::ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
+      #
+      # List of procs we pass the value to.
+      #
+      # All procs must return true for the value to be valid. If any procs do
+      # not return true, the key will be used for the message: `"Property x's
+      # value :y <message>"`.
+      #
+      # @example
+      #   ```ruby
+      #   property :x, callbacks: { "is bigger than 10" => proc { |v| v <= 10 }, "is not awesome" => proc { |v| !v.awesome }}
+      #   ```
+      #
+      def _pv_callbacks(opts, key, callbacks)
+        raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
+        value = _pv_opts_lookup(opts, key)
+        if !value.nil?
+          callbacks.each do |message, zeproc|
+            unless zeproc.call(value)
+              raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!"
             end
           end
         end
+      end
 
-        # Assign a default value to a parameter.
-        def _pv_default(opts, key, default_value)
-          value = _pv_opts_lookup(opts, key)
-          if value == nil
-            opts[key] = default_value
+      #
+      # Allows a parameter to default to the value of the resource name.
+      #
+      # @example
+      #   ```ruby
+      #    property :x, name_property: true
+      #   ```
+      #
+      def _pv_name_property(opts, key, is_name_property = true)
+        if is_name_property
+          if opts[key].nil?
+            raise CannotValidateStaticallyError, "name_property cannot be evaluated without a resource." if self == Chef::Mixin::ParamsValidate
+            opts[key] = self.instance_variable_get(:"@name")
           end
         end
+      end
+      alias :_pv_name_attribute :_pv_name_property
 
-        # Check a parameter against a regular expression.
-        def _pv_regex(opts, key, regex)
-          value = _pv_opts_lookup(opts, key)
-          if value != nil
-            passes = false
-            [ regex ].flatten.each do |r|
-              if value != nil
-                if r.match(value.to_s)
-                  passes = true
-                end
-              end
-            end
-            unless passes
-              raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
+      #
+      # List of valid things values can be.
+      #
+      # Uses Ruby's `===` to evaluate (is === value).  At least one must match
+      # for the value to be valid.
+      #
+      # If a proc is passed, it is instance_eval'd in the resource, passed the
+      # value, and must return a truthy or falsey value.
+      #
+      # @example Class
+      #   ```ruby
+      #   property :x, String
+      #   x 'valid' #=> valid
+      #   x 1       #=> invalid
+      #   x nil     #=> invalid
+      #
+      # @example Value
+      #   ```ruby
+      #   property :x, [ :a, :b, :c, nil ]
+      #   x :a  #=> valid
+      #   x nil #=> valid
+      #   ```
+      #
+      # @example Regex
+      #   ```ruby
+      #   property :x, /bar/
+      #   x 'foobar' #=> valid
+      #   x 'foo'    #=> invalid
+      #   x nil      #=> invalid
+      #   ```
+      #
+      # @example Proc
+      #   ```ruby
+      #   property :x, proc { |x| x > y }
+      #   property :y, default: 2
+      #   x 3 #=> valid
+      #   x 1 #=> invalid
+      #   ```
+      #
+      # @example Property
+      #   ```ruby
+      #   type = Property.new(is: String)
+      #   property :x, type
+      #   x 'foo' #=> valid
+      #   x 1     #=> invalid
+      #   x nil   #=> invalid
+      #   ```
+      #
+      # @example RSpec Matcher
+      #   ```ruby
+      #   include RSpec::Matchers
+      #   property :x, a_string_matching /bar/
+      #   x 'foobar' #=> valid
+      #   x 'foo'    #=> invalid
+      #   x nil      #=> invalid
+      #   ```
+      #
+      def _pv_is(opts, key, to_be, raise_error: true)
+        return true if !opts.has_key?(key.to_s) && !opts.has_key?(key.to_sym)
+        value = _pv_opts_lookup(opts, key)
+        to_be = [ to_be ].flatten(1)
+        errors = []
+        passed = to_be.any? do |tb|
+          case tb
+          when Proc
+            raise CannotValidateStaticallyError, "is: proc { } must be evaluated once for each resource" if self == Chef::Mixin::ParamsValidate
+            instance_exec(value, &tb)
+          when Property
+            begin
+              validate(opts, { key => tb.validation_options })
+              true
+            rescue Exceptions::ValidationFailed
+              # re-raise immediately if there is only one "is" so we get a better stack
+              raise if to_be.size == 1
+              errors << $!
+              false
             end
+          else
+            tb === value
           end
         end
+        if passed
+          true
+        else
+          message = "Property #{key} must be one of: #{to_be.map { |v| v.inspect }.join(", ")}!  You passed #{value.inspect}."
+          unless errors.empty?
+            message << " Errors:\n#{errors.map { |m| "- #{m}" }.join("\n")}"
+          end
+          raise Exceptions::ValidationFailed, message
+        end
+      end
 
-        # Check a parameter against a hash of proc's.
-        def _pv_callbacks(opts, key, callbacks)
-          raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
-          value = _pv_opts_lookup(opts, key)
-          if value != nil
-            callbacks.each do |message, zeproc|
-              if zeproc.call(value) != true
-                raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!"
-              end
-            end
+      #
+      # Method to mess with a value before it is validated and stored.
+      #
+      # Allows you to transform values into a canonical form that is easy to
+      # work with.
+      #
+      # This is passed the value to transform, and is run in the context of the
+      # instance (so it has access to other resource properties). It must return
+      # the value that will be stored in the instance.
+      #
+      # @example
+      #   ```ruby
+      #   property :x, Integer, coerce: { |v| v.to_i }
+      #   ```
+      #
+      def _pv_coerce(opts, key, coercer)
+        if opts.has_key?(key.to_s)
+          raise CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate
+          opts[key.to_s] = instance_exec(opts[key], &coercer)
+        elsif opts.has_key?(key.to_sym)
+          raise CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate
+          opts[key.to_sym] = instance_exec(opts[key], &coercer)
+        end
+      end
+
+      # We allow Chef::Mixin::ParamsValidate.validate(), but we will raise an
+      # error if you try to do anything requiring there to be an actual resource.
+      # This way, you can statically validate things if you have constant validation
+      # (which is the norm).
+      extend self
+
+      # Used by #set_or_return to avoid emitting a deprecation warning for
+      # "value nil" and to keep default stickiness working exactly the same
+      # @api private
+      class SetOrReturnProperty < Chef::Property
+        def get(resource)
+          value = super
+          # All values are sticky, frozen or not
+          if !is_set?(resource)
+            set_value(resource, value)
           end
+          value
         end
 
-        # Allow a parameter to default to @name
-        def _pv_name_attribute(opts, key, is_name_attribute=true)
-          if is_name_attribute
-            if opts[key] == nil
-              opts[key] = self.instance_variable_get("@name")
-            end
+        def call(resource, value = NOT_PASSED)
+          # setting to nil does a get
+          if value.nil? && !explicitly_accepts_nil?(resource)
+            get(resource)
+          else
+            super
           end
         end
+      end
     end
   end
 end
-
diff --git a/lib/chef/mixin/path_sanity.rb b/lib/chef/mixin/path_sanity.rb
index ed857ff..7078c58 100644
--- a/lib/chef/mixin/path_sanity.rb
+++ b/lib/chef/mixin/path_sanity.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,10 @@ class Chef
   module Mixin
     module PathSanity
 
-      def enforce_path_sanity(env=ENV)
+      def enforce_path_sanity(env = ENV)
         if Chef::Config[:enforce_path_sanity]
           env["PATH"] = "" if env["PATH"].nil?
-          path_separator = Chef::Platform.windows? ? ';' : ':'
+          path_separator = Chef::Platform.windows? ? ";" : ":"
           existing_paths = env["PATH"].split(path_separator)
           # ensure the Ruby and Gem bindirs are included
           # mainly for 'full-stack' Chef installs
@@ -48,15 +48,15 @@ class Chef
       def sane_paths
         @sane_paths ||= begin
           if Chef::Platform.windows?
-            %w[]
+            %w{}
           else
-            %w[/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin]
+            %w{/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin}
           end
         end
       end
 
       def ruby_bindir
-        RbConfig::CONFIG['bindir']
+        RbConfig::CONFIG["bindir"]
       end
 
       def gem_bindir
diff --git a/lib/chef/mixin/powershell_out.rb b/lib/chef/mixin/powershell_out.rb
new file mode 100644
index 0000000..7fff958
--- /dev/null
+++ b/lib/chef/mixin/powershell_out.rb
@@ -0,0 +1,98 @@
+#--
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "chef/mixin/shell_out"
+require "chef/mixin/windows_architecture_helper"
+
+class Chef
+  module Mixin
+    module PowershellOut
+      include Chef::Mixin::ShellOut
+      include Chef::Mixin::WindowsArchitectureHelper
+
+      # Run a command under powershell with the same API as shell_out.  The
+      # options hash is extended to take an "architecture" flag which
+      # can be set to :i386 or :x86_64 to force the windows architecture.
+      #
+      # @param script [String] script to run
+      # @param options [Hash] options hash
+      # @return [Mixlib::Shellout] mixlib-shellout object
+      def powershell_out(*command_args)
+        script = command_args.first
+        options = command_args.last.is_a?(Hash) ? command_args.last : nil
+
+        run_command_with_os_architecture(script, options)
+      end
+
+      # Run a command under powershell with the same API as shell_out!
+      # (raises exceptions on errors)
+      #
+      # @param script [String] script to run
+      # @param options [Hash] options hash
+      # @return [Mixlib::Shellout] mixlib-shellout object
+      def powershell_out!(*command_args)
+        cmd = powershell_out(*command_args)
+        cmd.error!
+        cmd
+      end
+
+      private
+
+      # Helper function to run shell_out and wrap it with the correct
+      # flags to possibly disable WOW64 redirection (which we often need
+      # because chef-client runs as a 32-bit app on 64-bit windows).
+      #
+      # @param script [String] script to run
+      # @param options [Hash] options hash
+      # @return [Mixlib::Shellout] mixlib-shellout object
+      def run_command_with_os_architecture(script, options)
+        options ||= {}
+        options = options.dup
+        arch = options.delete(:architecture)
+
+        with_os_architecture(nil, architecture: arch) do
+          shell_out(
+            build_powershell_command(script),
+            options,
+          )
+        end
+      end
+
+      # Helper to build a powershell command around the script to run.
+      #
+      # @param script [String] script to run
+      # @retrurn [String] powershell command to execute
+      def build_powershell_command(script)
+        flags = [
+          # Hides the copyright banner at startup.
+          "-NoLogo",
+          # Does not present an interactive prompt to the user.
+          "-NonInteractive",
+          # Does not load the Windows PowerShell profile.
+          "-NoProfile",
+          # always set the ExecutionPolicy flag
+          # see http://technet.microsoft.com/en-us/library/ee176961.aspx
+          "-ExecutionPolicy Unrestricted",
+          # Powershell will hang if STDIN is redirected
+          # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
+          "-InputFormat None",
+        ]
+
+        "powershell.exe #{flags.join(' ')} -Command \"#{script}\""
+      end
+    end
+  end
+end
diff --git a/lib/chef/mixin/powershell_type_coercions.rb b/lib/chef/mixin/powershell_type_coercions.rb
index 75b3276..381cbed 100644
--- a/lib/chef/mixin/powershell_type_coercions.rb
+++ b/lib/chef/mixin/powershell_type_coercions.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 # Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,12 +23,14 @@ class Chef
 
       def type_coercions
         @type_coercions ||= {
-          Fixnum => { :type => lambda { |x| x.to_s }},
-          Float => { :type => lambda { |x| x.to_s }},
-          FalseClass => { :type => lambda { |x| '$false' }},
-          TrueClass => { :type => lambda { |x| '$true' }},
-          Hash => {:type => Proc.new { |x| translate_hash(x)}},
-          Array => {:type => Proc.new { |x| translate_array(x)}}
+          Fixnum => { :type => lambda { |x| x.to_s } },
+          Float => { :type => lambda { |x| x.to_s } },
+          FalseClass => { :type => lambda { |x| "$false" } },
+          TrueClass => { :type => lambda { |x| "$true" } },
+          Hash => { :type => Proc.new { |x| translate_hash(x) } },
+          Array => { :type => Proc.new { |x| translate_array(x) } },
+          Chef::Node::ImmutableMash => { :type => Proc.new { |x| translate_hash(x) } },
+          Chef::Node::ImmutableArray => { :type => Proc.new { |x| translate_array(x) } },
         }
       end
 
@@ -47,7 +49,7 @@ class Chef
       private
 
       def translate_hash(x)
-        translated = x.inject([]) do |memo, (k,v)|
+        translated = x.inject([]) do |memo, (k, v)|
           memo << "#{k}=#{translate_type(v)}"
         end
         "@{#{translated.join(';')}}"
@@ -61,7 +63,7 @@ class Chef
       end
 
       def unsafe?(s)
-        ["'", '#', '`', '"'].any? do |x|
+        ["'", '#', "`", '"'].any? do |x|
           s.include? x
         end
       end
diff --git a/lib/chef/mixin/properties.rb b/lib/chef/mixin/properties.rb
new file mode 100644
index 0000000..2e33d2d
--- /dev/null
+++ b/lib/chef/mixin/properties.rb
@@ -0,0 +1,302 @@
+require "chef/delayed_evaluator"
+require "chef/mixin/params_validate"
+require "chef/property"
+
+class Chef
+  module Mixin
+    module Properties
+      module ClassMethods
+        #
+        # The list of properties defined on this resource.
+        #
+        # Everything defined with `property` is in this list.
+        #
+        # @param include_superclass [Boolean] `true` to include properties defined
+        #   on superclasses; `false` or `nil` to return the list of properties
+        #   directly on this class.
+        #
+        # @return [Hash<Symbol,Property>] The list of property names and types.
+        #
+        def properties(include_superclass = true)
+          if include_superclass
+            result = {}
+            ancestors.reverse_each { |c| result.merge!(c.properties(false)) if c.respond_to?(:properties) }
+            result
+          else
+            @properties ||= {}
+          end
+        end
+
+        #
+        # Create a property on this resource class.
+        #
+        # If a superclass has this property, or if this property has already been
+        # defined by this resource, this will *override* the previous value.
+        #
+        # @param name [Symbol] The name of the property.
+        # @param type [Object,Array<Object>] The type(s) of this property.
+        #   If present, this is prepended to the `is` validation option.
+        # @param options [Hash<Symbol,Object>] Validation options.
+        #   @option options [Object,Array] :is An object, or list of
+        #     objects, that must match the value using Ruby's `===` operator
+        #     (`options[:is].any? { |v| v === value }`).
+        #   @option options [Object,Array] :equal_to An object, or list
+        #     of objects, that must be equal to the value using Ruby's `==`
+        #     operator (`options[:is].any? { |v| v == value }`)
+        #   @option options [Regexp,Array<Regexp>] :regex An object, or
+        #     list of objects, that must match the value with `regex.match(value)`.
+        #   @option options [Class,Array<Class>] :kind_of A class, or
+        #     list of classes, that the value must be an instance of.
+        #   @option options [Hash<String,Proc>] :callbacks A hash of
+        #     messages -> procs, all of which match the value. The proc must
+        #     return a truthy or falsey value (true means it matches).
+        #   @option options [Symbol,Array<Symbol>] :respond_to A method
+        #     name, or list of method names, the value must respond to.
+        #   @option options [Symbol,Array<Symbol>] :cannot_be A property,
+        #     or a list of properties, that the value cannot have (such as `:nil` or
+        #     `:empty`). The method with a questionmark at the end is called on the
+        #     value (e.g. `value.empty?`). If the value does not have this method,
+        #     it is considered valid (i.e. if you don't respond to `empty?` we
+        #     assume you are not empty).
+        #   @option options [Proc] :coerce A proc which will be called to
+        #     transform the user input to canonical form. The value is passed in,
+        #     and the transformed value returned as output. Lazy values will *not*
+        #     be passed to this method until after they are evaluated. Called in the
+        #     context of the resource (meaning you can access other properties).
+        #   @option options [Boolean] :required `true` if this property
+        #     must be present; `false` otherwise. This is checked after the resource
+        #     is fully initialized.
+        #   @option options [Boolean] :name_property `true` if this
+        #     property defaults to the same value as `name`. Equivalent to
+        #     `default: lazy { name }`, except that #property_is_set? will
+        #     return `true` if the property is set *or* if `name` is set.
+        #   @option options [Boolean] :name_attribute Same as `name_property`.
+        #   @option options [Object] :default The value this property
+        #     will return if the user does not set one. If this is `lazy`, it will
+        #     be run in the context of the instance (and able to access other
+        #     properties).
+        #   @option options [Boolean] :desired_state `true` if this property is
+        #     part of desired state. Defaults to `true`.
+        #   @option options [Boolean] :identity `true` if this property
+        #     is part of object identity. Defaults to `false`.
+        #
+        # @example Bare property
+        #   property :x
+        #
+        # @example With just a type
+        #   property :x, String
+        #
+        # @example With just options
+        #   property :x, default: 'hi'
+        #
+        # @example With type and options
+        #   property :x, String, default: 'hi'
+        #
+        def property(name, type = NOT_PASSED, **options)
+          name = name.to_sym
+
+          options.each { |k, v| options[k.to_sym] = v if k.is_a?(String) }
+
+          options[:instance_variable_name] = :"@#{name}" if !options.has_key?(:instance_variable_name)
+          options.merge!(name: name, declared_in: self)
+
+          if type == NOT_PASSED
+            # If a type is not passed, the property derives from the
+            # superclass property (if any)
+            if properties.has_key?(name)
+              property = properties[name].derive(**options)
+            else
+              property = property_type(**options)
+            end
+
+          # If a Property is specified, derive a new one from that.
+          elsif type.is_a?(Property) || (type.is_a?(Class) && type <= Property)
+            property = type.derive(**options)
+
+          # If a primitive type was passed, combine it with "is"
+          else
+            if options[:is]
+              options[:is] = ([ type ] + [ options[:is] ]).flatten(1)
+            else
+              options[:is] = type
+            end
+            property = property_type(**options)
+          end
+
+          local_properties = properties(false)
+          local_properties[name] = property
+
+          property.emit_dsl
+        end
+
+        #
+        # Create a reusable property type that can be used in multiple properties
+        # in different resources.
+        #
+        # @param options [Hash<Symbol,Object>] Validation options. see #property for
+        #   the list of options.
+        #
+        # @example
+        #   property_type(default: 'hi')
+        #
+        def property_type(**options)
+          Property.derive(**options)
+        end
+
+        #
+        # Create a lazy value for assignment to a default value.
+        #
+        # @param block The block to run when the value is retrieved.
+        #
+        # @return [Chef::DelayedEvaluator] The lazy value
+        #
+        def lazy(&block)
+          DelayedEvaluator.new(&block)
+        end
+
+        #
+        # Get or set the list of desired state properties for this resource.
+        #
+        # State properties are properties that describe the desired state
+        # of the system, such as file permissions or ownership.
+        # In general, state properties are properties that could be populated by
+        # examining the state of the system (e.g., File.stat can tell you the
+        # permissions on an existing file). Contrarily, properties that are not
+        # "state properties" usually modify the way Chef itself behaves, for example
+        # by providing additional options for a package manager to use when
+        # installing a package.
+        #
+        # This list is used by the Chef client auditing system to extract
+        # information from resources to describe changes made to the system.
+        #
+        # This method is unnecessary when declaring properties with `property`;
+        # properties are added to state_properties by default, and can be turned off
+        # with `desired_state: false`.
+        #
+        # ```ruby
+        # property :x # part of desired state
+        # property :y, desired_state: false # not part of desired state
+        # ```
+        #
+        # @param names [Array<Symbol>] A list of property names to set as desired
+        #   state.
+        #
+        # @return [Array<Property>] All properties in desired state.
+        #
+        def state_properties(*names)
+          if !names.empty?
+            names = names.map { |name| name.to_sym }.uniq
+
+            local_properties = properties(false)
+            # Add new properties to the list.
+            names.each do |name|
+              property = properties[name]
+              if !property
+                self.property name, instance_variable_name: false, desired_state: true
+              elsif !property.desired_state?
+                self.property name, desired_state: true
+              end
+            end
+
+            # If state_attrs *excludes* something which is currently desired state,
+            # mark it as desired_state: false.
+            local_properties.each do |name, property|
+              if property.desired_state? && !names.include?(name)
+                self.property name, desired_state: false
+              end
+            end
+          end
+
+          properties.values.select { |property| property.desired_state? }
+        end
+
+        #
+        # Set the identity of this resource to a particular set of properties.
+        #
+        # This drives #identity, which returns data that uniquely refers to a given
+        # resource on the given node (in such a way that it can be correlated
+        # across Chef runs).
+        #
+        # This method is unnecessary when declaring properties with `property`;
+        # properties can be added to identity during declaration with
+        # `identity: true`.
+        #
+        # ```ruby
+        # property :x, identity: true # part of identity
+        # property :y # not part of identity
+        # ```
+        #
+        # If no properties are marked as identity, "name" is considered the identity.
+        #
+        # @param names [Array<Symbol>] A list of property names to set as the identity.
+        #
+        # @return [Array<Property>] All identity properties.
+        #
+        def identity_properties(*names)
+          if !names.empty?
+            names = names.map { |name| name.to_sym }
+
+            # Add or change properties that are not part of the identity.
+            names.each do |name|
+              property = properties[name]
+              if !property
+                self.property name, instance_variable_name: false, identity: true
+              elsif !property.identity?
+                self.property name, identity: true
+              end
+            end
+
+            # If identity_properties *excludes* something which is currently part of
+            # the identity, mark it as identity: false.
+            properties.each do |name, property|
+              if property.identity? && !names.include?(name)
+
+                self.property name, identity: false
+              end
+            end
+          end
+
+          result = properties.values.select { |property| property.identity? }
+          result = [ properties[:name] ] if result.empty?
+          result
+        end
+
+        def included(other)
+          other.extend ClassMethods
+        end
+      end
+
+      def self.included(other)
+        other.extend ClassMethods
+      end
+
+      include Chef::Mixin::ParamsValidate
+
+      #
+      # Whether this property has been set (or whether it has a default that has
+      # been retrieved).
+      #
+      # @param name [Symbol] The name of the property.
+      # @return [Boolean] `true` if the property has been set.
+      #
+      def property_is_set?(name)
+        property = self.class.properties[name.to_sym]
+        raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
+        property.is_set?(self)
+      end
+
+      #
+      # Clear this property as if it had never been set. It will thereafter return
+      # the default.
+      # been retrieved).
+      #
+      # @param name [Symbol] The name of the property.
+      #
+      def reset_property(name)
+        property = self.class.properties[name.to_sym]
+        raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
+        property.reset(self)
+      end
+    end
+  end
+end
diff --git a/lib/chef/mixin/provides.rb b/lib/chef/mixin/provides.rb
index bc25af6..34a078c 100644
--- a/lib/chef/mixin/provides.rb
+++ b/lib/chef/mixin/provides.rb
@@ -1,32 +1,26 @@
 
-require 'chef/mixin/descendants_tracker'
+require "chef/mixin/descendants_tracker"
 
 class Chef
   module Mixin
     module Provides
+      # TODO no longer needed, remove or deprecate?
       include Chef::Mixin::DescendantsTracker
 
-      def node_map
-        @node_map ||= Chef::NodeMap.new
+      def provides(short_name, opts = {}, &block)
+        raise NotImplementedError, :provides
       end
 
-      def provides(short_name, opts={}, &block)
-        if !short_name.kind_of?(Symbol)
-          # YAGNI: this is probably completely unnecessary and can be removed?
-          Chef::Log.deprecation "Passing a non-Symbol to Chef::Resource#provides will be removed"
-          if short_name.kind_of?(String)
-            short_name.downcase!
-            short_name.gsub!(/\s/, "_")
-          end
-          short_name = short_name.to_sym
-        end
-        node_map.set(short_name, true, opts, &block)
+      # Check whether this resource provides the resource_name DSL for the given
+      # node.  TODO remove this when we stop checking unregistered things.
+      def provides?(node, resource)
+        raise NotImplementedError, :provides?
       end
 
-      # provides a node on the resource (early binding)
-      def provides?(node, resource_name)
-        resource_name = resource_name.resource_name if resource_name.is_a?(Chef::Resource)
-        node_map.get(node, resource_name)
+      # Get the list of recipe DSL this resource is responsible for on the given
+      # node.
+      def provided_as(node)
+        node_map.list(node)
       end
     end
   end
diff --git a/lib/chef/mixin/proxified_socket.rb b/lib/chef/mixin/proxified_socket.rb
new file mode 100644
index 0000000..c3b0f76
--- /dev/null
+++ b/lib/chef/mixin/proxified_socket.rb
@@ -0,0 +1,38 @@
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "proxifier"
+
+class Chef
+  module Mixin
+    module ProxifiedSocket
+
+      # This looks at the environment variables and leverages Proxifier to
+      # make the TCPSocket respect ENV['https_proxy'] or ENV['http_proxy'] if
+      # they are present
+      def proxified_socket(host, port)
+        proxy = ENV["https_proxy"] || ENV["http_proxy"] || false
+        if proxy
+          Proxifier.Proxy(proxy, no_proxy: ENV["no_proxy"]).open(host, port)
+        else
+          TCPSocket.new(host, port)
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mixin/recipe_definition_dsl_core.rb b/lib/chef/mixin/recipe_definition_dsl_core.rb
index 704ee16..6a9b12d 100644
--- a/lib/chef/mixin/recipe_definition_dsl_core.rb
+++ b/lib/chef/mixin/recipe_definition_dsl_core.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,7 @@
 # This constant (module name) will eventually be deprecated and then removed.
 ###
 
-require 'chef/mixin/deprecation'
+require "chef/mixin/deprecation"
 
 class Chef
   module Mixin
diff --git a/lib/chef/mixin/securable.rb b/lib/chef/mixin/securable.rb
index aaedf0b..af3e101 100644
--- a/lib/chef/mixin/securable.rb
+++ b/lib/chef/mixin/securable.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,46 +20,45 @@ class Chef
   module Mixin
     module Securable
 
-      def owner(arg=nil)
+      def owner(arg = nil)
         set_or_return(
           :owner,
           arg,
-          :regex => Chef::Config[:user_valid_regex]
+          :regex => Chef::Config[:user_valid_regex],
         )
       end
 
       alias :user :owner
 
-      def group(arg=nil)
+      def group(arg = nil)
         set_or_return(
           :group,
           arg,
-          :regex => Chef::Config[:group_valid_regex]
+          :regex => Chef::Config[:group_valid_regex],
         )
       end
 
-      def mode(arg=nil)
+      def mode(arg = nil)
         set_or_return(
           :mode,
           arg,
           :callbacks => {
             "not in valid numeric range" => lambda { |m|
               if m.kind_of?(String)
-                m =~ /^0/ || m="0#{m}"
+                m =~ /^0/ || m = "0#{m}"
               end
 
               # Windows does not support the sticky or setuid bits
               if Chef::Platform.windows?
-                Integer(m)<=0777 && Integer(m)>=0
+                Integer(m) <= 0777 && Integer(m) >= 0
               else
-                Integer(m)<=07777 && Integer(m)>=0
+                Integer(m) <= 07777 && Integer(m) >= 0
               end
-            },
-          }
+            }
+          },
         )
       end
 
-
       #==WindowsMacros
       # Defines methods for adding attributes to a chef resource to describe
       # Windows file security metadata.
@@ -108,29 +107,28 @@ class Chef
         # * `:one_level_deep` (optional): Boolean
         #
         def rights_attribute(name)
-
           # equivalent to something like:
           # def rights(permissions=nil, principals=nil, args_hash=nil)
-          define_method(name) do |permissions=nil, principals=nil, args_hash=nil|
-            rights = self.instance_variable_get("@#{name.to_s}".to_sym)
+          define_method(name) do |permissions = nil, principals = nil, args_hash = nil|
+            rights = self.instance_variable_get("@#{name}".to_sym)
             unless permissions.nil?
               input = {
                 :permissions => permissions,
-                :principals => principals
+                :principals => principals,
               }
               input.merge!(args_hash) unless args_hash.nil?
 
-              validations = {:permissions => { :required => true },
-                             :principals => { :required => true, :kind_of => [String, Array] },
-                             :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ]},
-                             :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
-                             :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] }
+              validations = { :permissions => { :required => true },
+                              :principals => { :required => true, :kind_of => [String, Array] },
+                              :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ] },
+                              :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] },
+                              :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] },
                             }
               validate(input, validations)
 
               [ permissions ].flatten.each do |permission|
                 if permission.is_a?(Integer)
-                  if permission < 0 || permission > 1<<32
+                  if permission < 0 || permission > 1 << 32
                     raise ArgumentError, "permissions flags must be positive and <= 32 bits (#{permission})"
                   end
                 elsif !([:full_control, :modify, :read_execute, :read, :write].include?(permission.to_sym))
@@ -158,7 +156,7 @@ class Chef
             set_or_return(
               name,
               rights,
-              {}
+              {},
             )
           end
         end
@@ -169,12 +167,11 @@ class Chef
       # including class
       module WindowsSecurableAttributes
 
-
-        def inherits(arg=nil)
+        def inherits(arg = nil)
           set_or_return(
             :inherits,
             arg,
-            :kind_of => [ TrueClass, FalseClass ]
+            :kind_of => [ TrueClass, FalseClass ],
           )
         end
       end
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 5290230..d3598f6 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'mixlib/shellout'
+require "mixlib/shellout"
 
 class Chef
   module Mixin
@@ -35,15 +35,15 @@ class Chef
           env_key = options.has_key?(:env) ? :env : :environment
           options[env_key] ||= {}
           options[env_key] = options[env_key].dup
-          options[env_key]['LC_ALL'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LC_ALL')
-          options[env_key]['LANGUAGE'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LANGUAGE')
-          options[env_key]['LANG'] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?('LANG')
+          options[env_key]["LC_ALL"] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?("LC_ALL")
+          options[env_key]["LANGUAGE"] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?("LANGUAGE")
+          options[env_key]["LANG"] ||= Chef::Config[:internal_locale] unless options[env_key].has_key?("LANG")
           args << options
         else
           args << { :environment => {
-            'LC_ALL' => Chef::Config[:internal_locale],
-            'LANGUAGE' => Chef::Config[:internal_locale],
-            'LANG' => Chef::Config[:internal_locale],
+            "LC_ALL" => Chef::Config[:internal_locale],
+            "LANGUAGE" => Chef::Config[:internal_locale],
+            "LANG" => Chef::Config[:internal_locale],
           } }
         end
 
@@ -114,4 +114,4 @@ class Chef
 end
 
 # Break circular dep
-require 'chef/config'
+require "chef/config"
diff --git a/lib/chef/mixin/subclass_directive.rb b/lib/chef/mixin/subclass_directive.rb
new file mode 100644
index 0000000..397a37c
--- /dev/null
+++ b/lib/chef/mixin/subclass_directive.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module Mixin
+    module SubclassDirective
+      def subclass_directive(sym)
+        define_singleton_method sym do
+          instance_variable_set(:"@#{sym}", true)
+        end
+
+        define_singleton_method :"#{sym}?" do
+          !!instance_variable_get(:"@#{sym}")
+        end
+
+        define_method :"#{sym}?" do
+          self.class.send(:"#{sym}?")
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/mixin/template.rb b/lib/chef/mixin/template.rb
index d705a9e..c423cca 100644
--- a/lib/chef/mixin/template.rb
+++ b/lib/chef/mixin/template.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'erubis'
+require "tempfile"
+require "erubis"
 
 class Chef
   module Mixin
@@ -44,6 +44,52 @@ class Chef
 
         attr_reader :_extension_modules
 
+        #
+        # Helpers for adding context of which resource is rendering the template (CHEF-5012)
+        #
+
+        # name of the cookbook containing the template resource, e.g.:
+        #   test
+        #
+        # @return [String] cookbook name
+        attr_reader :cookbook_name
+
+        # name of the recipe containing the template resource, e.g.:
+        #   default
+        #
+        # @return [String] recipe name
+        attr_reader :recipe_name
+
+        # string representation of the line in the recipe containing the template resource, e.g.:
+        #   /Users/lamont/solo/cookbooks/test/recipes/default.rb:2:in `from_file'
+        #
+        # @return [String] recipe line
+        attr_reader :recipe_line_string
+
+        # path to the recipe containing the template resource, e.g.:
+        #   /Users/lamont/solo/cookbooks/test/recipes/default.rb
+        #
+        # @return [String] recipe path
+        attr_reader :recipe_path
+
+        # line in the recipe containing the template reosurce, e.g.:
+        #   2
+        #
+        # @return [String] recipe line
+        attr_reader :recipe_line
+
+        # name of the template source itself, e.g.:
+        #   foo.erb
+        #
+        # @return [String] template name
+        attr_reader :template_name
+
+        # path to the template source itself, e.g.:
+        #   /Users/lamont/solo/cookbooks/test/templates/default/foo.erb
+        #
+        # @return [String] template path
+        attr_reader :template_path
+
         def initialize(variables)
           super
           @_extension_modules = []
@@ -59,7 +105,7 @@ class Chef
         def node
           return @node if @node
           raise "Could not find a value for node. If you are explicitly setting variables in a template, " +
-                "include a node variable if you plan to use it."
+            "include a node variable if you plan to use it."
         end
 
         #
@@ -89,6 +135,7 @@ class Chef
           raise "You cannot render partials in this context" unless @template_finder
 
           partial_variables = options.delete(:variables) || _public_instance_variables
+          partial_variables[:template_finder] = @template_finder
           partial_context = self.class.new(partial_variables)
           partial_context._extend_modules(@_extension_modules)
 
@@ -129,7 +176,7 @@ class Chef
           # this template.
 
           if Chef::Platform.windows?
-            output = output.gsub(/\r?\n/,"\r\n")
+            output = output.gsub(/\r?\n/, "\r\n")
           end
 
           output
@@ -177,7 +224,7 @@ class Chef
         end
 
         def line_number
-          @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ }
+          @line_number ||= $1.to_i if original_exception.backtrace.find { |line| line =~ /\(erubis\):(\d+)/ }
         end
 
         def source_location
@@ -198,7 +245,7 @@ class Chef
             contextual_lines = lines[beginning_line, source_size]
             output = []
             contextual_lines.each_with_index do |line, index|
-              line_number = (index+beginning_line+1).to_s.rjust(3)
+              line_number = (index + beginning_line + 1).to_s.rjust(3)
               output << "#{line_number}: #{line}"
             end
             output.join("\n")
diff --git a/lib/chef/mixin/unformatter.rb b/lib/chef/mixin/unformatter.rb
new file mode 100644
index 0000000..7dad56b
--- /dev/null
+++ b/lib/chef/mixin/unformatter.rb
@@ -0,0 +1,32 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module Mixin
+    module Unformatter
+
+      def write(message)
+        data = message.match(/(\[.+?\] )?([\w]+):(.*)$/)
+        self.send(data[2].downcase.chomp.to_sym, data[3].strip)
+      rescue NoMethodError
+        self.send(:info, message)
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mixin/uris.rb b/lib/chef/mixin/uris.rb
new file mode 100644
index 0000000..24e8a4f
--- /dev/null
+++ b/lib/chef/mixin/uris.rb
@@ -0,0 +1,43 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "uri"
+
+class Chef
+  module Mixin
+    module Uris
+      # uri_scheme? returns true if the string starts with
+      # scheme://
+      # For example, it will match http://foo.bar.com
+      def uri_scheme?(source)
+        # From open-uri
+        !!(%r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ source)
+      end
+
+      def as_uri(source)
+        begin
+          URI.parse(source)
+        rescue URI::InvalidURIError
+          Chef::Log.warn("#{source} was an invalid URI. Trying to escape invalid characters")
+          URI.parse(URI.escape(source))
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mixin/which.rb b/lib/chef/mixin/which.rb
index 4179c97..de446d9 100644
--- a/lib/chef/mixin/which.rb
+++ b/lib/chef/mixin/which.rb
@@ -1,6 +1,6 @@
 #--
 # Author:: Lamont Granquist <lamont at getchef.io>
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,14 @@ class Chef
       def which(cmd, opts = {})
         extra_path =
           if opts[:extra_path].nil?
-            [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+            [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
           else
             [ opts[:extra_path] ].flatten
           end
-        paths = ENV['PATH'].split(File::PATH_SEPARATOR) + extra_path
+        paths = ENV["PATH"].split(File::PATH_SEPARATOR) + extra_path
         paths.each do |path|
           filename = File.join(path, cmd)
-          return filename if File.executable?(filename)
+          return filename if File.executable?(Chef.path_to(filename))
         end
         false
       end
diff --git a/lib/chef/mixin/why_run.rb b/lib/chef/mixin/why_run.rb
index d3acea5..b2aa594 100644
--- a/lib/chef/mixin/why_run.rb
+++ b/lib/chef/mixin/why_run.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Dan DeLeo ( <dan at opscode.com> )
-# Author:: Marc Paradise ( <marc at opscode.com> )
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Dan DeLeo ( <dan at chef.io> )
+# Author:: Marc Paradise ( <marc at chef.io> )
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -222,7 +222,6 @@ class Chef
             @assertion_failed
           end
 
-
           # Runs the assertion/assumption logic. Will raise an Exception of the
           # type specified in #failure_message (or AssertionFailure by default)
           # if the requirement is not met and Chef is not running in why run
@@ -247,7 +246,7 @@ class Chef
 
         def initialize(resource, run_context)
           @resource, @run_context = resource, run_context
-          @assertions = Hash.new {|h,k| h[k] = [] }
+          @assertions = Hash.new { |h, k| h[k] = [] }
           @blocked_actions = []
         end
 
@@ -313,7 +312,7 @@ class Chef
         def assert(*actions)
           assertion = Assertion.new
           yield assertion
-          actions.each {|action| @assertions[action] << assertion }
+          actions.each { |action| @assertions[action] << assertion }
         end
 
         # Run the assertion and assumption logic.
@@ -322,7 +321,7 @@ class Chef
             a.run(action, events, @resource)
             if a.assertion_failed? and a.block_action?
               @blocked_actions << action
-              return
+              break
             end
           end
         end
diff --git a/lib/chef/mixin/wide_string.rb b/lib/chef/mixin/wide_string.rb
new file mode 100644
index 0000000..4566bdd
--- /dev/null
+++ b/lib/chef/mixin/wide_string.rb
@@ -0,0 +1,72 @@
+#
+# Author:: Jay Mundrawala(<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  module Mixin
+    module WideString
+
+      def wstring(str)
+        if str.nil? || str.encoding == Encoding::UTF_16LE
+          str
+        else
+          utf8_to_wide(str)
+        end
+      end
+
+      def utf8_to_wide(ustring)
+        # ensure it is actually UTF-8
+        # Ruby likes to mark binary data as ASCII-8BIT
+        ustring = (ustring + "").force_encoding("UTF-8") if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
+
+        # ensure we have the double-null termination Windows Wide likes
+        ustring = ustring + "\000\000" if ustring.length == 0 or ustring[-1].chr != "\000"
+
+        # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
+        ustring = begin
+          if ustring.respond_to?(:encode)
+            ustring.encode("UTF-16LE")
+          else
+            require "iconv"
+            Iconv.conv("UTF-16LE", "UTF-8", ustring)
+          end
+        end
+        ustring
+      end
+
+      def wide_to_utf8(wstring)
+        # ensure it is actually UTF-16LE
+        # Ruby likes to mark binary data as ASCII-8BIT
+        wstring = wstring.force_encoding("UTF-16LE") if wstring.respond_to?(:force_encoding)
+
+        # encode it all as UTF-8
+        wstring = begin
+          if wstring.respond_to?(:encode)
+            wstring.encode("UTF-8")
+          else
+            require "iconv"
+            Iconv.conv("UTF-8", "UTF-16LE", wstring)
+          end
+        end
+        # remove trailing CRLF and NULL characters
+        wstring.strip!
+        wstring
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/mixin/windows_architecture_helper.rb b/lib/chef/mixin/windows_architecture_helper.rb
index a0ac34f..5f8d3e3 100644
--- a/lib/chef/mixin/windows_architecture_helper.rb
+++ b/lib/chef/mixin/windows_architecture_helper.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,15 @@
 # limitations under the License.
 #
 
-
-require 'chef/exceptions'
-require 'chef/platform/query_helpers'
-require 'win32/api' if Chef::Platform.windows?
-require 'chef/win32/api/process' if Chef::Platform.windows?
-require 'chef/win32/api/error' if Chef::Platform.windows?
+require "chef/exceptions"
+require "chef/platform/query_helpers"
+require "chef/win32/process" if Chef::Platform.windows?
+require "chef/win32/system" if Chef::Platform.windows?
 
 class Chef
   module Mixin
     module WindowsArchitectureHelper
 
-      if Chef::Platform.windows?
-        include Chef::ReservedNames::Win32::API::Process
-        include Chef::ReservedNames::Win32::API::Error
-      end
-
       def node_windows_architecture(node)
         node[:kernel][:machine].to_sym
       end
@@ -42,18 +35,31 @@ class Chef
           is_i386_process_on_x86_64_windows?
       end
 
-      def with_os_architecture(node)
+      def forced_32bit_override_required?(node, desired_architecture)
+        desired_architecture == :i386 &&
+          node_windows_architecture(node) == :x86_64 &&
+          !is_i386_process_on_x86_64_windows?
+      end
+
+      def wow64_directory
+        Chef::ReservedNames::Win32::System.get_system_wow64_directory
+      end
+
+      def with_os_architecture(node, architecture: nil)
         node ||= begin
-          os_arch = ENV['PROCESSOR_ARCHITEW6432'] ||
-                    ENV['PROCESSOR_ARCHITECTURE']
+          os_arch = ENV["PROCESSOR_ARCHITEW6432"] ||
+                    ENV["PROCESSOR_ARCHITECTURE"]
           Hash.new.tap do |n|
             n[:kernel] = Hash.new
-            n[:kernel][:machine] = os_arch == 'AMD64' ? :x86_64 : :i386
+            n[:kernel][:machine] = os_arch == "AMD64" ? :x86_64 : :i386
           end
         end
+
+        architecture ||= node_windows_architecture(node)
+
         wow64_redirection_state = nil
 
-        if wow64_architecture_override_required?(node, node_windows_architecture(node))
+        if wow64_architecture_override_required?(node, architecture)
           wow64_redirection_state = disable_wow64_file_redirection(node)
         end
 
@@ -85,49 +91,21 @@ class Chef
 
       def is_i386_process_on_x86_64_windows?
         if Chef::Platform.windows?
-          is_64_bit_process_result = FFI::MemoryPointer.new(:int)
-
-          # The return value of IsWow64Process is nonzero value if the API call succeeds.
-          # The result data are returned in the last parameter, not the return value.
-          call_succeeded = IsWow64Process(GetCurrentProcess(), is_64_bit_process_result)
-
-          # The result is nonzero if IsWow64Process's calling process, in the case here
-          # this process, is running under WOW64, i.e. the result is nonzero if this
-          # process is 32-bit (aka :i386).
-          result = (call_succeeded != 0) && (is_64_bit_process_result.get_int(0) != 0)
+          Chef::ReservedNames::Win32::Process.is_wow64_process
         else
           false
         end
       end
 
       def disable_wow64_file_redirection( node )
-        original_redirection_state = ['0'].pack('P')
-
         if ( ( node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?)
-          win32_wow_64_disable_wow_64_fs_redirection =
-            ::Win32::API.new('Wow64DisableWow64FsRedirection', 'P', 'L', 'kernel32')
-
-          succeeded = win32_wow_64_disable_wow_64_fs_redirection.call(original_redirection_state)
-
-          if succeeded == 0
-            raise Win32APIError "Failed to disable Wow64 file redirection"
-          end
-
+          Chef::ReservedNames::Win32::System.wow64_disable_wow64_fs_redirection
         end
-
-        original_redirection_state
       end
 
       def restore_wow64_file_redirection( node, original_redirection_state )
         if ( (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?)
-          win32_wow_64_revert_wow_64_fs_redirection =
-            ::Win32::API.new('Wow64RevertWow64FsRedirection', 'P', 'L', 'kernel32')
-
-          succeeded = win32_wow_64_revert_wow_64_fs_redirection.call(original_redirection_state)
-
-          if succeeded == 0
-            raise Win32APIError "Failed to revert Wow64 file redirection"
-          end
+          Chef::ReservedNames::Win32::System.wow64_revert_wow64_fs_redirection(original_redirection_state)
         end
       end
 
diff --git a/lib/chef/mixin/windows_env_helper.rb b/lib/chef/mixin/windows_env_helper.rb
index 490b235..b2e08ed 100644
--- a/lib/chef/mixin/windows_env_helper.rb
+++ b/lib/chef/mixin/windows_env_helper.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,17 @@
 # limitations under the License.
 #
 
-
-require 'chef/exceptions'
-require 'chef/platform/query_helpers'
-require 'chef/win32/error' if Chef::Platform.windows?
-require 'chef/win32/api/system' if Chef::Platform.windows?
+require "chef/exceptions"
+require "chef/mixin/wide_string"
+require "chef/platform/query_helpers"
+require "chef/win32/error" if Chef::Platform.windows?
+require "chef/win32/api/system" if Chef::Platform.windows?
+require "chef/win32/api/unicode" if Chef::Platform.windows?
 
 class Chef
   module Mixin
     module WindowsEnvHelper
+      include Chef::Mixin::WideString
 
       if Chef::Platform.windows?
         include Chef::ReservedNames::Win32::API::System
@@ -39,7 +41,16 @@ class Chef
 
       def broadcast_env_change
         flags = SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG
-        SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string('Environment').address, flags, 5000, nil)
+        # for why two calls, see:
+        # http://stackoverflow.com/questions/4968373/why-doesnt-sendmessagetimeout-update-the-environment-variables
+        if ( SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string("Environment").address, flags, 5000, nil) == 0 )
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        if ( SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, FFI::MemoryPointer.from_string(
+            utf8_to_wide("Environment")
+        ).address, flags, 5000, nil) == 0 )
+          Chef::ReservedNames::Win32::Error.raise!
+        end
       end
 
       def expand_path(path)
diff --git a/lib/chef/mixin/xml_escape.rb b/lib/chef/mixin/xml_escape.rb
index ceb45df..afb0d09 100644
--- a/lib/chef/mixin/xml_escape.rb
+++ b/lib/chef/mixin/xml_escape.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2005 Sam Ruby
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2005-2016, Sam Ruby
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,7 @@
 #
 # Thanks, Sam!
 #
-# Copyright (c) 2005, Sam Ruby
+# Copyright 2005-2016, Sam Ruby
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -46,10 +46,10 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-require 'chef/log'
+require "chef/log"
 
 begin
-  require 'fast_xs'
+  require "fast_xs"
 rescue LoadError
   Chef::Log.info "The fast_xs gem is not installed, slower pure ruby XML escaping will be used."
 end
@@ -93,9 +93,9 @@ class Chef
 
         # http://www.w3.org/TR/REC-xml/#dt-chardata
         PREDEFINED = {
-          38 => '&', # ampersand
-          60 => '<',  # left angle bracket
-          62 => '>'  # right angle bracket
+          38 => "&", # ampersand
+          60 => "<",  # left angle bracket
+          62 => ">" # right angle bracket
         }
 
         # http://www.w3.org/TR/REC-xml/#charsets
@@ -104,9 +104,9 @@ class Chef
 
         def xml_escape(unescaped_str)
           begin
-            unescaped_str.unpack("U*").map {|char| xml_escape_char!(char)}.join
+            unescaped_str.unpack("U*").map { |char| xml_escape_char!(char) }.join
           rescue
-            unescaped_str.unpack("C*").map {|char| xml_escape_char!(char)}.join
+            unescaped_str.unpack("C*").map { |char| xml_escape_char!(char) }.join
           end
         end
 
@@ -114,8 +114,8 @@ class Chef
 
         def xml_escape_char!(char)
           char = CP1252[char] || char
-          char = 42 unless VALID.detect {|range| range.include? char}
-          char = PREDEFINED[char] || (char<128 ? char.chr : "&##{char};")
+          char = 42 unless VALID.detect { |range| range.include? char }
+          char = PREDEFINED[char] || (char < 128 ? char.chr : "&##{char};")
         end
       end
 
diff --git a/lib/chef/mixins.rb b/lib/chef/mixins.rb
index 17be162..b980e81 100644
--- a/lib/chef/mixins.rb
+++ b/lib/chef/mixins.rb
@@ -1,14 +1,13 @@
-require 'chef/mixin/shell_out'
-require 'chef/mixin/checksum'
-require 'chef/mixin/command'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/create_path'
-require 'chef/mixin/deep_merge'
-require 'chef/mixin/enforce_ownership_and_permissions'
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/path_sanity'
-require 'chef/mixin/template'
-require 'chef/mixin/securable'
-require 'chef/mixin/xml_escape'
-
+require "chef/mixin/shell_out"
+require "chef/mixin/checksum"
+require "chef/mixin/command"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/create_path"
+require "chef/mixin/deep_merge"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
+require "chef/mixin/path_sanity"
+require "chef/mixin/template"
+require "chef/mixin/securable"
+require "chef/mixin/xml_escape"
diff --git a/lib/chef/monkey_patches/net-ssh-multi.rb b/lib/chef/monkey_patches/net-ssh-multi.rb
index 0f4dd66..b0d05a0 100644
--- a/lib/chef/monkey_patches/net-ssh-multi.rb
+++ b/lib/chef/monkey_patches/net-ssh-multi.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,11 +34,11 @@
 #
 # See: https://github.com/net-ssh/net-ssh-multi/pull/4
 
-require 'net/ssh/multi/version'
+require "net/ssh/multi/version"
 
 if Net::SSH::Multi::Version::STRING == "1.1.0" || Net::SSH::Multi::Version::STRING == "1.2.0"
 
-  require 'net/ssh/multi'
+  require "net/ssh/multi"
 
   module Net
     module SSH
@@ -47,14 +47,14 @@ if Net::SSH::Multi::Version::STRING == "1.1.0" || Net::SSH::Multi::Version::STRI
 
           # Make sure that server returns false if the ssh connection
           # has failed.
-          def busy?(include_invisible=false)
+          def busy?(include_invisible = false)
             !failed? && session && session.busy?(include_invisible)
           end
 
         end
 
         class Session
-          def next_session(server, force=false) #:nodoc:
+          def next_session(server, force = false) #:nodoc:
             # don't retry a failed attempt
             return nil if server.failed?
 
diff --git a/lib/chef/monkey_patches/net_http.rb b/lib/chef/monkey_patches/net_http.rb
index 9c8044a..c1cb87b 100644
--- a/lib/chef/monkey_patches/net_http.rb
+++ b/lib/chef/monkey_patches/net_http.rb
@@ -5,7 +5,7 @@ module ChefNetHTTPExceptionExtensions
   attr_accessor :chef_rest_request
 end
 
-require 'net/http'
+require "net/http"
 module Net
   class HTTPError
     include ChefNetHTTPExceptionExtensions
@@ -21,7 +21,7 @@ module Net
   end
 end
 
-if Net::HTTP.instance_methods.map {|m| m.to_s}.include?("proxy_uri")
+if Net::HTTP.instance_methods.map { |m| m.to_s }.include?("proxy_uri")
   begin
     # Ruby 2.0 changes the way proxy support is implemented in Net::HTTP.
     # The implementation does not work correctly with IPv6 literals because it
diff --git a/lib/chef/monkey_patches/webrick-utils.rb b/lib/chef/monkey_patches/webrick-utils.rb
new file mode 100644
index 0000000..71bed2b
--- /dev/null
+++ b/lib/chef/monkey_patches/webrick-utils.rb
@@ -0,0 +1,51 @@
+require "webrick/utils"
+
+module WEBrick
+  module Utils
+    ##
+    # Creates TCP server sockets bound to +address+:+port+ and returns them.
+    #
+    # It will create IPV4 and IPV6 sockets on all interfaces.
+    #
+    # NOTE: We need to monkey patch this method because
+    # create_listeners on Windows with Ruby > 2.0.0 does not
+    # raise an error if we're already listening on a port.
+    #
+    def create_listeners(address, port, logger = nil)
+      #
+      # utils.rb -- Miscellaneous utilities
+      #
+      # Author: IPR -- Internet Programming with Ruby -- writers
+      # Copyright 2001-2016, TAKAHASHI Masayoshi, GOTOU Yuuzou
+      # Copyright 2002-2016, Internet Programming with Ruby writers. All rights
+      # reserved.
+      #
+      # $IPR: utils.rb,v 1.10 2003/02/16 22:22:54 gotoyuzo Exp $
+      unless port
+        raise ArgumentError, "must specify port"
+      end
+      res = Socket::getaddrinfo(address, port,
+                                Socket::AF_UNSPEC,   # address family
+                                Socket::SOCK_STREAM, # socket type
+                                0,                   # protocol
+                                Socket::AI_PASSIVE)  # flag
+      last_error = nil
+      sockets = []
+      res.each {|ai|
+        begin
+          logger.debug("TCPServer.new(#{ai[3]}, #{port})") if logger
+          sock = TCPServer.new(ai[3], port)
+          port = sock.addr[1] if port == 0
+          Utils::set_close_on_exec(sock)
+          sockets << sock
+        rescue => ex
+          logger.warn("TCPServer Error: #{ex}") if logger
+          last_error = ex
+        end
+      }
+      raise last_error if sockets.empty?
+      return sockets
+    end
+    module_function :create_listeners
+  end
+end
diff --git a/lib/chef/monkey_patches/win32/registry.rb b/lib/chef/monkey_patches/win32/registry.rb
new file mode 100644
index 0000000..a9333bd
--- /dev/null
+++ b/lib/chef/monkey_patches/win32/registry.rb
@@ -0,0 +1,72 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api/registry"
+require "chef/win32/unicode"
+require "win32/registry"
+
+module Win32
+  class Registry
+
+    module API
+
+      extend Chef::ReservedNames::Win32::API::Registry
+
+      module_function
+
+      if RUBY_VERSION =~ /^2\.1/
+        # ::Win32::Registry#delete_value is broken in Ruby 2.1 (up to Ruby 2.1.6).
+        # This should be resolved in a later release (see note #9 in link below).
+        # https://bugs.ruby-lang.org/issues/10820
+        def DeleteValue(hkey, name)
+          check RegDeleteValueW(hkey, name.to_wstring)
+        end
+      end
+
+      # ::Win32::Registry#delete_key uses RegDeleteKeyW. We need to use
+      # RegDeleteKeyExW to properly support WOW64 systems.
+      def DeleteKey(hkey, name)
+        check RegDeleteKeyExW(hkey, name.to_wstring, 0, 0)
+      end
+
+    end
+
+    if RUBY_VERSION =~ /^2.1/
+      # ::Win32::Registry#write does not correctly handle data in Ruby 2.1 (up to Ruby 2.1.6).
+      # https://bugs.ruby-lang.org/issues/11439
+      def write(name, type, data)
+        case type
+        when REG_SZ, REG_EXPAND_SZ
+          data = data.to_s.encode(WCHAR) + WCHAR_NUL
+        when REG_MULTI_SZ
+          data = data.to_a.map { |s| s.encode(WCHAR) }.join(WCHAR_NUL) << WCHAR_NUL << WCHAR_NUL
+        when REG_BINARY
+          data = data.to_s
+        when REG_DWORD
+          data = API.packdw(data.to_i)
+        when REG_DWORD_BIG_ENDIAN
+          data = [data.to_i].pack("N")
+        when REG_QWORD
+          data = API.packqw(data.to_i)
+        else
+          raise TypeError, "Unsupported type #{type}"
+        end
+        API.SetValue(@hkey, name, type, data, data.bytesize)
+      end
+    end
+  end
+end
diff --git a/lib/chef/monologger.rb b/lib/chef/monologger.rb
index f7d226f..77ca54d 100644
--- a/lib/chef/monologger.rb
+++ b/lib/chef/monologger.rb
@@ -1,5 +1,5 @@
-require 'logger'
-require 'pp'
+require "logger"
+require "pp"
 
 #== MonoLogger
 # A subclass of Ruby's stdlib Logger with all the mutex and logrotation stuff
@@ -38,7 +38,6 @@ class MonoLogger < Logger
     end
   end
 
-
   class LocklessLogDevice < LogDevice
 
     def initialize(log = nil)
@@ -86,5 +85,4 @@ class MonoLogger < Logger
 
   end
 
-
 end
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 9823185..1f72c86 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -1,9 +1,8 @@
-#
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,22 +18,22 @@
 # limitations under the License.
 #
 
-require 'forwardable'
-require 'chef/config'
-require 'chef/nil_argument'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mixin/deep_merge'
-require 'chef/dsl/include_attribute'
-require 'chef/dsl/platform_introspection'
-require 'chef/environment'
-require 'chef/rest'
-require 'chef/run_list'
-require 'chef/node/attribute'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-require 'chef/whitelist'
+require "forwardable"
+require "chef/config"
+require "chef/nil_argument"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mixin/deep_merge"
+require "chef/dsl/include_attribute"
+require "chef/dsl/platform_introspection"
+require "chef/environment"
+require "chef/server_api"
+require "chef/run_list"
+require "chef/node/attribute"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/whitelist"
 
 class Chef
   class Node
@@ -63,45 +62,67 @@ class Chef
 
     include Chef::Mixin::ParamsValidate
 
+    NULL_ARG = Object.new
+
     # Create a new Chef::Node object.
     def initialize(chef_server_rest: nil)
       @chef_server_rest = chef_server_rest
       @name = nil
 
-      @chef_environment = '_default'
+      @chef_environment = "_default"
       @primary_runlist = Chef::RunList.new
       @override_runlist = Chef::RunList.new
 
+      @policy_name = nil
+      @policy_group = nil
+
       @attributes = Chef::Node::Attribute.new({}, {}, {}, {})
 
       @run_state = {}
     end
 
+    # after the run_context has been set on the node, go through the cookbook_collection
+    # and setup the node[:cookbooks] attribute so that it is published in the node object
+    def set_cookbook_attribute
+      return unless run_context.cookbook_collection
+      run_context.cookbook_collection.each do |cookbook_name, cookbook|
+        automatic_attrs[:cookbooks][cookbook_name][:version] = cookbook.version
+      end
+    end
+
     # Used by DSL
     def node
       self
     end
 
     def chef_server_rest
-      @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      # for saving node data we use validate_utf8: false which will not
+      # raise an exception on bad utf8 data, but will replace the bad
+      # characters and render valid JSON.
+      @chef_server_rest ||= Chef::ServerAPI.new(
+        Chef::Config[:chef_server_url],
+        client_name: Chef::Config[:node_name],
+        signing_key_filename: Chef::Config[:client_key],
+        validate_utf8: false,
+      )
     end
 
     # Set the name of this Node, or return the current name.
-    def name(arg=nil)
+    def name(arg = nil)
       if arg != nil
         validate(
-                 {:name => arg },
-                 {:name => { :kind_of => String,
-                     :cannot_be => :blank,
-                     :regex => /^[\-[:alnum:]_:.]+$/}
-                 })
+                 { :name => arg },
+                 { :name => { :kind_of => String,
+                              :cannot_be => :blank,
+                              :regex => /^[\-[:alnum:]_:.]+$/ }
+                 },)
         @name = arg
       else
         @name
       end
     end
 
-    def chef_environment(arg=nil)
+    def chef_environment(arg = nil)
       set_or_return(
         :chef_environment,
         arg,
@@ -115,6 +136,50 @@ class Chef
 
     alias :environment :chef_environment
 
+    # The `policy_name` for this node. Setting this to a non-nil value will
+    # enable policyfile mode when `chef-client` is run. If set in the config
+    # file or in node json, running `chef-client` will update this value.
+    #
+    # @see Chef::PolicyBuilder::Dynamic
+    # @see Chef::PolicyBuilder::Policyfile
+    #
+    # @param arg [String] the new policy_name value
+    # @return [String] the current policy_name, or the one you just set
+    def policy_name(arg = NULL_ARG)
+      return @policy_name if arg.equal?(NULL_ARG)
+      validate({ policy_name: arg }, { policy_name: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+      @policy_name = arg
+    end
+
+    # A "non-DSL-style" setter for `policy_name`
+    #
+    # @see #policy_name
+    def policy_name=(policy_name)
+      policy_name(policy_name)
+    end
+
+    # The `policy_group` for this node. Setting this to a non-nil value will
+    # enable policyfile mode when `chef-client` is run. If set in the config
+    # file or in node json, running `chef-client` will update this value.
+    #
+    # @see Chef::PolicyBuilder::Dynamic
+    # @see Chef::PolicyBuilder::Policyfile
+    #
+    # @param arg [String] the new policy_group value
+    # @return [String] the current policy_group, or the one you just set
+    def policy_group(arg = NULL_ARG)
+      return @policy_group if arg.equal?(NULL_ARG)
+      validate({ policy_group: arg }, { policy_group: { kind_of: [ String, NilClass ], regex: /^[\-:.[:alnum:]_]+$/ } })
+      @policy_group = arg
+    end
+
+    # A "non-DSL-style" setter for `policy_group`
+    #
+    # @see #policy_group
+    def policy_group=(policy_group)
+      policy_group(policy_group)
+    end
+
     def attributes
       @attributes
     end
@@ -244,6 +309,7 @@ class Chef
     # saved back to the node and be searchable
     def loaded_recipe(cookbook, recipe)
       fully_qualified_recipe = "#{cookbook}::#{recipe}"
+
       automatic_attrs[:recipes] << fully_qualified_recipe unless Array(self[:recipes]).include?(fully_qualified_recipe)
     end
 
@@ -297,23 +363,24 @@ class Chef
     # Consumes the combined run_list and other attributes in +attrs+
     def consume_attributes(attrs)
       normal_attrs_to_merge = consume_run_list(attrs)
+      normal_attrs_to_merge = consume_chef_environment(normal_attrs_to_merge)
       Chef::Log.debug("Applying attributes from json file")
-      self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs,normal_attrs_to_merge)
+      self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs, normal_attrs_to_merge)
       self.tags # make sure they're defined
     end
 
     # Lazy initializer for tags attribute
     def tags
-      normal[:tags] = [] unless attribute?(:tags)
+      normal[:tags] = Array(normal[:tags])
       normal[:tags]
     end
 
-    def tag(*tags)
-      tags.each do |tag|
-        self.normal[:tags].push(tag.to_s) unless self[:tags].include? tag.to_s
+    def tag(*args)
+      args.each do |tag|
+        tags.push(tag.to_s) unless tags.include? tag.to_s
       end
 
-      self[:tags]
+      tags
     end
 
     # Extracts the run list from +attrs+ and applies it. Returns the remaining attributes
@@ -323,12 +390,30 @@ class Chef
         if attrs.key?("recipes") || attrs.key?("run_list")
           raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only."
         end
-        Chef::Log.info("Setting the run_list to #{new_run_list.to_s} from CLI options")
+        Chef::Log.info("Setting the run_list to #{new_run_list} from CLI options")
         run_list(new_run_list)
       end
       attrs
     end
 
+    # chef_environment when set in -j JSON will take precedence over
+    # -E ENVIRONMENT. Ideally, IMO, the order of precedence should be (lowest to
+    #  highest):
+    #   config_file
+    #   -j JSON
+    #   -E ENVIRONMENT
+    # so that users could reuse their JSON and override the chef_environment
+    # configured within it with -E ENVIRONMENT. Because command line options are
+    # merged with Chef::Config there is currently no way to distinguish between
+    # an environment set via config from an environment set via command line.
+    def consume_chef_environment(attrs)
+      attrs = attrs ? attrs.dup : {}
+      if env = attrs.delete("chef_environment")
+        chef_environment(env)
+      end
+      attrs
+    end
+
     # Clear defaults and overrides, so that any deleted attributes
     # between runs are still gone.
     def reset_defaults_and_overrides
@@ -348,13 +433,14 @@ class Chef
     # run_list is mutated? Or perhaps do something smarter like
     # on-demand generation of default_attrs and override_attrs,
     # invalidated only when run_list is mutated?
-    def expand!(data_source = 'server')
+    def expand!(data_source = "server")
       expansion = run_list.expand(chef_environment, data_source)
       raise Chef::Exceptions::MissingRole, expansion if expansion.errors?
 
       self.tags # make sure they're defined
 
-      automatic_attrs[:recipes] = expansion.recipes
+      automatic_attrs[:recipes] = expansion.recipes.with_duplicate_names
+      automatic_attrs[:expanded_run_list] = expansion.recipes.with_fully_qualified_names_and_version_constraints
       automatic_attrs[:roles] = expansion.roles
 
       apply_expansion_attributes(expansion)
@@ -366,7 +452,7 @@ class Chef
     # passed in, which came from roles.
     def apply_expansion_attributes(expansion)
       loaded_environment = if chef_environment == "_default"
-                             Chef::Environment.new.tap {|e| e.name("_default")}
+                             Chef::Environment.new.tap { |e| e.name("_default") }
                            else
                              Chef::Environment.load(chef_environment)
                            end
@@ -414,15 +500,23 @@ class Chef
       result = {
         "name" => name,
         "chef_environment" => chef_environment,
-        'json_class' => self.class.name,
+        "json_class" => self.class.name,
         "automatic" => attributes.automatic,
         "normal" => attributes.normal,
         "chef_type" => "node",
         "default" => attributes.combined_default,
         "override" => attributes.combined_override,
         #Render correctly for run_list items so malformed json does not result
-        "run_list" => @primary_runlist.run_list.map { |item| item.to_s }
+        "run_list" => @primary_runlist.run_list.map { |item| item.to_s },
       }
+      # Chef Server rejects node JSON with extra keys; prior to 12.3,
+      # "policy_name" and "policy_group" are unknown; after 12.3 they are
+      # optional, therefore only including them in the JSON if present
+      # maximizes compatibility for most people.
+      unless policy_group.nil? && policy_name.nil?
+        result["policy_name"] = policy_name
+        result["policy_group"] = policy_group
+      end
       result
     end
 
@@ -438,6 +532,12 @@ class Chef
 
     # Create a Chef::Node from JSON
     def self.json_create(o)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Node#from_hash")
+      from_hash(o)
+    end
+
+    def self.from_hash(o)
+      return o if o.kind_of? Chef::Node
       node = new
       node.name(o["name"])
       node.chef_environment(o["chef_environment"])
@@ -451,38 +551,43 @@ class Chef
 
       if o.has_key?("run_list")
         node.run_list.reset!(o["run_list"])
-      else
+      elsif o.has_key?("recipes")
         o["recipes"].each { |r| node.recipes << r }
       end
+
+      node.policy_name = o["policy_name"] if o.has_key?("policy_name")
+      node.policy_group = o["policy_group"] if o.has_key?("policy_group")
+
       node
     end
 
-    def self.list_by_environment(environment, inflate=false)
+    def self.list_by_environment(environment, inflate = false)
       if inflate
         response = Hash.new
-        Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") {|n| response[n.name] = n unless n.nil?}
+        Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") { |n| response[n.name] = n unless n.nil? }
         response
       else
-        Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("environments/#{environment}/nodes")
+        Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("environments/#{environment}/nodes")
       end
     end
 
-    def self.list(inflate=false)
+    def self.list(inflate = false)
       if inflate
         response = Hash.new
         Chef::Search::Query.new.search(:node) do |n|
+          n = Chef::Node.from_hash(n)
           response[n.name] = n unless n.nil?
         end
         response
       else
-        Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes")
+        Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes")
       end
     end
 
     def self.find_or_create(node_name)
       load(node_name)
     rescue Net::HTTPServerException => e
-      raise unless e.response.code == '404'
+      raise unless e.response.code == "404"
       node = build(node_name)
       node.create
     end
@@ -496,12 +601,12 @@ class Chef
 
     # Load a node by name
     def self.load(name)
-      Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes/#{name}")
+      from_hash(Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("nodes/#{name}"))
     end
 
     # Remove this node via the REST API
     def destroy
-      chef_server_rest.delete_rest("nodes/#{name}")
+      chef_server_rest.delete("nodes/#{name}")
     end
 
     # Save this node via the REST API
@@ -510,33 +615,74 @@ class Chef
       # so then POST to create.
       begin
         if Chef::Config[:why_run]
-          Chef::Log.warn("In whyrun mode, so NOT performing node save.")
+          Chef::Log.warn("In why-run mode, so NOT performing node save.")
         else
-          chef_server_rest.put_rest("nodes/#{name}", data_for_save)
+          chef_server_rest.put("nodes/#{name}", data_for_save)
         end
       rescue Net::HTTPServerException => e
-        raise e unless e.response.code == "404"
-        chef_server_rest.post_rest("nodes", data_for_save)
+        if e.response.code == "404"
+          chef_server_rest.post("nodes", data_for_save)
+        # Chef Server before 12.3 rejects node JSON with 'policy_name' or
+        # 'policy_group' keys, but 'policy_name' will be detected first.
+        # Backcompat can be removed in 13.0
+        elsif e.response.code == "400" && e.response.body.include?("Invalid key policy_name")
+          save_without_policyfile_attrs
+        else
+          raise
+        end
       end
       self
     end
 
     # Create the node via the REST API
     def create
-      chef_server_rest.post_rest("nodes", data_for_save)
+      chef_server_rest.post("nodes", data_for_save)
       self
+    rescue Net::HTTPServerException => e
+      # Chef Server before 12.3 rejects node JSON with 'policy_name' or
+      # 'policy_group' keys, but 'policy_name' will be detected first.
+      # Backcompat can be removed in 13.0
+      if e.response.code == "400" && e.response.body.include?("Invalid key policy_name")
+        chef_server_rest.post("nodes", data_for_save_without_policyfile_attrs)
+      else
+        raise
+      end
     end
 
     def to_s
       "node[#{name}]"
     end
 
+    def ==(other)
+      if other.kind_of?(self.class)
+        self.name == other.name
+      else
+        false
+      end
+    end
+
     def <=>(other_node)
       self.name <=> other_node.name
     end
 
     private
 
+    def save_without_policyfile_attrs
+      trimmed_data = data_for_save_without_policyfile_attrs
+
+      chef_server_rest.put("nodes/#{name}", trimmed_data)
+    rescue Net::HTTPServerException => e
+      raise e unless e.response.code == "404"
+      chef_server_rest.post("nodes", trimmed_data)
+    end
+
+    def data_for_save_without_policyfile_attrs
+      data_for_save.tap do |trimmed_data|
+        trimmed_data.delete("policy_name")
+        trimmed_data.delete("policy_group")
+      end
+    end
+
     def data_for_save
       data = for_json
       ["automatic", "default", "normal", "override"].each do |level|
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index 45f2ef0..ab97cf9 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 # limitations under the License.
 #
 
-require 'chef/node/immutable_collections'
-require 'chef/node/attribute_collections'
-require 'chef/mixin/deep_merge'
-require 'chef/log'
+require "chef/node/immutable_collections"
+require "chef/node/attribute_collections"
+require "chef/mixin/deep_merge"
+require "chef/log"
 
 class Chef
   class Node
@@ -48,21 +48,21 @@ class Chef
         :@role_override,
         :@env_override,
         :@force_override,
-        :@automatic
+        :@automatic,
       ].freeze
 
       DEFAULT_COMPONENTS = [
         :@default,
         :@env_default,
         :@role_default,
-        :@force_default
+        :@force_default,
       ]
 
       OVERRIDE_COMPONENTS = [
         :@override,
         :@role_override,
         :@env_override,
-        :@force_override
+        :@force_override,
       ]
 
       [:all?,
@@ -144,34 +144,34 @@ class Chef
        end
 
        # return the cookbook level default attribute component
-       attr_reader :default
+      attr_reader :default
 
        # return the role level default attribute component
-       attr_reader :role_default
+      attr_reader :role_default
 
        # return the environment level default attribute component
-       attr_reader :env_default
+      attr_reader :env_default
 
        # return the force_default level attribute component
-       attr_reader :force_default
+      attr_reader :force_default
 
        # return the "normal" level attribute component
-       attr_reader :normal
+      attr_reader :normal
 
        # return the cookbook level override attribute component
-       attr_reader :override
+      attr_reader :override
 
        # return the role level override attribute component
-       attr_reader :role_override
+      attr_reader :role_override
 
        # return the enviroment level override attribute component
-       attr_reader :env_override
+      attr_reader :env_override
 
        # return the force override level attribute component
-       attr_reader :force_override
+      attr_reader :force_override
 
        # return the automatic level attribute component
-       attr_reader :automatic
+      attr_reader :automatic
 
        # This is used to track the top level key as we descend through method chaining into
        # a precedence level (e.g. node.default['foo']['bar']['baz']= results in 'foo' here).  We
@@ -179,36 +179,36 @@ class Chef
        # that we can invalidate the whole top-level deep merge cache for the top-level key.  It is
        # the responsibility of the accessor on the Chef::Node object to reset this to nil, and then
        # the first VividMash#[] call can ||= and set this to the first key we encounter.
-       attr_accessor :top_level_breadcrumb
+      attr_accessor :top_level_breadcrumb
 
        # Cache of deep merged values by top-level key.  This is a simple hash which has keys that are the
        # top-level keys of the node object, and we save the computed deep-merge for that key here.  There is
        # no cache of subtrees.
-       attr_accessor :deep_merge_cache
+      attr_accessor :deep_merge_cache
 
-       def initialize(normal, default, override, automatic)
-         @set_unless_present = false
+      def initialize(normal, default, override, automatic)
+        @set_unless_present = false
 
-         @default = VividMash.new(self, default)
-         @env_default = VividMash.new(self, {})
-         @role_default = VividMash.new(self, {})
-         @force_default = VividMash.new(self, {})
+        @default = VividMash.new(self, default)
+        @env_default = VividMash.new(self, {})
+        @role_default = VividMash.new(self, {})
+        @force_default = VividMash.new(self, {})
 
-         @normal = VividMash.new(self, normal)
+        @normal = VividMash.new(self, normal)
 
-         @override = VividMash.new(self, override)
-         @role_override = VividMash.new(self, {})
-         @env_override = VividMash.new(self, {})
-         @force_override = VividMash.new(self, {})
+        @override = VividMash.new(self, override)
+        @role_override = VividMash.new(self, {})
+        @env_override = VividMash.new(self, {})
+        @force_override = VividMash.new(self, {})
 
-         @automatic = VividMash.new(self, automatic)
+        @automatic = VividMash.new(self, automatic)
 
-         @merged_attributes = nil
-         @combined_override = nil
-         @combined_default = nil
-         @top_level_breadcrumb = nil
-         @deep_merge_cache = {}
-       end
+        @merged_attributes = nil
+        @combined_override = nil
+        @combined_default = nil
+        @top_level_breadcrumb = nil
+        @deep_merge_cache = {}
+      end
 
        # Debug what's going on with an attribute. +args+ is a path spec to the
        # attribute you're interested in. For example, to debug where the value
@@ -221,195 +221,195 @@ class Chef
        # the component, such as role default, normal, etc. and value is the
        # attribute value set at that precedence level. If there is no value at
        # that precedence level, +value+ will be the symbol +:not_present+.
-       def debug_value(*args)
-         components = COMPONENTS.map do |component|
-           ivar = instance_variable_get(component)
-           value = args.inject(ivar) do |so_far, key|
-             if so_far == :not_present
-               :not_present
-             elsif so_far.has_key?(key)
-               so_far[key]
-             else
-               :not_present
-             end
-           end
-           [component.to_s.sub(/^@/,""), value]
-         end
-         [["set_unless_enabled?", @set_unless_present]] + components
-       end
+      def debug_value(*args)
+        components = COMPONENTS.map do |component|
+          ivar = instance_variable_get(component)
+          value = args.inject(ivar) do |so_far, key|
+            if so_far == :not_present
+              :not_present
+            elsif so_far.has_key?(key)
+              so_far[key]
+            else
+              :not_present
+            end
+          end
+          [component.to_s.sub(/^@/, ""), value]
+        end
+        [["set_unless_enabled?", @set_unless_present]] + components
+      end
 
        # Enables or disables `||=`-like attribute setting. See, e.g., Node#set_unless
-       def set_unless_value_present=(setting)
-         @set_unless_present = setting
-       end
+      def set_unless_value_present=(setting)
+        @set_unless_present = setting
+      end
 
        # Invalidate a key in the deep_merge_cache.  If called with nil, or no arg, this will invalidate
        # the entire deep_merge cache.  In the case of the user doing node.default['foo']['bar']['baz']=
        # that eventually results in a call to reset_cache('foo') here.  A node.default=hash_thing call
        # must invalidate the entire cache and re-deep-merge the entire node object.
-       def reset_cache(path = nil)
-         if path.nil?
-           @deep_merge_cache = {}
-         else
-           deep_merge_cache.delete(path.to_s)
-         end
-       end
+      def reset_cache(path = nil)
+        if path.nil?
+          @deep_merge_cache = {}
+        else
+          deep_merge_cache.delete(path.to_s)
+        end
+      end
 
-       alias :reset :reset_cache
+      alias :reset :reset_cache
 
        # Set the cookbook level default attribute component to +new_data+.
-       def default=(new_data)
-         reset
-         @default = VividMash.new(self, new_data)
-       end
+      def default=(new_data)
+        reset
+        @default = VividMash.new(self, new_data)
+      end
 
        # Set the role level default attribute component to +new_data+
-       def role_default=(new_data)
-         reset
-         @role_default = VividMash.new(self, new_data)
-       end
+      def role_default=(new_data)
+        reset
+        @role_default = VividMash.new(self, new_data)
+      end
 
        # Set the environment level default attribute component to +new_data+
-       def env_default=(new_data)
-         reset
-         @env_default = VividMash.new(self, new_data)
-       end
+      def env_default=(new_data)
+        reset
+        @env_default = VividMash.new(self, new_data)
+      end
 
        # Set the force_default (+default!+) level attributes to +new_data+
-       def force_default=(new_data)
-         reset
-         @force_default = VividMash.new(self, new_data)
-       end
+      def force_default=(new_data)
+        reset
+        @force_default = VividMash.new(self, new_data)
+      end
 
        # Set the normal level attribute component to +new_data+
-       def normal=(new_data)
-         reset
-         @normal = VividMash.new(self, new_data)
-       end
+      def normal=(new_data)
+        reset
+        @normal = VividMash.new(self, new_data)
+      end
 
        # Set the cookbook level override attribute component to +new_data+
-       def override=(new_data)
-         reset
-         @override = VividMash.new(self, new_data)
-       end
+      def override=(new_data)
+        reset
+        @override = VividMash.new(self, new_data)
+      end
 
        # Set the role level override attribute component to +new_data+
-       def role_override=(new_data)
-         reset
-         @role_override = VividMash.new(self, new_data)
-       end
+      def role_override=(new_data)
+        reset
+        @role_override = VividMash.new(self, new_data)
+      end
 
        # Set the environment level override attribute component to +new_data+
-       def env_override=(new_data)
-         reset
-         @env_override = VividMash.new(self, new_data)
-       end
+      def env_override=(new_data)
+        reset
+        @env_override = VividMash.new(self, new_data)
+      end
 
-       def force_override=(new_data)
-         reset
-         @force_override = VividMash.new(self, new_data)
-       end
+      def force_override=(new_data)
+        reset
+        @force_override = VividMash.new(self, new_data)
+      end
 
-       def automatic=(new_data)
-         reset
-         @automatic = VividMash.new(self, new_data)
-       end
+      def automatic=(new_data)
+        reset
+        @automatic = VividMash.new(self, new_data)
+      end
 
        #
        # Deleting attributes
        #
 
        # clears attributes from all precedence levels
-       def rm(*args)
-         reset(args[0])
-         # just easier to compute our retval, rather than collect+merge sub-retvals
-         ret = args.inject(merged_attributes) do |attr, arg|
-           if attr.nil? || !attr.respond_to?(:[])
-             nil
-           else
-             begin
-               attr[arg]
-             rescue TypeError
-               raise TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)"
-             end
-           end
-         end
-         rm_default(*args)
-         rm_normal(*args)
-         rm_override(*args)
-         ret
-       end
+      def rm(*args)
+        reset(args[0])
+        # just easier to compute our retval, rather than collect+merge sub-retvals
+        ret = args.inject(merged_attributes) do |attr, arg|
+          if attr.nil? || !attr.respond_to?(:[])
+            nil
+          else
+            begin
+              attr[arg]
+            rescue TypeError
+              raise TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)"
+            end
+          end
+        end
+        rm_default(*args)
+        rm_normal(*args)
+        rm_override(*args)
+        ret
+      end
 
        # does <level>['foo']['bar'].delete('baz')
-       def remove_from_precedence_level(level, *args, key)
-         multimash = level.element(*args)
-         multimash.nil? ? nil : multimash.delete(key)
-       end
+      def remove_from_precedence_level(level, *args, key)
+        multimash = level.element(*args)
+        multimash.nil? ? nil : multimash.delete(key)
+      end
 
-       private :remove_from_precedence_level
+      private :remove_from_precedence_level
 
        # clears attributes from all default precedence levels
        #
        # equivalent to: force_default!['foo']['bar'].delete('baz')
-       def rm_default(*args)
-         reset(args[0])
-         remove_from_precedence_level(force_default!(autovivify: false), *args)
-       end
+      def rm_default(*args)
+        reset(args[0])
+        remove_from_precedence_level(force_default!(autovivify: false), *args)
+      end
 
        # clears attributes from normal precedence
        #
        # equivalent to: normal!['foo']['bar'].delete('baz')
-       def rm_normal(*args)
-         reset(args[0])
-         remove_from_precedence_level(normal!(autovivify: false), *args)
-       end
+      def rm_normal(*args)
+        reset(args[0])
+        remove_from_precedence_level(normal!(autovivify: false), *args)
+      end
 
        # clears attributes from all override precedence levels
        #
        # equivalent to: force_override!['foo']['bar'].delete('baz')
-       def rm_override(*args)
-         reset(args[0])
-         remove_from_precedence_level(force_override!(autovivify: false), *args)
-       end
+      def rm_override(*args)
+        reset(args[0])
+        remove_from_precedence_level(force_override!(autovivify: false), *args)
+      end
 
        #
        # Replacing attributes without merging
        #
 
        # sets default attributes without merging
-       def default!(opts={})
-         # FIXME: do not flush whole cache
-         reset
-         MultiMash.new(self, @default, [], opts)
-       end
+      def default!(opts = {})
+        # FIXME: do not flush whole cache
+        reset
+        MultiMash.new(self, @default, [], opts)
+      end
 
        # sets normal attributes without merging
-       def normal!(opts={})
-         # FIXME: do not flush whole cache
-         reset
-         MultiMash.new(self, @normal, [], opts)
-       end
+      def normal!(opts = {})
+        # FIXME: do not flush whole cache
+        reset
+        MultiMash.new(self, @normal, [], opts)
+      end
 
        # sets override attributes without merging
-       def override!(opts={})
-         # FIXME: do not flush whole cache
-         reset
-         MultiMash.new(self, @override, [], opts)
-       end
+      def override!(opts = {})
+        # FIXME: do not flush whole cache
+        reset
+        MultiMash.new(self, @override, [], opts)
+      end
 
        # clears from all default precedence levels and then sets force_default
-       def force_default!(opts={})
-         # FIXME: do not flush whole cache
-         reset
-         MultiMash.new(self, @force_default, [@default, @env_default, @role_default], opts)
-       end
+      def force_default!(opts = {})
+        # FIXME: do not flush whole cache
+        reset
+        MultiMash.new(self, @force_default, [@default, @env_default, @role_default], opts)
+      end
 
        # clears from all override precedence levels and then sets force_override
-       def force_override!(opts={})
-         # FIXME: do not flush whole cache
-         reset
-         MultiMash.new(self, @force_override, [@override, @env_override, @role_override], opts)
-       end
+      def force_override!(opts = {})
+        # FIXME: do not flush whole cache
+        reset
+        MultiMash.new(self, @force_override, [@override, @env_override, @role_override], opts)
+      end
 
        #
        # Accessing merged attributes.
@@ -419,75 +419,75 @@ class Chef
        # all of node['foo'] even if the user only requires node['foo']['bar']['baz'].
        #
 
-       def merged_attributes(*path)
-        # immutablize(
-           merge_all(path)
-        # )
-       end
-
-       def combined_override(*path)
-         immutablize(merge_overrides(path))
-       end
-
-       def combined_default(*path)
-         immutablize(merge_defaults(path))
-       end
-
-       def [](key)
-         if deep_merge_cache.has_key?(key.to_s)
-           # return the cache of the deep merged values by top-level key
-           deep_merge_cache[key.to_s]
-         else
-           # save all the work of computing node[key]
-           deep_merge_cache[key.to_s] = merged_attributes(key)
-         end
-       end
-
-       def []=(key, value)
-         raise Exceptions::ImmutableAttributeModification
-       end
-
-       def has_key?(key)
-         COMPONENTS.any? do |component_ivar|
-           instance_variable_get(component_ivar).has_key?(key)
-         end
-       end
-
-       alias :attribute? :has_key?
-       alias :member? :has_key?
-       alias :include? :has_key?
-       alias :key? :has_key?
-
-       alias :each_attribute :each
-
-       def method_missing(symbol, *args)
-         if args.empty?
-           if key?(symbol)
-             self[symbol]
-           else
-             raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
-           end
-         elsif symbol.to_s =~ /=$/
-           key_to_set = symbol.to_s[/^(.+)=$/, 1]
-           self[key_to_set] = (args.length == 1 ? args[0] : args)
-         else
-           raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
-         end
-       end
-
-       def to_s
-         merged_attributes.to_s
-       end
-
-       def inspect
-         "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map{|iv|
-           "#{iv}=#{instance_variable_get(iv).inspect}"
-         }.join(', ') << ">"
-       end
-
-       def set_unless?
-         @set_unless_present
-       end
+      def merged_attributes(*path)
+       # immutablize(
+        merge_all(path)
+       # )
+      end
+
+      def combined_override(*path)
+        immutablize(merge_overrides(path))
+      end
+
+      def combined_default(*path)
+        immutablize(merge_defaults(path))
+      end
+
+      def [](key)
+        if deep_merge_cache.has_key?(key.to_s)
+          # return the cache of the deep merged values by top-level key
+          deep_merge_cache[key.to_s]
+        else
+          # save all the work of computing node[key]
+          deep_merge_cache[key.to_s] = merged_attributes(key)
+        end
+      end
+
+      def []=(key, value)
+        raise Exceptions::ImmutableAttributeModification
+      end
+
+      def has_key?(key)
+        COMPONENTS.any? do |component_ivar|
+          instance_variable_get(component_ivar).has_key?(key)
+        end
+      end
+
+      alias :attribute? :has_key?
+      alias :member? :has_key?
+      alias :include? :has_key?
+      alias :key? :has_key?
+
+      alias :each_attribute :each
+
+      def method_missing(symbol, *args)
+        if args.empty?
+          if key?(symbol)
+            self[symbol]
+          else
+            raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'"
+          end
+        elsif symbol.to_s =~ /=$/
+          key_to_set = symbol.to_s[/^(.+)=$/, 1]
+          self[key_to_set] = (args.length == 1 ? args[0] : args)
+        else
+          raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'"
+        end
+      end
+
+      def to_s
+        merged_attributes.to_s
+      end
+
+      def inspect
+        "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map {|iv|
+          "#{iv}=#{instance_variable_get(iv).inspect}"
+        }.join(", ") << ">"
+      end
+
+      def set_unless?
+        @set_unless_present
+      end
 
        private
 
@@ -501,32 +501,32 @@ class Chef
        # raise any TypeError if it attempts to apply a hash key to an Integer/String/TrueClass, and just returns
        # nil in that case.
        #
-       def apply_path(component, path)
-         path ||= []
-         path.inject(component) do |val, path_arg|
-           if val.respond_to?(:[])
-             # Have an Array-like or Hash-like thing
-             if !val.respond_to?(:has_key?)
-               # Have an Array-like thing
-               val[path_arg]
-             elsif val.has_key?(path_arg)
-               # Hash-like thing (must check has_key? first to protect against Autovivification)
-               val[path_arg]
-             else
-               nil
-             end
-           else
-             nil
-           end
-         end
-       end
+      def apply_path(component, path)
+        path ||= []
+        path.inject(component) do |val, path_arg|
+          if val.respond_to?(:[])
+            # Have an Array-like or Hash-like thing
+            if !val.respond_to?(:has_key?)
+              # Have an Array-like thing
+              val[path_arg]
+            elsif val.has_key?(path_arg)
+              # Hash-like thing (must check has_key? first to protect against Autovivification)
+              val[path_arg]
+            else
+              nil
+            end
+          else
+            nil
+          end
+        end
+      end
 
        # For elements like Fixnums, true, nil...
-       def safe_dup(e)
-         e.dup
-       rescue TypeError
-         e
-       end
+      def safe_dup(e)
+        e.dup
+      rescue TypeError
+        e
+      end
 
        # Deep merge all attribute levels using hash-only merging between different precidence
        # levels (so override arrays completely replace arrays set at any default level).
@@ -535,24 +535,24 @@ class Chef
        #
        # @param path [Array] Array of args to method chain to descend into the node object
        # @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
-       def merge_all(path)
-         components = [
-           merge_defaults(path),
-           apply_path(@normal, path),
-           merge_overrides(path),
-           apply_path(@automatic, path),
-         ]
-
-         components.map! do |component|
-           safe_dup(component)
-         end
+      def merge_all(path)
+        components = [
+          merge_defaults(path),
+          apply_path(@normal, path),
+          merge_overrides(path),
+          apply_path(@automatic, path),
+        ]
 
-         return nil if components.compact.empty?
+        components.map! do |component|
+          safe_dup(component)
+        end
 
-         components.inject(ImmutableMash.new({})) do |merged, component|
-           Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
-         end
-       end
+        return nil if components.compact.empty?
+
+        components.inject(ImmutableMash.new({})) do |merged, component|
+          Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
+        end
+      end
 
        # Deep merge the default attribute levels with array merging.
        #
@@ -560,12 +560,12 @@ class Chef
        #
        # @param path [Array] Array of args to method chain to descend into the node object
        # @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
-       def merge_defaults(path)
-         DEFAULT_COMPONENTS.inject(nil) do |merged, component_ivar|
-           component_value = apply_path(instance_variable_get(component_ivar), path)
-           Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
-         end
-       end
+      def merge_defaults(path)
+        DEFAULT_COMPONENTS.inject(nil) do |merged, component_ivar|
+          component_value = apply_path(instance_variable_get(component_ivar), path)
+          Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+        end
+      end
 
        # Deep merge the override attribute levels with array merging.
        #
@@ -573,12 +573,12 @@ class Chef
        #
        # @param path [Array] Array of args to method chain to descend into the node object
        # @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
-       def merge_overrides(path)
-         OVERRIDE_COMPONENTS.inject(nil) do |merged, component_ivar|
-           component_value = apply_path(instance_variable_get(component_ivar), path)
-           Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
-         end
-       end
+      def merge_overrides(path)
+        OVERRIDE_COMPONENTS.inject(nil) do |merged, component_ivar|
+          component_value = apply_path(instance_variable_get(component_ivar), path)
+          Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+        end
+      end
 
     end
 
diff --git a/lib/chef/node/attribute_collections.rb b/lib/chef/node/attribute_collections.rb
index b912904..68f3a69 100644
--- a/lib/chef/node/attribute_collections.rb
+++ b/lib/chef/node/attribute_collections.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -54,7 +54,7 @@ class Chef
         :sort!,
         :sort_by!,
         :uniq!,
-        :unshift
+        :unshift,
       ]
 
       # For all of the methods that may mutate an Array, we override them to
@@ -82,7 +82,7 @@ class Chef
       end
 
       def dup
-        Array.new(map {|e| safe_dup(e)})
+        Array.new(map { |e| safe_dup(e) })
       end
 
     end
@@ -117,7 +117,7 @@ class Chef
         :reject!,
         :replace,
         :select!,
-        :shift
+        :shift,
       ]
 
       # For all of the mutating methods on Mash, override them so that they
@@ -130,7 +130,7 @@ class Chef
         end
       end
 
-      def initialize(root, data={})
+      def initialize(root, data = {})
         @root = root
         super(data)
       end
@@ -148,7 +148,7 @@ class Chef
 
       def []=(key, value)
         root.top_level_breadcrumb ||= key
-        if set_unless? && key?(key)
+        if set_unless? && key?(key) && !self[key].nil?
           self[key]
         else
           root.reset_cache(root.top_level_breadcrumb)
@@ -241,7 +241,7 @@ class Chef
       # Initialize with an array of mashes.  For the delete return value to work
       # properly the mashes must come from the same attribute level (i.e. all
       # override or all default, but not a mix of both).
-      def initialize(root, primary_mash, mashes, opts={})
+      def initialize(root, primary_mash, mashes, opts = {})
         @root = root
         @primary_mash = primary_mash
         @mashes = mashes
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index 0e28006..b5fd86f 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -63,7 +63,7 @@ class Chef
         :sort!,
         :sort_by!,
         :uniq!,
-        :unshift
+        :unshift,
       ]
 
       def initialize(array_data)
@@ -88,7 +88,7 @@ class Chef
       end
 
       def dup
-        Array.new(map {|e| safe_dup(e)})
+        Array.new(map { |e| safe_dup(e) })
       end
 
       def to_a
@@ -143,7 +143,7 @@ class Chef
         :reject!,
         :replace,
         :select!,
-        :shift
+        :shift,
       ]
 
       def initialize(mash_data)
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index 2ca6d9b..5eac63d 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,128 +19,204 @@
 class Chef
   class NodeMap
 
-    VALID_OPTS = [
-      :on_platform,
-      :on_platforms,
-      :platform,
-      :os,
-      :platform_family,
-    ]
-
-    DEPRECATED_OPTS = [
-      :on_platform,
-      :on_platforms,
-    ]
-
-    # Create a new NodeMap
     #
-    def initialize
-      @map = {}
-    end
-
     # Set a key/value pair on the map with a filter.  The filter must be true
     # when applied to the node in order to retrieve the value.
     #
     # @param key [Object] Key to store
     # @param value [Object] Value associated with the key
     # @param filters [Hash] Node filter options to apply to key retrieval
+    #
     # @yield [node] Arbitrary node filter as a block which takes a node argument
+    #
     # @return [NodeMap] Returns self for possible chaining
     #
-    def set(key, value, filters = {}, &block)
-      validate_filter!(filters)
-      deprecate_filter!(filters)
-      @map[key] ||= []
-      # we match on the first value we find, so we want to unshift so that the
-      # last setter wins
-      # FIXME: need a test for this behavior
-      @map[key].unshift({ filters: filters, block: block, value: value })
-      self
+    def set(key, value, platform: nil, platform_version: nil, platform_family: nil, os: nil, on_platform: nil, on_platforms: nil, canonical: nil, override: nil, &block)
+      Chef.log_deprecation("The on_platform option to node_map has been deprecated") if on_platform
+      Chef.log_deprecation("The on_platforms option to node_map has been deprecated") if on_platforms
+      platform ||= on_platform || on_platforms
+      filters = {}
+      filters[:platform] = platform if platform
+      filters[:platform_version] = platform_version if platform_version
+      filters[:platform_family] = platform_family if platform_family
+      filters[:os] = os if os
+      new_matcher = { value: value, filters: filters }
+      new_matcher[:block] = block if block
+      new_matcher[:canonical] = canonical if canonical
+      new_matcher[:override] = override if override
+
+      # The map is sorted in order of preference already; we just need to find
+      # our place in it (just before the first value with the same preference level).
+      insert_at = nil
+      map[key] ||= []
+      map[key].each_with_index do |matcher, index|
+        cmp = compare_matchers(key, new_matcher, matcher)
+        insert_at ||= index if cmp && cmp <= 0
+      end
+      if insert_at
+        map[key].insert(insert_at, new_matcher)
+      else
+        map[key] << new_matcher
+      end
+      map
     end
 
+    #
     # Get a value from the NodeMap via applying the node to the filters that
     # were set on the key.
     #
-    # @param node [Chef::Node] The Chef::Node object for the run
+    # @param node [Chef::Node] The Chef::Node object for the run, or `nil` to
+    #   ignore all filters.
     # @param key [Object] Key to look up
+    # @param canonical [Boolean] `true` or `false` to match canonical or
+    #   non-canonical values only. `nil` to ignore canonicality.  Default: `nil`
+    #
     # @return [Object] Value
     #
-    def get(node, key)
-      # FIXME: real exception
-      raise "first argument must be a Chef::Node" unless node.is_a?(Chef::Node)
-      return nil unless @map.has_key?(key)
-      @map[key].each do |matcher|
-        if filters_match?(node, matcher[:filters]) &&
-          block_matches?(node, matcher[:block])
-          return matcher[:value]
-        end
-      end
-      nil
+    def get(node, key, canonical: nil)
+      raise ArgumentError, "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) || node.nil?
+      list(node, key, canonical: canonical).first
     end
 
-    private
-
-    # only allow valid filter options
-    def validate_filter!(filters)
-      filters.each_key do |key|
-        # FIXME: real exception
-        raise "Bad key #{key} in Chef::NodeMap filter expression" unless VALID_OPTS.include?(key)
-      end
+    #
+    # List all matches for the given node and key from the NodeMap, from
+    # most-recently added to oldest.
+    #
+    # @param node [Chef::Node] The Chef::Node object for the run, or `nil` to
+    #   ignore all filters.
+    # @param key [Object] Key to look up
+    # @param canonical [Boolean] `true` or `false` to match canonical or
+    #   non-canonical values only. `nil` to ignore canonicality.  Default: `nil`
+    #
+    # @return [Object] Value
+    #
+    def list(node, key, canonical: nil)
+      raise ArgumentError, "first argument must be a Chef::Node" unless node.is_a?(Chef::Node) || node.nil?
+      return [] unless map.has_key?(key)
+      map[key].select do |matcher|
+        node_matches?(node, matcher) && canonical_matches?(canonical, matcher)
+      end.map { |matcher| matcher[:value] }
     end
 
-    # warn on deprecated filter options
-    def deprecate_filter!(filters)
-      filters.each_key do |key|
-        Chef::Log.warn "The #{key} option to node_map has been deprecated" if DEPRECATED_OPTS.include?(key)
+    # Seriously, don't use this, it's nearly certain to change on you
+    # @return remaining
+    # @api private
+    def delete_canonical(key, value)
+      remaining = map[key]
+      if remaining
+        remaining.delete_if { |matcher| matcher[:canonical] && Array(matcher[:value]) == Array(value) }
+        if remaining.empty?
+          map.delete(key)
+          remaining = nil
+        end
       end
+      remaining
     end
 
-    # @todo: this works fine, but is probably hard to understand
-    def negative_match(filter, param)
-      # We support strings prefaced by '!' to mean 'not'.  In particular, this is most useful
-      # for os matching on '!windows'.
-      negative_matches = filter.select { |f| f[0] == '!' }
-      return true if !negative_matches.empty? && negative_matches.include?('!' + param)
+    protected
+
+    #
+    # Succeeds if:
+    # - no negative matches (!value)
+    # - at least one positive match (value or :all), or no positive filters
+    #
+    def matches_black_white_list?(node, filters, attribute)
+      # It's super common for the filter to be nil.  Catch that so we don't
+      # spend any time here.
+      return true if !filters[attribute]
+      filter_values = Array(filters[attribute])
+      value = node[attribute]
+
+      # Split the blacklist and whitelist
+      blacklist, whitelist = filter_values.partition { |v| v.is_a?(String) && v.start_with?("!") }
 
-      # We support the symbol :all to match everything, for backcompat, but this can and should
-      # simply be ommitted.
-      positive_matches = filter.reject { |f| f[0] == '!' || f == :all }
-      return true if !positive_matches.empty? && !positive_matches.include?(param)
+      # If any blacklist value matches, we don't match
+      return false if blacklist.any? { |v| v[1..-1] == value }
 
-      # sorry double-negative: this means we pass this filter.
-      false
+      # If the whitelist is empty, or anything matches, we match.
+      whitelist.empty? || whitelist.any? { |v| v == :all || v == value }
+    end
+
+    def matches_version_list?(node, filters, attribute)
+      # It's super common for the filter to be nil.  Catch that so we don't
+      # spend any time here.
+      return true if !filters[attribute]
+      filter_values = Array(filters[attribute])
+      value = node[attribute]
+
+      filter_values.empty? ||
+        Array(filter_values).any? do |v|
+          Chef::VersionConstraint::Platform.new(v).include?(value)
+        end
     end
 
     def filters_match?(node, filters)
-      return true if filters.empty?
+      matches_black_white_list?(node, filters, :os) &&
+        matches_black_white_list?(node, filters, :platform_family) &&
+        matches_black_white_list?(node, filters, :platform) &&
+        matches_version_list?(node, filters, :platform_version)
+    end
+
+    def block_matches?(node, block)
+      return true if block.nil?
+      block.call node
+    end
 
-      # each filter is applied in turn.  if any fail, then it shortcuts and returns false.
-      # if it passes or does not exist it succeeds and continues on.  so multiple filters are
-      # effectively joined by 'and'.  all filters can be single strings, or arrays which are
-      # effectively joined by 'or'.
+    def node_matches?(node, matcher)
+      return true if !node
+      filters_match?(node, matcher[:filters]) && block_matches?(node, matcher[:block])
+    end
 
-      os_filter = [ filters[:os] ].flatten.compact
-      unless os_filter.empty?
-        return false if negative_match(os_filter, node[:os])
-      end
+    def canonical_matches?(canonical, matcher)
+      return true if canonical.nil?
+      !!canonical == !!matcher[:canonical]
+    end
 
-      platform_family_filter = [ filters[:platform_family] ].flatten.compact
-      unless platform_family_filter.empty?
-        return false if negative_match(platform_family_filter, node[:platform_family])
-      end
+    def compare_matchers(key, new_matcher, matcher)
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:block] }
+      return cmp if cmp != 0
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_version] }
+      return cmp if cmp != 0
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform] }
+      return cmp if cmp != 0
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:platform_family] }
+      return cmp if cmp != 0
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:filters][:os] }
+      return cmp if cmp != 0
+      cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:override] }
+      return cmp if cmp != 0
+      # If all things are identical, return 0
+      0
+    end
 
-      # :on_platform and :on_platforms here are synonyms which are deprecated
-      platform_filter = [ filters[:platform] || filters[:on_platform] || filters[:on_platforms] ].flatten.compact
-      unless platform_filter.empty?
-        return false if negative_match(platform_filter, node[:platform])
+    def compare_matcher_properties(new_matcher, matcher)
+      a = yield(new_matcher)
+      b = yield(matcher)
+
+      # Check for blcacklists ('!windows'). Those always come *after* positive
+      # whitelists.
+      a_negated = Array(a).any? { |f| f.is_a?(String) && f.start_with?("!") }
+      b_negated = Array(b).any? { |f| f.is_a?(String) && f.start_with?("!") }
+      if a_negated != b_negated
+        return 1 if a_negated
+        return -1 if b_negated
       end
 
-      return true
+      # We treat false / true and nil / not-nil with the same comparison
+      a = nil if a == false
+      b = nil if b == false
+      cmp = a <=> b
+      # This is the case where one is non-nil, and one is nil. The one that is
+      # nil is "greater" (i.e. it should come last).
+      if cmp.nil?
+        return 1 if a.nil?
+        return -1 if b.nil?
+      end
+      cmp
     end
 
-    def block_matches?(node, block)
-      return true if block.nil?
-      block.call node
+    def map
+      @map ||= {}
     end
   end
 end
diff --git a/lib/chef/null_logger.rb b/lib/chef/null_logger.rb
index 5195cc5..927cfc0 100644
--- a/lib/chef/null_logger.rb
+++ b/lib/chef/null_logger.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -42,7 +42,7 @@ class Chef
     def debug(message, &block)
     end
 
-    def add(severity, message=nil, progname=nil)
+    def add(severity, message = nil, progname = nil)
     end
 
     def <<(message)
diff --git a/lib/chef/org.rb b/lib/chef/org.rb
index 41d74b6..a148e37 100644
--- a/lib/chef/org.rb
+++ b/lib/chef/org.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (steve at opscode.com)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
-require 'chef/mixin/params_validate'
-require 'chef/rest'
+require "chef/json_compat"
+require "chef/mixin/params_validate"
+require "chef/server_api"
 
 class Chef
   class Org
@@ -27,7 +27,7 @@ class Chef
 
     def initialize(name)
       @name = name
-      @full_name = ''
+      @full_name = ""
       # The Chef API returns the private key of the validator
       # client on create
       @private_key = nil
@@ -35,25 +35,25 @@ class Chef
     end
 
     def chef_rest
-      @chef_rest ||= Chef::REST.new(Chef::Config[:chef_server_root])
+      @chef_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root])
     end
 
-    def name(arg=nil)
+    def name(arg = nil)
       set_or_return(:name, arg,
                     :regex => /^[a-z0-9\-_]+$/)
     end
 
-    def full_name(arg=nil)
+    def full_name(arg = nil)
       set_or_return(:full_name,
                     arg, :kind_of => String)
     end
 
-    def private_key(arg=nil)
+    def private_key(arg = nil)
       set_or_return(:private_key,
                     arg, :kind_of => String)
     end
 
-    def guid(arg=nil)
+    def guid(arg = nil)
       set_or_return(:guid,
                     arg, :kind_of => String)
     end
@@ -61,7 +61,7 @@ class Chef
     def to_hash
       result = {
         "name" => @name,
-        "full_name" => @full_name
+        "full_name" => @full_name,
       }
       result["private_key"] = @private_key if @private_key
       result["guid"] = @guid if @guid
@@ -73,19 +73,19 @@ class Chef
     end
 
     def create
-      payload = {:name => self.name, :full_name => self.full_name}
-      new_org = chef_rest.post_rest("organizations", payload)
+      payload = { :name => self.name, :full_name => self.full_name }
+      new_org = chef_rest.post("organizations", payload)
       Chef::Org.from_hash(self.to_hash.merge(new_org))
     end
 
     def update
-      payload = {:name => self.name, :full_name => self.full_name}
-      new_org = chef_rest.put_rest("organizations/#{name}", payload)
+      payload = { :name => self.name, :full_name => self.full_name }
+      new_org = chef_rest.put("organizations/#{name}", payload)
       Chef::Org.from_hash(self.to_hash.merge(new_org))
     end
 
     def destroy
-      chef_rest.delete_rest("organizations/#{@name}")
+      chef_rest.delete("organizations/#{@name}")
     end
 
     def save
@@ -101,22 +101,22 @@ class Chef
     end
 
     def associate_user(username)
-      request_body = {:user => username}
-      response = chef_rest.post_rest "organizations/#{@name}/association_requests", request_body
+      request_body = { :user => username }
+      response = chef_rest.post "organizations/#{@name}/association_requests", request_body
       association_id = response["uri"].split("/").last
-      chef_rest.put_rest "users/#{username}/association_requests/#{association_id}", { :response => 'accept' }
+      chef_rest.put "users/#{username}/association_requests/#{association_id}", { :response => "accept" }
     end
 
     def dissociate_user(username)
-      chef_rest.delete_rest "organizations/#{name}/users/#{username}"
+      chef_rest.delete "organizations/#{name}/users/#{username}"
     end
 
     # Class methods
     def self.from_hash(org_hash)
-      org = Chef::Org.new(org_hash['name'])
-      org.full_name org_hash['full_name']
-      org.private_key org_hash['private_key'] if org_hash.key?('private_key')
-      org.guid org_hash['guid'] if org_hash.key?('guid')
+      org = Chef::Org.new(org_hash["name"])
+      org.full_name org_hash["full_name"]
+      org.private_key org_hash["private_key"] if org_hash.key?("private_key")
+      org.guid org_hash["guid"] if org_hash.key?("guid")
       org
     end
 
@@ -124,17 +124,18 @@ class Chef
       Chef::Org.from_hash(Chef::JSONCompat.from_json(json))
     end
 
-    class <<self
-      alias_method :json_create, :from_json
+    def self.json_create(json)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Org#from_json or Chef::Org#load.")
+      Chef::Org.from_json(json)
     end
 
     def self.load(org_name)
-      response =  Chef::REST.new(Chef::Config[:chef_server_root]).get_rest("organizations/#{org_name}")
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("organizations/#{org_name}")
       Chef::Org.from_hash(response)
     end
 
-    def self.list(inflate=false)
-      orgs = Chef::REST.new(Chef::Config[:chef_server_root]).get_rest('organizations')
+    def self.list(inflate = false)
+      orgs = Chef::ServerAPI.new(Chef::Config[:chef_server_root]).get("organizations")
       if inflate
         orgs.inject({}) do |org_map, (name, _url)|
           org_map[name] = Chef::Org.load(name)
diff --git a/lib/chef/platform.rb b/lib/chef/platform.rb
index 841aa1b..1657152 100644
--- a/lib/chef/platform.rb
+++ b/lib/chef/platform.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 #
 
 # Order of these headers is important: query helpers is needed by many things
-require 'chef/platform/query_helpers'
-require 'chef/platform/provider_mapping'
+require "chef/platform/query_helpers"
+require "chef/platform/provider_mapping"
 
 class Chef
   class Platform
diff --git a/lib/chef/platform/handler_map.rb b/lib/chef/platform/handler_map.rb
new file mode 100644
index 0000000..da8f842
--- /dev/null
+++ b/lib/chef/platform/handler_map.rb
@@ -0,0 +1,40 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/node_map"
+
+class Chef
+  class Platform
+    class HandlerMap < Chef::NodeMap
+      #
+      # "provides" lines with identical filters sort by class name (ascending).
+      #
+      def compare_matchers(key, new_matcher, matcher)
+        cmp = super
+        if cmp == 0
+          # Sort by class name (ascending) as well, if all other properties
+          # are exactly equal
+          if new_matcher[:value].is_a?(Class) && !new_matcher[:override]
+            cmp = compare_matcher_properties(new_matcher, matcher) { |m| m[:value].name }
+          end
+        end
+        cmp
+      end
+    end
+  end
+end
diff --git a/lib/chef/platform/priority_map.rb b/lib/chef/platform/priority_map.rb
new file mode 100644
index 0000000..c36d00e
--- /dev/null
+++ b/lib/chef/platform/priority_map.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/node_map"
+
+class Chef
+  class Platform
+    class PriorityMap < Chef::NodeMap
+      def priority(resource_name, priority_array, *filter)
+        set_priority_array(resource_name.to_sym, priority_array, *filter)
+      end
+
+      # @api private
+      def get_priority_array(node, key)
+        get(node, key)
+      end
+
+      # @api private
+      def set_priority_array(key, priority_array, *filter, &block)
+        priority_array = Array(priority_array)
+        set(key, priority_array, *filter, &block)
+        priority_array
+      end
+    end
+  end
+end
diff --git a/lib/chef/platform/provider_handler_map.rb b/lib/chef/platform/provider_handler_map.rb
new file mode 100644
index 0000000..26acf15
--- /dev/null
+++ b/lib/chef/platform/provider_handler_map.rb
@@ -0,0 +1,29 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "singleton"
+require "chef/platform/handler_map"
+
+class Chef
+  class Platform
+    # @api private
+    class ProviderHandlerMap < Chef::Platform::HandlerMap
+      include Singleton
+    end
+  end
+end
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 0d72857..39d415e 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/exceptions'
-require 'chef/mixin/params_validate'
-require 'chef/version_constraint/platform'
-
-# This file depends on nearly every provider in chef, but requiring them
-# directly causes circular requires resulting in uninitialized constant errors.
-# Therefore, we do the includes inline rather than up top.
-require 'chef/provider'
-
+require "chef/log"
+require "chef/exceptions"
+require "chef/mixin/params_validate"
+require "chef/version_constraint/platform"
+require "chef/provider"
 
 class Chef
   class Platform
@@ -34,267 +29,7 @@ class Chef
       attr_writer :platforms
 
       def platforms
-        @platforms ||= begin
-          require 'chef/providers'
-
-          {
-            :freebsd => {
-              :default => {
-                :group   => Chef::Provider::Group::Pw,
-                :user    => Chef::Provider::User::Pw,
-              }
-            },
-            :ubuntu   => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Debian,
-              },
-              ">= 11.10" => {
-                :ifconfig => Chef::Provider::Ifconfig::Debian
-              }
-              # Chef::Provider::Service::Upstart is a candidate to be used in
-              # ubuntu versions >= 13.10 but it currently requires all the
-              # services to have an entry under /etc/init. We need to update it
-              # to use the service ctl apis in order to migrate to using it on
-              # ubuntu >= 13.10.
-            },
-            :gcel   => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Debian,
-              }
-            },
-            :linaro   => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Debian,
-              }
-            },
-            :raspbian   => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Debian,
-              }
-            },
-            :linuxmint   => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Upstart,
-              }
-            },
-            :debian => {
-              :default => {
-                :package => Chef::Provider::Package::Apt,
-                :service => Chef::Provider::Service::Debian,
-              },
-              ">= 6.0" => {
-                :service => Chef::Provider::Service::Insserv
-              },
-              ">= 7.0" => {
-                :ifconfig => Chef::Provider::Ifconfig::Debian
-              }
-            },
-            :xenserver   => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Yum,
-              }
-            },
-            :xcp   => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Yum,
-              }
-            },
-            :centos   => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Yum,
-                :ifconfig => Chef::Provider::Ifconfig::Redhat
-              },
-              "< 7" => {
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :amazon   => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Yum,
-              }
-            },
-            :scientific => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Yum,
-              },
-              "< 7" => {
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :fedora   => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Yum,
-                :ifconfig => Chef::Provider::Ifconfig::Redhat
-              },
-              "< 15" => {
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :opensuse     => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Zypper,
-                :group => Chef::Provider::Group::Suse
-              },
-              # Only OpenSuSE 12.3+ should use the Usermod group provider:
-              ">= 12.3" => {
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :suse     => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Zypper,
-                :group => Chef::Provider::Group::Gpasswd
-              },
-              "< 12.0" => {
-                :group => Chef::Provider::Group::Suse,
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :oracle  => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Yum,
-              },
-              "< 7" => {
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :redhat   => {
-              :default => {
-                :service => Chef::Provider::Service::Systemd,
-                :package => Chef::Provider::Package::Yum,
-                :ifconfig => Chef::Provider::Ifconfig::Redhat
-              },
-              "< 7" => {
-                :service => Chef::Provider::Service::Redhat
-              }
-            },
-            :ibm_powerkvm   => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Yum,
-                :ifconfig => Chef::Provider::Ifconfig::Redhat
-              }
-            },
-            :cloudlinux   => {
-              :default => {
-                :service => Chef::Provider::Service::Redhat,
-                :package => Chef::Provider::Package::Yum,
-                :ifconfig => Chef::Provider::Ifconfig::Redhat
-              }
-            },
-            :parallels   => {
-                :default => {
-                    :service => Chef::Provider::Service::Redhat,
-                    :package => Chef::Provider::Package::Yum,
-                    :ifconfig => Chef::Provider::Ifconfig::Redhat
-                }
-            },
-            :gentoo   => {
-              :default => {
-                :package => Chef::Provider::Package::Portage,
-                :service => Chef::Provider::Service::Gentoo,
-              }
-            },
-            :arch   => {
-              :default => {
-                :package => Chef::Provider::Package::Pacman,
-                :service => Chef::Provider::Service::Systemd,
-              }
-            },
-            :solaris  => {},
-            :openindiana => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Ips,
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :opensolaris => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Ips,
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :nexentacore => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Solaris,
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :omnios => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Ips,
-                :group => Chef::Provider::Group::Usermod,
-                :user => Chef::Provider::User::Solaris,
-              }
-            },
-            :solaris2 => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Ips,
-                :group => Chef::Provider::Group::Usermod,
-                :user => Chef::Provider::User::Solaris,
-              },
-              "< 5.11" => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::Solaris,
-                :group => Chef::Provider::Group::Usermod,
-                :user => Chef::Provider::User::Solaris,
-              }
-            },
-            :smartos => {
-              :default => {
-                :mount => Chef::Provider::Mount::Solaris,
-                :package => Chef::Provider::Package::SmartOS,
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :hpux => {
-              :default => {
-                :group => Chef::Provider::Group::Usermod
-              }
-            },
-            :aix => {
-              :default => {
-                :group => Chef::Provider::Group::Aix,
-                :mount => Chef::Provider::Mount::Aix,
-                :ifconfig => Chef::Provider::Ifconfig::Aix,
-                :package => Chef::Provider::Package::Aix,
-                :user => Chef::Provider::User::Aix,
-                :service => Chef::Provider::Service::Aix
-              }
-            },
-            :exherbo => {
-              :default => {
-                :package => Chef::Provider::Package::Paludis,
-                :service => Chef::Provider::Service::Systemd,
-              }
-            },
-            :default => {
-              :mount => Chef::Provider::Mount::Mount,
-              :user => Chef::Provider::User::Useradd,
-              :group => Chef::Provider::Group::Gpasswd,
-              :ifconfig => Chef::Provider::Ifconfig,
-            }
-          }
-        end
+        @platforms ||= { default: {} }
       end
 
       include Chef::Mixin::ParamsValidate
@@ -304,13 +39,13 @@ class Chef
 
         name_sym = name
         if name.kind_of?(String)
-          name.downcase!
+          name = name.downcase
           name.gsub!(/\s/, "_")
           name_sym = name.to_sym
         end
 
         if platforms.has_key?(name_sym)
-          platform_versions = platforms[name_sym].select {|k, v| k != :default }
+          platform_versions = platforms[name_sym].select { |k, v| k != :default }
           if platforms[name_sym].has_key?(:default)
             provider_map.merge!(platforms[name_sym][:default])
           end
@@ -318,15 +53,13 @@ class Chef
             begin
               version_constraint = Chef::VersionConstraint::Platform.new(platform_version)
               if version_constraint.include?(version)
-                Chef::Log.debug("Platform #{name.to_s} version #{version} found")
+                Chef::Log.debug("Platform #{name} version #{version} found")
                 provider_map.merge!(provider)
               end
             rescue Chef::Exceptions::InvalidPlatformVersion
               Chef::Log.debug("Chef::Version::Comparable does not know how to parse the platform version: #{version}")
             end
           end
-        else
-          Chef::Log.debug("Platform #{name} not found, using all defaults. (Unsupported platform?)")
         end
         provider_map
       end
@@ -356,7 +89,7 @@ class Chef
         return platform, version
       end
 
-      def provider_for_resource(resource, action=:nothing)
+      def provider_for_resource(resource, action = :nothing)
         node = resource.run_context && resource.run_context.node
         raise ArgumentError, "Cannot find the provider for a resource with no run context set" unless node
         provider = find_provider_for_node(node, resource).new(resource, resource.run_context)
@@ -386,12 +119,12 @@ class Chef
               :required => false,
             },
             :resource => {
-              :kind_of => Symbol,
+              :kind_of => Symbol
             },
             :provider => {
-              :kind_of => [ String, Symbol, Class ],
-            }
-          }
+              :kind_of => [ String, Symbol, Class ]
+            },
+          },
         )
         if args.has_key?(:platform)
           if args.has_key?(:version)
@@ -443,34 +176,38 @@ class Chef
                          platform_provider(platform, version, resource_type) ||
                          resource_matching_provider(platform, version, resource_type)
 
-        raise ArgumentError, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil?
+        raise Chef::Exceptions::ProviderNotFound, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil?
 
         provider_klass
       end
 
       private
 
-        def explicit_provider(platform, version, resource_type)
-          resource_type.kind_of?(Chef::Resource) ? resource_type.provider : nil
-        end
+      def explicit_provider(platform, version, resource_type)
+        resource_type.kind_of?(Chef::Resource) ? resource_type.provider : nil
+      end
 
-        def platform_provider(platform, version, resource_type)
-          pmap = Chef::Platform.find(platform, version)
-          rtkey = resource_type.kind_of?(Chef::Resource) ? resource_type.resource_name.to_sym : resource_type
-          pmap.has_key?(rtkey) ? pmap[rtkey] : nil
-        end
+      def platform_provider(platform, version, resource_type)
+        pmap = Chef::Platform.find(platform, version)
+        rtkey = resource_type.kind_of?(Chef::Resource) ? resource_type.resource_name.to_sym : resource_type
+        pmap.has_key?(rtkey) ? pmap[rtkey] : nil
+      end
 
-        def resource_matching_provider(platform, version, resource_type)
-          if resource_type.kind_of?(Chef::Resource)
-            begin
-              Chef::Provider.const_get(resource_type.class.to_s.split('::').last)
-            rescue NameError
-              nil
-            end
-          else
-            nil
+      include Chef::Mixin::ConvertToClassName
+
+      def resource_matching_provider(platform, version, resource_type)
+        if resource_type.kind_of?(Chef::Resource)
+          class_name = resource_type.class.name ? resource_type.class.name.split("::").last :
+            convert_to_class_name(resource_type.resource_name.to_s)
+
+          if Chef::Provider.const_defined?(class_name)
+            Chef::Log.warn("Class Chef::Provider::#{class_name} does not declare 'provides #{convert_to_snake_case(class_name).to_sym.inspect}'.")
+            Chef::Log.warn("This will no longer work in Chef 13: you must use 'provides' to use the resource's DSL.")
+            return Chef::Provider.const_get(class_name)
           end
         end
+        nil
+      end
 
     end
   end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index 1539f61..0c8a728 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -1,92 +1,11 @@
+require "singleton"
+require "chef/platform/priority_map"
 
 class Chef
   class Platform
-    class ProviderPriorityMap
+    # @api private
+    class ProviderPriorityMap < Chef::Platform::PriorityMap
       include Singleton
-
-      def initialize
-        load_default_map
-      end
-
-      def get_priority_array(node, resource_name)
-        priority_map.get(node, resource_name.to_sym)
-      end
-
-      def set_priority_array(resource_name, priority_array, *filter)
-        priority(resource_name.to_sym, priority_array.to_a, *filter)
-      end
-
-      def priority(*args)
-        priority_map.set(*args)
-      end
-
-      private
-
-      def load_default_map
-        require 'chef/providers'
-
-        #
-        # Linux
-        #
-
-        # default block for linux O/Sen must come before platform_family exceptions
-        priority :service, [
-          Chef::Provider::Service::Systemd,
-          Chef::Provider::Service::Insserv,
-          Chef::Provider::Service::Redhat,
-        ], os: "linux"
-
-        priority :service, [
-          Chef::Provider::Service::Systemd,
-          Chef::Provider::Service::Arch,
-        ], platform_family: "arch"
-
-        priority :service, [
-          Chef::Provider::Service::Systemd,
-          Chef::Provider::Service::Gentoo,
-        ], platform_family: "gentoo"
-
-        priority :service, [
-          # we can determine what systemd supports accurately
-          Chef::Provider::Service::Systemd,
-          # on debian-ish system if an upstart script exists that must win over sysv types
-          Chef::Provider::Service::Upstart,
-          Chef::Provider::Service::Insserv,
-          Chef::Provider::Service::Debian,
-          Chef::Provider::Service::Invokercd,
-        ], platform_family: "debian"
-
-        priority :service, [
-          Chef::Provider::Service::Systemd,
-          Chef::Provider::Service::Insserv,
-          Chef::Provider::Service::Redhat,
-        ], platform_family: [ "rhel", "fedora", "suse" ]
-
-        #
-        # BSDen
-        #
-
-        priority :service, Chef::Provider::Service::Freebsd, os: [ "freebsd", "netbsd" ]
-        priority :service, Chef::Provider::Service::Openbsd, os: [ "openbsd" ]
-
-        #
-        # Solaris-en
-        #
-
-        priority :service, Chef::Provider::Service::Solaris, os: "solaris2"
-
-        #
-        # Mac
-        #
-
-        priority :service, Chef::Provider::Service::Macosx, os: "darwin"
-        priority :package, Chef::Provider::Package::Homebrew, os: "darwin"
-      end
-
-      def priority_map
-        require 'chef/node_map'
-        @priority_map ||= Chef::NodeMap.new
-      end
     end
   end
 end
diff --git a/lib/chef/platform/query_helpers.rb b/lib/chef/platform/query_helpers.rb
index f7c85fb..7d52207 100644
--- a/lib/chef/platform/query_helpers.rb
+++ b/lib/chef/platform/query_helpers.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,39 +21,92 @@ class Chef
 
     class << self
       def windows?
-        if RUBY_PLATFORM =~ /mswin|mingw|windows/
-          true
-        else
-          false
-        end
+        ChefConfig.windows?
       end
 
       def windows_server_2003?
+        # WMI startup shouldn't be performed unless we're on Windows.
         return false unless windows?
-        require 'wmi-lite/wmi'
-
-        # CHEF-4888: Work around ruby #2618, expected to be fixed in Ruby 2.1.0
-        # https://github.com/ruby/ruby/commit/588504b20f5cc880ad51827b93e571e32446e5db
-        # https://github.com/ruby/ruby/commit/27ed294c7134c0de582007af3c915a635a6506cd
+        require "wmi-lite/wmi"
 
         wmi = WmiLite::Wmi.new
-        host = wmi.first_of('Win32_OperatingSystem')
-        is_server_2003 = (host['version'] && host['version'].start_with?("5.2"))
+        host = wmi.first_of("Win32_OperatingSystem")
+        is_server_2003 = (host["version"] && host["version"].start_with?("5.2"))
 
         is_server_2003
       end
 
+      def windows_nano_server?
+        return false unless windows?
+        require "win32/registry"
+
+        # This method may be called before ohai runs (e.g., it may be used to
+        # determine settings in config.rb). Chef::Win32::Registry.new uses
+        # node attributes to verify the machine architecture which aren't
+        # accessible before ohai runs.
+        nano = nil
+        key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Server\\ServerLevels"
+        access = ::Win32::Registry::KEY_QUERY_VALUE | 0x0100 # nano is 64-bit only
+        begin
+          ::Win32::Registry::HKEY_LOCAL_MACHINE.open(key, access) do |reg|
+            nano = reg["NanoServer"]
+          end
+        rescue ::Win32::Registry::Error
+          # If accessing the registry key failed, then we're probably not on
+          # nano. Fail through.
+        end
+        return nano == 1
+      end
+
+      def supports_msi?
+        return false unless windows?
+        require "win32/registry"
+
+        key = "System\\CurrentControlSet\\Services\\msiserver"
+        access = ::Win32::Registry::KEY_QUERY_VALUE
+
+        begin
+          ::Win32::Registry::HKEY_LOCAL_MACHINE.open(key, access) do |reg|
+            true
+          end
+        rescue ::Win32::Registry::Error
+          false
+        end
+      end
+
+      def supports_powershell_execution_bypass?(node)
+        node[:languages] && node[:languages][:powershell] &&
+          node[:languages][:powershell][:version].to_i >= 3
+      end
+
       def supports_dsc?(node)
         node[:languages] && node[:languages][:powershell] &&
           node[:languages][:powershell][:version].to_i >= 4
       end
 
       def supports_dsc_invoke_resource?(node)
-        require 'rubygems'
         supports_dsc?(node) &&
-          Gem::Version.new(node[:languages][:powershell][:version]) >=
-            Gem::Version.new("5.0.10018.0")
+          supported_powershell_version?(node, "5.0.10018.0")
+      end
+
+      def supports_refresh_mode_enabled?(node)
+        supported_powershell_version?(node, "5.0.10586.0")
+      end
+
+      def dsc_refresh_mode_disabled?(node)
+        require "chef/util/powershell/cmdlet"
+        cmdlet = Chef::Util::Powershell::Cmdlet.new(node, "Get-DscLocalConfigurationManager", :object)
+        metadata = cmdlet.run!.return_value
+        metadata["RefreshMode"] == "Disabled"
       end
+
+      def supported_powershell_version?(node, version_string)
+        return false unless node[:languages] && node[:languages][:powershell]
+        require "rubygems"
+        Gem::Version.new(node[:languages][:powershell][:version]) >=
+          Gem::Version.new(version_string)
+      end
+
     end
   end
 end
diff --git a/lib/chef/platform/rebooter.rb b/lib/chef/platform/rebooter.rb
index b46f0e3..c678b60 100644
--- a/lib/chef/platform/rebooter.rb
+++ b/lib/chef/platform/rebooter.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Chris Doherty <cdoherty at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/dsl/reboot_pending'
-require 'chef/log'
-require 'chef/platform'
+require "chef/dsl/reboot_pending"
+require "chef/log"
+require "chef/platform"
 
 class Chef
   class Platform
@@ -31,12 +31,12 @@ class Chef
           reboot_info = node.run_context.reboot_info
 
           cmd = if Chef::Platform.windows?
-            # should this do /f as well? do we then need a minimum delay to let apps quit?
-            "shutdown /r /t #{reboot_info[:delay_mins]} /c \"#{reboot_info[:reason]}\""
-          else
-            # probably Linux-only.
-            "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
-          end
+                  # should this do /f as well? do we then need a minimum delay to let apps quit?
+                  "shutdown /r /t #{reboot_info[:delay_mins] * 60} /c \"#{reboot_info[:reason]}\""
+                else
+                  # probably Linux-only.
+                  "shutdown -r +#{reboot_info[:delay_mins]} \"#{reboot_info[:reason]}\""
+                end
 
           Chef::Log.warn "Rebooting server at a recipe's request. Details: #{reboot_info.inspect}"
           shell_out!(cmd)
diff --git a/lib/chef/platform/resource_handler_map.rb b/lib/chef/platform/resource_handler_map.rb
new file mode 100644
index 0000000..be1b9c2
--- /dev/null
+++ b/lib/chef/platform/resource_handler_map.rb
@@ -0,0 +1,29 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "singleton"
+require "chef/platform/handler_map"
+
+class Chef
+  class Platform
+    # @api private
+    class ResourceHandlerMap < Chef::Platform::HandlerMap
+      include Singleton
+    end
+  end
+end
diff --git a/lib/chef/platform/resource_priority_map.rb b/lib/chef/platform/resource_priority_map.rb
index fc43b3e..1871dcd 100644
--- a/lib/chef/platform/resource_priority_map.rb
+++ b/lib/chef/platform/resource_priority_map.rb
@@ -1,37 +1,11 @@
+require "singleton"
+require "chef/platform/priority_map"
+
 class Chef
   class Platform
-    class ResourcePriorityMap
+    # @api private
+    class ResourcePriorityMap < Chef::Platform::PriorityMap
       include Singleton
-
-      def initialize
-        load_default_map
-      end
-
-      def get_priority_array(node, resource_name)
-        priority_map.get(node, resource_name.to_sym)
-      end
-
-      def set_priority_array(resource_name, priority_array, *filter)
-        priority resource_name.to_sym, priority_array.to_a, *filter
-      end
-
-      def priority(*args)
-        priority_map.set(*args)
-      end
-
-      private
-
-      def load_default_map
-        require 'chef/resources'
-
-        # MacOSX
-        priority :package, Chef::Resource::HomebrewPackage, os: "darwin"
-      end
-
-      def priority_map
-        require 'chef/node_map'
-        @priority_map ||= Chef::NodeMap.new
-      end
     end
   end
 end
diff --git a/lib/chef/platform/service_helpers.rb b/lib/chef/platform/service_helpers.rb
index dc0a808..87b87d4 100644
--- a/lib/chef/platform/service_helpers.rb
+++ b/lib/chef/platform/service_helpers.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,12 @@
 # limitations under the License.
 #
 
-# XXX: mixing shellout into a mixin into classes has to be code smell
-require 'chef/mixin/shell_out'
-require 'chef/mixin/which'
+require "chef/chef_class"
 
 class Chef
   class Platform
     class ServiceHelpers
       class << self
-
-        include Chef::Mixin::ShellOut
-        include Chef::Mixin::Which
-
         # This helper is mostly used to sort out the mess of different
         # linux mechanisms that can be used to start services.  It does
         # not necessarily need to linux-specific, but currently all our
@@ -42,60 +36,59 @@ class Chef
         # different services is NOT a design concern of this module.
         #
         def service_resource_providers
-          service_resource_providers = []
+          providers = []
 
-          if ::File.exist?("/usr/sbin/update-rc.d")
-            service_resource_providers << :debian
+          if ::File.exist?(Chef.path_to("/usr/sbin/update-rc.d"))
+            providers << :debian
           end
 
-          if ::File.exist?("/usr/sbin/invoke-rc.d")
-            service_resource_providers << :invokercd
+          if ::File.exist?(Chef.path_to("/usr/sbin/invoke-rc.d"))
+            providers << :invokercd
           end
 
-          if ::File.exist?("/sbin/insserv")
-            service_resource_providers << :insserv
+          if ::File.exist?(Chef.path_to("/sbin/initctl"))
+            providers << :upstart
           end
 
-          # debian >= 6.0 has /etc/init but does not have upstart
-          if ::File.exist?("/etc/init") && ::File.exist?("/sbin/start")
-            service_resource_providers << :upstart
+          if ::File.exist?(Chef.path_to("/sbin/insserv"))
+            providers << :insserv
           end
 
-          if ::File.exist?("/sbin/chkconfig")
-            service_resource_providers << :redhat
+          if systemd_is_init?
+            providers << :systemd
           end
 
-          if systemd_sanity_check?
-            service_resource_providers << :systemd
+          if ::File.exist?(Chef.path_to("/sbin/chkconfig"))
+            providers << :redhat
           end
 
-          service_resource_providers
+          providers
         end
 
         def config_for_service(service_name)
           configs = []
 
-          if ::File.exist?("/etc/init.d/#{service_name}")
+          if ::File.exist?(Chef.path_to("/etc/init.d/#{service_name}"))
             configs << :initd
           end
 
-          if ::File.exist?("/etc/init/#{service_name}.conf")
+          if ::File.exist?(Chef.path_to("/etc/init/#{service_name}.conf"))
             configs << :upstart
           end
 
-          if ::File.exist?("/etc/xinetd.d/#{service_name}")
+          if ::File.exist?(Chef.path_to("/etc/xinetd.d/#{service_name}"))
             configs << :xinetd
           end
 
-          if ::File.exist?("/etc/rc.d/#{service_name}")
+          if ::File.exist?(Chef.path_to("/etc/rc.d/#{service_name}"))
             configs << :etc_rcd
           end
 
-          if ::File.exist?("/usr/local/etc/rc.d/#{service_name}")
+          if ::File.exist?(Chef.path_to("/usr/local/etc/rc.d/#{service_name}"))
             configs << :usr_local_etc_rcd
           end
 
-          if systemd_sanity_check? && platform_has_systemd_unit?(service_name)
+          if has_systemd_service_unit?(service_name) || has_systemd_unit?(service_name)
             configs << :systemd
           end
 
@@ -104,37 +97,24 @@ class Chef
 
         private
 
-        def systemctl_path
-          if @systemctl_path.nil?
-            @systemctl_path = which("systemctl")
-          end
-          @systemctl_path
-        end
-
-        def systemd_sanity_check?
-          systemctl_path && File.exist?("/proc/1/comm") && File.open("/proc/1/comm").gets.chomp == "systemd"
+        def systemd_is_init?
+          ::File.exist?(Chef.path_to("/proc/1/comm")) &&
+            ::File.open(Chef.path_to("/proc/1/comm")).gets.chomp == "systemd"
         end
 
-        def extract_systemd_services(command)
-          output = shell_out!(command).stdout
-          # first line finds e.g. "sshd.service"
-          services = []
-          output.each_line do |line|
-            fields = line.split
-            services << fields[0] if fields[1] == "loaded" || fields[1] == "not-found"
+        def has_systemd_service_unit?(svc_name)
+          %w{ /etc /usr/lib /lib /run }.any? do |load_path|
+            ::File.exist?(
+              Chef.path_to("#{load_path}/systemd/system/#{svc_name.gsub(/@.*$/, '@')}.service")
+            )
           end
-          # this splits off the suffix after the last dot to return "sshd"
-          services += services.select {|s| s.match(/\.service$/) }.map { |s| s.sub(/(.*)\.service$/, '\1') }
-        rescue Mixlib::ShellOut::ShellCommandFailed
-          false
         end
 
-        def platform_has_systemd_unit?(service_name)
-          services = extract_systemd_services("#{systemctl_path} --all") +
-            extract_systemd_services("#{systemctl_path} list-unit-files")
-          services.include?(service_name)
-        rescue Mixlib::ShellOut::ShellCommandFailed
-          false
+        def has_systemd_unit?(svc_name)
+          # TODO: stop supporting non-service units with service resource
+          %w{ /etc /usr/lib /lib /run }.any? do |load_path|
+            ::File.exist?(Chef.path_to("#{load_path}/systemd/system/#{svc_name}"))
+          end
         end
       end
     end
diff --git a/lib/chef/policy_builder.rb b/lib/chef/policy_builder.rb
index 136b285..56533e9 100644
--- a/lib/chef/policy_builder.rb
+++ b/lib/chef/policy_builder.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/policy_builder/expand_node_object'
-require 'chef/policy_builder/policyfile'
+require "chef/policy_builder/expand_node_object"
+require "chef/policy_builder/policyfile"
+require "chef/policy_builder/dynamic"
 
 class Chef
 
@@ -37,13 +38,5 @@ class Chef
   # * cookbook_hash is stored in run_context
   module PolicyBuilder
 
-    def self.strategy
-      if Chef::Config[:use_policyfile]
-        Policyfile
-      else
-        ExpandNodeObject
-      end
-    end
-
   end
 end
diff --git a/lib/chef/policy_builder/dynamic.rb b/lib/chef/policy_builder/dynamic.rb
new file mode 100644
index 0000000..22438a1
--- /dev/null
+++ b/lib/chef/policy_builder/dynamic.rb
@@ -0,0 +1,185 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "forwardable"
+
+require "chef/log"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/exceptions"
+
+class Chef
+  module PolicyBuilder
+
+    # PolicyBuilder that selects either a Policyfile or non-Policyfile
+    # implementation based on the content of the node object.
+    class Dynamic
+
+      extend Forwardable
+
+      attr_reader :node
+      attr_reader :node_name
+      attr_reader :ohai_data
+      attr_reader :json_attribs
+      attr_reader :override_runlist
+      attr_reader :events
+
+      def initialize(node_name, ohai_data, json_attribs, override_runlist, events)
+        @implementation = nil
+
+        @node_name = node_name
+        @ohai_data = ohai_data
+        @json_attribs = json_attribs
+        @override_runlist = override_runlist
+        @events = events
+
+        @node = nil
+      end
+
+      ## PolicyBuilder API ##
+
+      # Loads the node state from the server, then picks the correct
+      # implementation class based on the node and json_attribs.
+      #
+      # Calls #finish_load_node on the implementation object to complete the
+      # loading process. All subsequent lifecycle calls are delegated.
+      #
+      # @return [Chef::Node] the loaded node.
+      def load_node
+        events.node_load_start(node_name, config)
+        Chef::Log.debug("Building node object for #{node_name}")
+
+        @node =
+          if Chef::Config[:solo]
+            Chef::Node.build(node_name)
+          else
+            Chef::Node.find_or_create(node_name)
+          end
+        select_implementation(node)
+        implementation.finish_load_node(node)
+        node
+      rescue Exception => e
+        events.node_load_failed(node_name, e, config)
+        raise
+      end
+
+      ## Delegated Public API Methods ##
+
+      ### Accessors ###
+
+      def_delegator :implementation, :original_runlist
+      def_delegator :implementation, :run_context
+      def_delegator :implementation, :run_list_expansion
+
+      ### Lifecycle Methods ###
+
+      # @!method build_node
+      #
+      # Applies external attributes (e.g., from JSON file, environment,
+      # policyfile, etc.) and determines the correct expanded run list for the
+      # run.
+      #
+      # @return [Chef::Node]
+      def_delegator :implementation, :build_node
+
+      # @!method setup_run_context
+      #
+      # Synchronizes cookbooks and initializes the run context object for the
+      # run.
+      #
+      # @return [Chef::RunContext]
+      def_delegator :implementation, :setup_run_context
+
+      # @!method expanded_run_list
+      #
+      # Resolves the run list to a form containing only recipes and sets the
+      # `roles` and `recipes` automatic attributes on the node.
+      #
+      # @return [#recipes, #roles] A RunListExpansion or duck-type.
+      def_delegator :implementation, :expand_run_list
+
+      # @!method sync_cookbooks
+      #
+      # Synchronizes cookbooks. In a normal chef-client run, this is handled by
+      # #setup_run_context, but may be called directly in some circumstances.
+      #
+      # @return [Hash{String => Chef::CookbookManifest}] A map of
+      #   CookbookManifest objects by cookbook name.
+      def_delegator :implementation, :sync_cookbooks
+
+      # @!method temporary_policy?
+      #
+      # Indicates whether the policy is temporary, which means an
+      # override_runlist was provided. Chef::Client uses this to decide whether
+      # to do the final node save at the end of the run or not.
+      #
+      # @return [true,false]
+      def_delegator :implementation, :temporary_policy?
+
+      ## Internal Public API ##
+
+      # Returns the selected implementation, or raises if not set. The
+      # implementation is set when #load_node is called.
+      #
+      # @return [PolicyBuilder::Policyfile, PolicyBuilder::ExpandNodeObject]
+      def implementation
+        @implementation or raise Exceptions::InvalidPolicybuilderCall, "#load_node must be called before other policy builder methods"
+      end
+
+      # @api private
+      #
+      # Sets the implementation based on the content of the node, node JSON
+      # (i.e., the `-j JSON_FILE` data), and config. This is only public for
+      # testing purposes; production code should call #load_node instead.
+      def select_implementation(node)
+        if policyfile_set_in_config? ||
+           policyfile_attribs_in_node_json? ||
+           node_has_policyfile_attrs?(node) ||
+           policyfile_compat_mode_config?
+          @implementation = Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events)
+        else
+          @implementation = ExpandNodeObject.new(node_name, ohai_data, json_attribs, override_runlist, events)
+        end
+      end
+
+      def config
+        Chef::Config
+      end
+
+      private
+
+      def node_has_policyfile_attrs?(node)
+        node.policy_name || node.policy_group
+      end
+
+      def policyfile_attribs_in_node_json?
+        json_attribs.key?("policy_name") || json_attribs.key?("policy_group")
+      end
+
+      def policyfile_set_in_config?
+        config[:use_policyfile] || config[:policy_name] || config[:policy_group]
+      end
+
+      def policyfile_compat_mode_config?
+        config[:deployment_group] && !config[:policy_document_native_api]
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 524bdd9..b69ecfe 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,12 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/rest'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/node'
-require 'chef/chef_class'
+require "chef/log"
+require "chef/server_api"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/chef_class"
 
 class Chef
   module PolicyBuilder
@@ -33,6 +33,9 @@ class Chef
     # expands the run_list on a node object and then queries the chef-server
     # to find the correct set of cookbooks, given version constraints of the
     # node's environment.
+    #
+    # Note that this class should only be used via PolicyBuilder::Dynamic and
+    # not instantiated directly.
     class ExpandNodeObject
 
       attr_reader :events
@@ -55,26 +58,29 @@ class Chef
         @run_list_expansion = nil
       end
 
-      # This method injects the run_context and provider and resource priority
-      # maps into the Chef class.  The run_context has to be injected here, the provider and
-      # resource maps could be moved if a better place can be found to do this work.
+      # This method injects the run_context and into the Chef class.
+      #
+      # NOTE: This is duplicated with the Policyfile implementation. If
+      # it gets any more complicated, it needs to be moved elsewhere.
       #
       # @param run_context [Chef::RunContext] the run_context to inject
       def setup_chef_class(run_context)
         Chef.set_run_context(run_context)
       end
 
-      def setup_run_context(specific_recipes=nil)
+      def setup_run_context(specific_recipes = nil)
         if Chef::Config[:solo]
           Chef::Cookbook::FileVendor.fetch_from_disk(Chef::Config[:cookbook_path])
           cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
           cl.load_cookbooks
           cookbook_collection = Chef::CookbookCollection.new(cl)
+          cookbook_collection.validate!
           run_context = Chef::RunContext.new(node, cookbook_collection, @events)
         else
           Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
           cookbook_hash = sync_cookbooks
           cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
+          cookbook_collection.validate!
           run_context = Chef::RunContext.new(node, cookbook_collection, @events)
         end
 
@@ -93,25 +99,36 @@ class Chef
         run_context
       end
 
-
-      # In client-server operation, loads the node state from the server. In
-      # chef-solo operation, builds a new node object.
+      # DEPRECATED: As of Chef 12.5, chef selects either policyfile mode or
+      # "expand node" mode dynamically, based on the content of the node
+      # object, first boot JSON, and config. This happens in
+      # PolicyBuilder::Dynamic, which selects the implementation during
+      # #load_node and then delegates to either ExpandNodeObject or Policyfile
+      # implementations as appropriate. Tools authors should update their code
+      # to create a PolicyBuilder::Dynamc policy builder and allow it to select
+      # the proper implementation.
       def load_node
-        events.node_load_start(node_name, Chef::Config)
+        Chef.log_deprecation("ExpandNodeObject#load_node is deprecated. Please use Chef::PolicyBuilder::Dynamic instead of using ExpandNodeObject directly")
+
+        events.node_load_start(node_name, config)
         Chef::Log.debug("Building node object for #{node_name}")
 
-        if Chef::Config[:solo]
-          @node = Chef::Node.build(node_name)
-        else
-          @node = Chef::Node.find_or_create(node_name)
-        end
+        @node =
+          if Chef::Config[:solo]
+            Chef::Node.build(node_name)
+          else
+            Chef::Node.find_or_create(node_name)
+          end
+        finish_load_node(node)
+        node
       rescue Exception => e
-        # TODO: wrap this exception so useful error info can be given to the
-        # user.
-        events.node_load_failed(node_name, e, Chef::Config)
+        events.node_load_failed(node_name, e, config)
         raise
       end
 
+      def finish_load_node(node)
+        @node = node
+      end
 
       # Applies environment, external JSON attributes, and override run list to
       # the node, Then expands the run_list.
@@ -139,6 +156,7 @@ class Chef
         Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]")
 
         events.node_load_completed(node, @expanded_run_list_with_versions, Chef::Config)
+        events.run_list_expanded(@run_list_expansion)
 
         node
       end
@@ -146,10 +164,10 @@ class Chef
       # Expands the node's run list. Stores the run_list_expansion object for later use.
       def expand_run_list
         @run_list_expansion = if Chef::Config[:solo]
-          node.expand!('disk')
-        else
-          node.expand!('server')
-        end
+                                node.expand!("disk")
+                              else
+                                node.expand!("server")
+                              end
 
         # @run_list_expansion is a RunListExpansion.
         #
@@ -180,7 +198,12 @@ class Chef
         begin
           events.cookbook_resolution_start(@expanded_run_list_with_versions)
           cookbook_hash = api_service.post("environments/#{node.chef_environment}/cookbook_versions",
-                                         {:run_list => @expanded_run_list_with_versions})
+                                           { :run_list => @expanded_run_list_with_versions })
+
+          cookbook_hash = cookbook_hash.inject({}) do |memo, (key, value)|
+            memo[key] = Chef::CookbookVersion.from_hash(value)
+            memo
+          end
         rescue Exception => e
           # TODO: wrap/munge exception to provide helpful error output
           events.cookbook_resolution_failed(@expanded_run_list_with_versions, e)
@@ -226,7 +249,7 @@ class Chef
       def runlist_override_sanity_check!
         # Convert to array and remove whitespace
         if override_runlist.is_a?(String)
-          @override_runlist = override_runlist.split(',').map { |e| e.strip }
+          @override_runlist = override_runlist.split(",").map { |e| e.strip }
         end
         @override_runlist = [override_runlist].flatten.compact
         override_runlist.map! do |item|
@@ -239,7 +262,7 @@ class Chef
       end
 
       def api_service
-        @api_service ||= Chef::REST.new(config[:chef_server_url])
+        @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
       end
 
       def config
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index ac25b54..9a6e62b 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2008-2014 Chef Software, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,11 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/rest'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/node'
+require "chef/log"
+require "chef/run_context"
+require "chef/config"
+require "chef/node"
+require "chef/server_api"
 
 class Chef
   module PolicyBuilder
@@ -68,22 +68,20 @@ class Chef
 
         @node = nil
 
-        Chef::Log.warn("Using experimental Policyfile feature")
-
         if Chef::Config[:solo]
-          raise UnsupportedFeature, "Policyfile does not support chef-solo at this time."
+          raise UnsupportedFeature, "Policyfile does not support chef-solo. Use chef-client local mode instead."
         end
 
         if override_runlist
-          raise UnsupportedFeature, "Policyfile does not support override run lists at this time"
+          raise UnsupportedFeature, "Policyfile does not support override run lists. Use named run_lists instead."
         end
 
         if json_attribs && json_attribs.key?("run_list")
-          raise UnsupportedFeature, "Policyfile does not support setting the run_list in json data at this time"
+          raise UnsupportedFeature, "Policyfile does not support setting the run_list in json data."
         end
 
         if Chef::Config[:environment] && !Chef::Config[:environment].chomp.empty?
-          raise UnsupportedFeature, "Policyfile does not work with Chef Environments"
+          raise UnsupportedFeature, "Policyfile does not work with Chef Environments."
         end
       end
 
@@ -112,17 +110,11 @@ class Chef
 
       ## PolicyBuilder API ##
 
-      # Loads the node state from the server.
-      def load_node
-        events.node_load_start(node_name, Chef::Config)
-        Chef::Log.debug("Building node object for #{node_name}")
-
-        @node = Chef::Node.find_or_create(node_name)
+      def finish_load_node(node)
+        @node = node
+        select_policy_name_and_group
         validate_policyfile
-        node
-      rescue Exception => e
-        events.node_load_failed(node_name, e, Chef::Config)
-        raise
+        events.policyfile_loaded(policy)
       end
 
       # Applies environment, external JSON attributes, and override run list to
@@ -144,7 +136,6 @@ class Chef
         Chef::Log.info("Run List is [#{run_list}]")
         Chef::Log.info("Run List expands to [#{run_list_with_versions_for_display.join(', ')}]")
 
-
         events.node_load_completed(node, run_list_with_versions_for_display, Chef::Config)
 
         node
@@ -153,25 +144,43 @@ class Chef
         raise
       end
 
-      def setup_run_context(specific_recipes=nil)
+      # Synchronizes cookbooks and initializes the run context object for the
+      # run.
+      #
+      # @return [Chef::RunContext]
+      def setup_run_context(specific_recipes = nil)
         Chef::Cookbook::FileVendor.fetch_from_remote(http_api)
         sync_cookbooks
         cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
+        cookbook_collection.validate!
         run_context = Chef::RunContext.new(node, cookbook_collection, events)
 
+        setup_chef_class(run_context)
+
         run_context.load(run_list_expansion_ish)
 
+        setup_chef_class(run_context)
         run_context
       end
 
+      # Sets `run_list` on the node from the policy, sets `roles` and `recipes`
+      # attributes on the node accordingly.
+      #
+      # @return [RunListExpansionIsh] A RunListExpansion duck-type.
       def expand_run_list
+        CookbookCacheCleaner.instance.skip_removal = true if named_run_list_requested?
+
         node.run_list(run_list)
         node.automatic_attrs[:roles] = []
         node.automatic_attrs[:recipes] = run_list_expansion_ish.recipes
         run_list_expansion_ish
       end
 
-
+      # Synchronizes cookbooks. In a normal chef-client run, this is handled by
+      # #setup_run_context, but may be called directly in some circumstances.
+      #
+      # @return [Hash{String => Chef::CookbookManifest}] A map of
+      #   CookbookManifest objects by cookbook name.
       def sync_cookbooks
         Chef::Log.debug("Synchronizing cookbooks")
         synchronizer = Chef::CookbookSynchronizer.new(cookbooks_to_sync, events)
@@ -185,12 +194,18 @@ class Chef
 
       # Whether or not this is a temporary policy. Since PolicyBuilder doesn't
       # support override_runlist, this is always false.
+      #
+      # @return [false]
       def temporary_policy?
         false
       end
 
       ## Internal Public API ##
 
+      # @api private
+      #
+      # Generates an array of strings with recipe names including version and
+      # identifier info.
       def run_list_with_versions_for_display
         run_list.map do |recipe_spec|
           cookbook, recipe = parse_recipe_spec(recipe_spec)
@@ -200,6 +215,11 @@ class Chef
         end
       end
 
+      # @api private
+      #
+      # Sets up a RunListExpansionIsh object so that it can be used in place of
+      # a RunListExpansion object, to satisfy the API contract of
+      # #expand_run_list
       def run_list_expansion_ish
         recipes = run_list.map do |recipe_spec|
           cookbook, recipe = parse_recipe_spec(recipe_spec)
@@ -208,11 +228,15 @@ class Chef
         RunListExpansionIsh.new(recipes, [])
       end
 
+      # @api private
+      #
+      # Sets attributes from the policyfile on the node, using the role priority.
       def apply_policyfile_attributes
         node.attributes.role_default = policy["default_attributes"]
         node.attributes.role_override = policy["override_attributes"]
       end
 
+      # @api private
       def parse_recipe_spec(recipe_spec)
         rmatch = recipe_spec.match(/recipe\[([^:]+)::([^:]+)\]/)
         if rmatch.nil?
@@ -222,20 +246,31 @@ class Chef
         end
       end
 
+      # @api private
       def cookbook_lock_for(cookbook_name)
         cookbook_locks[cookbook_name]
       end
 
+      # @api private
       def run_list
-        policy["run_list"]
+        if named_run_list_requested?
+          named_run_list or
+            raise ConfigurationError,
+            "Policy '#{retrieved_policy_name}' revision '#{revision_id}' does not have named_run_list '#{named_run_list_name}'" +
+              "(available named_run_lists: [#{available_named_run_lists.join(', ')}])"
+        else
+          policy["run_list"]
+        end
       end
 
+      # @api private
       def policy
         @policy ||= http_api.get(policyfile_location)
       rescue Net::HTTPServerException => e
         raise ConfigurationError, "Error loading policyfile from `#{policyfile_location}': #{e.class} - #{e.message}"
       end
 
+      # @api private
       def policyfile_location
         if Chef::Config[:policy_document_native_api]
           validate_policy_config!
@@ -272,6 +307,7 @@ class Chef
         end
       end
 
+      # @api private
       def validate_recipe_spec(recipe_spec)
         parse_recipe_spec(recipe_spec)
         nil
@@ -281,11 +317,13 @@ class Chef
 
       class ConfigurationError < StandardError; end
 
+      # @api private
       def deployment_group
         Chef::Config[:deployment_group] or
           raise ConfigurationError, "Setting `deployment_group` is not configured."
       end
 
+      # @api private
       def validate_policy_config!
         policy_group or
           raise ConfigurationError, "Setting `policy_group` is not configured."
@@ -294,14 +332,75 @@ class Chef
           raise ConfigurationError, "Setting `policy_name` is not configured."
       end
 
+      # @api private
       def policy_group
         Chef::Config[:policy_group]
       end
 
+      # @api private
       def policy_name
         Chef::Config[:policy_name]
       end
 
+      # @api private
+      #
+      # Selects the `policy_name` and `policy_group` from the following sources
+      # in priority order:
+      #
+      # 1. JSON attribs (i.e., `-j JSON_FILE`)
+      # 2. `Chef::Config`
+      # 3. The node object
+      #
+      # The selected values are then copied to `Chef::Config` and the node.
+      def select_policy_name_and_group
+        policy_name_to_set =
+          policy_name_from_json_attribs ||
+          policy_name_from_config ||
+          policy_name_from_node
+
+        policy_group_to_set =
+          policy_group_from_json_attribs ||
+          policy_group_from_config ||
+          policy_group_from_node
+
+        node.policy_name = policy_name_to_set
+        node.policy_group = policy_group_to_set
+
+        Chef::Config[:policy_name] = policy_name_to_set
+        Chef::Config[:policy_group] = policy_group_to_set
+      end
+
+      # @api private
+      def policy_group_from_json_attribs
+        json_attribs["policy_group"]
+      end
+
+      # @api private
+      def policy_name_from_json_attribs
+        json_attribs["policy_name"]
+      end
+
+      # @api private
+      def policy_group_from_config
+        Chef::Config[:policy_group]
+      end
+
+      # @api private
+      def policy_name_from_config
+        Chef::Config[:policy_name]
+      end
+
+      # @api private
+      def policy_group_from_node
+        node.policy_group
+      end
+
+      # @api private
+      def policy_name_from_node
+        node.policy_name
+      end
+
+      # @api private
       # Builds a 'cookbook_hash' map of the form
       #   "COOKBOOK_NAME" => "IDENTIFIER"
       #
@@ -329,6 +428,7 @@ class Chef
         raise
       end
 
+      # @api private
       # Fetches the CookbookVersion object for the given name and identifer
       # specified in the lock_data.
       # TODO: This only implements Chef 11 compatibility mode, which means that
@@ -342,20 +442,58 @@ class Chef
         end
       end
 
+      # @api private
       def cookbook_locks
         policy["cookbook_locks"]
       end
 
+      # @api private
+      def revision_id
+        policy["revision_id"]
+      end
+
+      # @api private
       def http_api
-        @api_service ||= Chef::REST.new(config[:chef_server_url])
+        @api_service ||= Chef::ServerAPI.new(config[:chef_server_url])
       end
 
+      # @api private
       def config
         Chef::Config
       end
 
       private
 
+      # This method injects the run_context and into the Chef class.
+      #
+      # NOTE: This is duplicated with the ExpandNodeObject implementation. If
+      # it gets any more complicated, it needs to be moved elsewhere.
+      #
+      # @param run_context [Chef::RunContext] the run_context to inject
+      def setup_chef_class(run_context)
+        Chef.set_run_context(run_context)
+      end
+
+      def retrieved_policy_name
+        policy["name"]
+      end
+
+      def named_run_list
+        policy["named_run_lists"] && policy["named_run_lists"][named_run_list_name]
+      end
+
+      def available_named_run_lists
+        (policy["named_run_lists"] || {}).keys
+      end
+
+      def named_run_list_requested?
+        !!Chef::Config[:named_run_list]
+      end
+
+      def named_run_list_name
+        Chef::Config[:named_run_list]
+      end
+
       def compat_mode_manifest_for(cookbook_name, lock_data)
         xyz_version = lock_data["dotted_decimal_identifier"]
         rel_url = "cookbooks/#{cookbook_name}/#{xyz_version}"
diff --git a/lib/chef/property.rb b/lib/chef/property.rb
new file mode 100644
index 0000000..8198dd6
--- /dev/null
+++ b/lib/chef/property.rb
@@ -0,0 +1,673 @@
+#
+# Author:: John Keiser <jkeiser at chef.io>
+# Copyright:: Copyright 2015-2016, John Keiser.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/exceptions"
+require "chef/delayed_evaluator"
+require "chef/chef_class"
+require "chef/log"
+
+class Chef
+  #
+  # Type and validation information for a property on a resource.
+  #
+  # A property named "x" manipulates the "@x" instance variable on a
+  # resource.  The *presence* of the variable (`instance_variable_defined?(@x)`)
+  # tells whether the variable is defined; it may have any actual value,
+  # constrained only by validation.
+  #
+  # Properties may have validation, defaults, and coercion, and have full
+  # support for lazy values.
+  #
+  # @see Chef::Resource.property
+  # @see Chef::DelayedEvaluator
+  #
+  class Property
+    #
+    # Create a reusable property type that can be used in multiple properties
+    # in different resources.
+    #
+    # @param options [Hash<Symbol,Object>] Validation options. See Chef::Resource.property for
+    #   the list of options.
+    #
+    # @example
+    #   Property.derive(default: 'hi')
+    #
+    def self.derive(**options)
+      new(**options)
+    end
+
+    #
+    # Create a new property.
+    #
+    # @param options [Hash<Symbol,Object>] Property options, including
+    #   control options here, as well as validation options (see
+    #   Chef::Mixin::ParamsValidate#validate for a description of validation
+    #   options).
+    #   @option options [Symbol] :name The name of this property.
+    #   @option options [Class] :declared_in The class this property comes from.
+    #   @option options [Symbol] :instance_variable_name The instance variable
+    #     tied to this property. Must include a leading `@`. Defaults to `@<name>`.
+    #     `nil` means the property is opaque and not tied to a specific instance
+    #     variable.
+    #   @option options [Boolean] :desired_state `true` if this property is part of desired
+    #     state. Defaults to `true`.
+    #   @option options [Boolean] :identity `true` if this property is part of object
+    #     identity. Defaults to `false`.
+    #   @option options [Boolean] :name_property `true` if this
+    #     property defaults to the same value as `name`. Equivalent to
+    #     `default: lazy { name }`, except that #property_is_set? will
+    #     return `true` if the property is set *or* if `name` is set.
+    #   @option options [Object] :default The value this property
+    #     will return if the user does not set one. If this is `lazy`, it will
+    #     be run in the context of the instance (and able to access other
+    #     properties) and cached. If not, the value will be frozen with Object#freeze
+    #     to prevent users from modifying it in an instance.
+    #   @option options [Proc] :coerce A proc which will be called to
+    #     transform the user input to canonical form. The value is passed in,
+    #     and the transformed value returned as output. Lazy values will *not*
+    #     be passed to this method until after they are evaluated. Called in the
+    #     context of the resource (meaning you can access other properties).
+    #   @option options [Boolean] :required `true` if this property
+    #     must be present; `false` otherwise. This is checked after the resource
+    #     is fully initialized.
+    #
+    def initialize(**options)
+      options.each { |k, v| options[k.to_sym] = v; options.delete(k) if k.is_a?(String) }
+      @options = options
+      options[:name] = options[:name].to_sym if options[:name]
+      options[:instance_variable_name] = options[:instance_variable_name].to_sym if options[:instance_variable_name]
+
+      # Replace name_attribute with name_property
+      if options.has_key?(:name_attribute)
+        # If we have both name_attribute and name_property and they differ, raise an error
+        if options.has_key?(:name_property)
+          raise ArgumentError, "Cannot specify both name_property and name_attribute together on property #{self}."
+        end
+        # replace name_property with name_attribute in place
+        options = Hash[options.map { |k, v| k == :name_attribute ? [ :name_property, v ] : [ k, v ] }]
+        @options = options
+      end
+
+      # Only pick the first of :default, :name_property and :name_attribute if
+      # more than one is specified.
+      if options.has_key?(:default) && options[:name_property]
+        if options[:default].nil? || options.keys.index(:name_property) < options.keys.index(:default)
+          options.delete(:default)
+          preferred_default = :name_property
+        else
+          options.delete(:name_property)
+          preferred_default = :default
+        end
+        Chef.log_deprecation("Cannot specify both default and name_property together on property #{self}. Only one (#{preferred_default}) will be obeyed. In Chef 13, this will become an error. Please remove one or the other from the property.")
+      end
+
+      # Validate the default early, so the user gets a good error message, and
+      # cache it so we don't do it again if so
+      begin
+        # If we can validate it all the way to output, do it.
+        @stored_default = input_to_stored_value(nil, default, is_default: true)
+      rescue Chef::Exceptions::CannotValidateStaticallyError
+        # If the validation is not static (i.e. has procs), we will have to
+        # coerce and validate the default each time we run
+      end
+    end
+
+    def to_s
+      "#{name || "<property type>"}#{declared_in ? " of resource #{declared_in.resource_name}" : ""}"
+    end
+
+    #
+    # The name of this property.
+    #
+    # @return [String]
+    #
+    def name
+      options[:name]
+    end
+
+    #
+    # The class this property was defined in.
+    #
+    # @return [Class]
+    #
+    def declared_in
+      options[:declared_in]
+    end
+
+    #
+    # The instance variable associated with this property.
+    #
+    # Defaults to `@<name>`
+    #
+    # @return [Symbol]
+    #
+    def instance_variable_name
+      if options.has_key?(:instance_variable_name)
+        options[:instance_variable_name]
+      elsif name
+        :"@#{name}"
+      end
+    end
+
+    #
+    # The raw default value for this resource.
+    #
+    # Does not coerce or validate the default. Does not evaluate lazy values.
+    #
+    # Defaults to `lazy { name }` if name_property is true; otherwise defaults to
+    # `nil`
+    #
+    def default
+      return options[:default] if options.has_key?(:default)
+      return Chef::DelayedEvaluator.new { name } if name_property?
+      nil
+    end
+
+    #
+    # Whether this is part of the resource's natural identity or not.
+    #
+    # @return [Boolean]
+    #
+    def identity?
+      options[:identity]
+    end
+
+    #
+    # Whether this is part of desired state or not.
+    #
+    # Defaults to true.
+    #
+    # @return [Boolean]
+    #
+    def desired_state?
+      return true if !options.has_key?(:desired_state)
+      options[:desired_state]
+    end
+
+    #
+    # Whether this is name_property or not.
+    #
+    # @return [Boolean]
+    #
+    def name_property?
+      options[:name_property]
+    end
+
+    #
+    # Whether this property has a default value.
+    #
+    # @return [Boolean]
+    #
+    def has_default?
+      options.has_key?(:default) || name_property?
+    end
+
+    #
+    # Whether this property is required or not.
+    #
+    # @return [Boolean]
+    #
+    def required?
+      options[:required]
+    end
+
+    #
+    # Validation options.  (See Chef::Mixin::ParamsValidate#validate.)
+    #
+    # @return [Hash<Symbol,Object>]
+    #
+    def validation_options
+      @validation_options ||= options.reject { |k, v|
+        [:declared_in, :name, :instance_variable_name, :desired_state, :identity, :default, :name_property, :coerce, :required].include?(k)
+      }
+    end
+
+    #
+    # Handle the property being called.
+    #
+    # The base implementation does the property get-or-set:
+    #
+    # ```ruby
+    # resource.myprop # get
+    # resource.myprop value # set
+    # ```
+    #
+    # Subclasses may implement this with any arguments they want, as long as
+    # the corresponding DSL calls it correctly.
+    #
+    # @param resource [Chef::Resource] The resource to get the property from.
+    # @param value The value to set (or NOT_PASSED if it is a get).
+    #
+    # @return The current value of the property. If it is a `set`, lazy values
+    #   will be returned without running, validating or coercing. If it is a
+    #   `get`, the non-lazy, coerced, validated value will always be returned.
+    #
+    def call(resource, value = NOT_PASSED)
+      if value == NOT_PASSED
+        return get(resource)
+      end
+
+      if value.nil?
+        # In Chef 12, value(nil) does a *get* instead of a set, so we
+        # warn if the value would have been changed. In Chef 13, it will be
+        # equivalent to value = nil.
+        result = get(resource)
+
+        # Warn about this becoming a set in Chef 13.
+        begin
+          input_to_stored_value(resource, value)
+          # If nil is valid, and it would change the value, warn that this will change to a set.
+          if !result.nil?
+            Chef.log_deprecation("An attempt was made to change #{name} from #{result.inspect} to nil by calling #{name}(nil). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil.")
+          end
+        rescue Chef::Exceptions::DeprecatedFeatureError
+          raise
+        rescue
+          # If nil is invalid, warn that this will become an error.
+          Chef.log_deprecation("nil is an invalid value for #{self}. In Chef 13, this warning will change to an error. Error: #{$!}")
+        end
+
+        result
+      else
+        # Anything else, such as myprop(value) is a set
+        set(resource, value)
+      end
+    end
+
+    #
+    # Get the property value from the resource, handling lazy values,
+    # defaults, and validation.
+    #
+    # - If the property's value is lazy, it is evaluated, coerced and validated.
+    # - If the property has no value, and is required, raises ValidationFailed.
+    # - If the property has no value, but has a lazy default, it is evaluated,
+    #   coerced and validated. If the evaluated value is frozen, the resulting
+    # - If the property has no value, but has a default, the default value
+    #   will be returned and frozen. If the default value is lazy, it will be
+    #   evaluated, coerced and validated, and the result stored in the property.
+    # - If the property has no value, but is name_property, `resource.name`
+    #   is retrieved, coerced, validated and stored in the property.
+    # - Otherwise, `nil` is returned.
+    #
+    # @param resource [Chef::Resource] The resource to get the property from.
+    #
+    # @return The value of the property.
+    #
+    # @raise Chef::Exceptions::ValidationFailed If the value is invalid for
+    #   this property, or if the value is required and not set.
+    #
+    def get(resource)
+      # If it's set, return it (and evaluate any lazy values)
+      if is_set?(resource)
+        value = get_value(resource)
+        value = stored_value_to_output(resource, value)
+
+      else
+        # We are getting the default value.
+
+        # If the user does something like this:
+        #
+        # ```
+        # class MyResource < Chef::Resource
+        #   property :content
+        #   action :create do
+        #     file '/x.txt' do
+        #       content content
+        #     end
+        #   end
+        # end
+        # ```
+        #
+        # It won't do what they expect. This checks whether you try to *read*
+        # `content` while we are compiling the resource.
+        if resource.respond_to?(:resource_initializing) &&
+           resource.resource_initializing &&
+           resource.respond_to?(:enclosing_provider) &&
+           resource.enclosing_provider &&
+           resource.enclosing_provider.new_resource &&
+           resource.enclosing_provider.new_resource.respond_to?(name)
+          Chef::Log.warn("#{Chef::Log.caller_location}: property #{name} is declared in both #{resource} and #{resource.enclosing_provider}. Use new_resource.#{name} instead. At #{Chef::Log.caller_location}")
+        end
+
+        if has_default?
+          # If we were able to cache the stored_default, grab it.
+          if defined?(@stored_default)
+            value = @stored_default
+          else
+            # Otherwise, we have to validate it now.
+            value = input_to_stored_value(resource, default, is_default: true)
+          end
+          value = stored_value_to_output(resource, value, is_default: true)
+
+          # If the value is mutable (non-frozen), we set it on the instance
+          # so that people can mutate it.  (All constant default values are
+          # frozen.)
+          if !value.frozen? && !value.nil?
+            set_value(resource, value)
+          end
+
+          value
+
+        elsif required?
+          raise Chef::Exceptions::ValidationFailed, "#{name} is required"
+        end
+      end
+    end
+
+    #
+    # Set the value of this property in the given resource.
+    #
+    # Non-lazy values are coerced and validated before being set. Coercion
+    # and validation of lazy values is delayed until they are first retrieved.
+    #
+    # @param resource [Chef::Resource] The resource to set this property in.
+    # @param value The value to set.
+    #
+    # @return The value that was set, after coercion (if lazy, still returns
+    #   the lazy value)
+    #
+    # @raise Chef::Exceptions::ValidationFailed If the value is invalid for
+    #   this property.
+    #
+    def set(resource, value)
+      set_value(resource, input_to_stored_value(resource, value))
+    end
+
+    #
+    # Find out whether this property has been set.
+    #
+    # This will be true if:
+    # - The user explicitly set the value
+    # - The property has a default, and the value was retrieved.
+    #
+    # From this point of view, it is worth looking at this as "what does the
+    # user think this value should be." In order words, if the user grabbed
+    # the value, even if it was a default, they probably based calculations on
+    # it. If they based calculations on it and the value changes, the rest of
+    # the world gets inconsistent.
+    #
+    # @param resource [Chef::Resource] The resource to get the property from.
+    #
+    # @return [Boolean]
+    #
+    def is_set?(resource)
+      value_is_set?(resource)
+    end
+
+    #
+    # Reset the value of this property so that is_set? will return false and the
+    # default will be returned in the future.
+    #
+    # @param resource [Chef::Resource] The resource to get the property from.
+    #
+    def reset(resource)
+      reset_value(resource)
+    end
+
+    #
+    # Coerce an input value into canonical form for the property.
+    #
+    # After coercion, the value is suitable for storage in the resource.
+    # You must validate values after coercion, however.
+    #
+    # Does no special handling for lazy values.
+    #
+    # @param resource [Chef::Resource] The resource we're coercing against
+    #   (to provide context for the coerce).
+    # @param value The value to coerce.
+    #
+    # @return The coerced value.
+    #
+    # @raise Chef::Exceptions::ValidationFailed If the value is invalid for
+    #   this property.
+    #
+    def coerce(resource, value)
+      if options.has_key?(:coerce)
+        # If we have no default value, `nil` is never coerced or validated
+        unless !has_default? && value.nil?
+          value = exec_in_resource(resource, options[:coerce], value)
+        end
+      end
+      value
+    end
+
+    #
+    # Validate a value.
+    #
+    # Calls Chef::Mixin::ParamsValidate#validate with #validation_options as
+    # options.
+    #
+    # @param resource [Chef::Resource] The resource we're validating against
+    #   (to provide context for the validate).
+    # @param value The value to validate.
+    #
+    # @raise Chef::Exceptions::ValidationFailed If the value is invalid for
+    #   this property.
+    #
+    def validate(resource, value)
+      # If we have no default value, `nil` is never coerced or validated
+      unless value.nil? && !has_default?
+        if resource
+          resource.validate({ name => value }, { name => validation_options })
+        else
+          name = self.name || :property_type
+          Chef::Mixin::ParamsValidate.validate({ name => value }, { name => validation_options })
+        end
+      end
+    end
+
+    #
+    # Derive a new Property that is just like this one, except with some added or
+    # changed options.
+    #
+    # @param options [Hash<Symbol,Object>] List of options that would be passed
+    #   to #initialize.
+    #
+    # @return [Property] The new property type.
+    #
+    def derive(**modified_options)
+      # Since name_property, name_attribute and default override each other,
+      # if you specify one of them in modified_options it overrides anything in
+      # the original options.
+      options = self.options
+      if modified_options.has_key?(:name_property) ||
+         modified_options.has_key?(:name_attribute) ||
+         modified_options.has_key?(:default)
+        options = options.reject { |k, v| k == :name_attribute || k == :name_property || k == :default }
+      end
+      self.class.new(options.merge(modified_options))
+    end
+
+    #
+    # Emit the DSL for this property into the resource class (`declared_in`).
+    #
+    # Creates a getter and setter for the property.
+    #
+    def emit_dsl
+      # We don't create the getter/setter if it's a custom property; we will
+      # be using the existing getter/setter to manipulate it instead.
+      return if !instance_variable_name
+
+      # We prefer this form because the property name won't show up in the
+      # stack trace if you use `define_method`.
+      declared_in.class_eval <<-EOM, __FILE__, __LINE__ + 1
+        def #{name}(value=NOT_PASSED)
+          raise "Property #{name} of \#{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block_given?
+          self.class.properties[#{name.inspect}].call(self, value)
+        end
+        def #{name}=(value)
+          raise "Property #{name} of \#{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block_given?
+          self.class.properties[#{name.inspect}].set(self, value)
+        end
+      EOM
+    rescue SyntaxError
+      # If the name is not a valid ruby name, we use define_method.
+      declared_in.define_method(name) do |value = NOT_PASSED, &block|
+        raise "Property #{name} of #{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block
+        self.class.properties[name].call(self, value)
+      end
+      declared_in.define_method("#{name}=") do |value, &block|
+        raise "Property #{name} of #{self} cannot be passed a block! If you meant to create a resource named #{name} instead, you'll need to first rename the property." if block
+        self.class.properties[name].set(self, value)
+      end
+    end
+
+    protected
+
+    #
+    # The options this Property will use for get/set behavior and validation.
+    #
+    # @see #initialize for a list of valid options.
+    #
+    attr_reader :options
+
+    #
+    # Find out whether this type accepts nil explicitly.
+    #
+    # A type accepts nil explicitly if "is" allows nil, it validates as nil, *and* is not simply
+    # an empty type.
+    #
+    # A type is presumed to accept nil if it does coercion (which must handle nil).
+    #
+    # These examples accept nil explicitly:
+    # ```ruby
+    # property :a, [ String, nil ]
+    # property :a, [ String, NilClass ]
+    # property :a, [ String, proc { |v| v.nil? } ]
+    # ```
+    #
+    # This does not (because the "is" doesn't exist or doesn't have nil):
+    #
+    # ```ruby
+    # property :x, String
+    # ```
+    #
+    # These do not, even though nil would validate fine (because they do not
+    # have "is"):
+    #
+    # ```ruby
+    # property :a
+    # property :a, equal_to: [ 1, 2, 3, nil ]
+    # property :a, kind_of: [ String, NilClass ]
+    # property :a, respond_to: [ ]
+    # property :a, callbacks: { "a" => proc { |v| v.nil? } }
+    # ```
+    #
+    # @param resource [Chef::Resource] The resource we're coercing against
+    #   (to provide context for the coerce).
+    #
+    # @return [Boolean] Whether this value explicitly accepts nil.
+    #
+    # @api private
+    def explicitly_accepts_nil?(resource)
+      options.has_key?(:coerce) ||
+        (options.has_key?(:is) && resource.send(:_pv_is, { name => nil }, name, options[:is], raise_error: false))
+    end
+
+    def get_value(resource)
+      if instance_variable_name
+        resource.instance_variable_get(instance_variable_name)
+      else
+        resource.send(name)
+      end
+    end
+
+    def set_value(resource, value)
+      if instance_variable_name
+        resource.instance_variable_set(instance_variable_name, value)
+      else
+        resource.send(name, value)
+      end
+    end
+
+    def value_is_set?(resource)
+      if instance_variable_name
+        resource.instance_variable_defined?(instance_variable_name)
+      else
+        true
+      end
+    end
+
+    def reset_value(resource)
+      if instance_variable_name
+        if value_is_set?(resource)
+          resource.remove_instance_variable(instance_variable_name)
+        end
+      else
+        raise ArgumentError, "Property #{name} has no instance variable defined and cannot be reset"
+      end
+    end
+
+    def exec_in_resource(resource, proc, *args)
+      if resource
+        if proc.arity > args.size
+          value = proc.call(resource, *args)
+        else
+          value = resource.instance_exec(*args, &proc)
+        end
+      else
+        # If we don't have a resource yet, we can't exec in resource!
+        raise Chef::Exceptions::CannotValidateStaticallyError, "Cannot validate or coerce without a resource"
+      end
+    end
+
+    def input_to_stored_value(resource, value, is_default: false)
+      unless value.is_a?(DelayedEvaluator)
+        value = coerce_and_validate(resource, value, is_default: is_default)
+      end
+      value
+    end
+
+    def stored_value_to_output(resource, value, is_default: false)
+      # Crack open lazy values before giving the result to the user
+      if value.is_a?(DelayedEvaluator)
+        value = exec_in_resource(resource, value)
+        value = coerce_and_validate(resource, value, is_default: is_default)
+      end
+      value
+    end
+
+    # Coerces and validates the value. If the value is a default, it will warn
+    # the user that invalid defaults are bad mmkay, and return it as if it were
+    # valid.
+    def coerce_and_validate(resource, value, is_default: false)
+      result = coerce(resource, value)
+      begin
+        # If the input is from a default, we need to emit an invalid default warning on validate.
+        validate(resource, result)
+      rescue Chef::Exceptions::CannotValidateStaticallyError
+        # This one gets re-raised
+        raise
+      rescue
+        # Anything else is just an invalid default: in those cases, we just
+        # warn and return the (possibly coerced) value to the user.
+        if is_default
+          if value.nil?
+            Chef.log_deprecation("Default value nil is invalid for property #{self}. Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property (for example, 'property #{name.inspect}, [ String, nil ], default: nil'). Error: #{$!}")
+          else
+            Chef.log_deprecation("Default value #{value.inspect} is invalid for property #{self}. In Chef 13 this will become an error: #{$!}.")
+          end
+        else
+          raise
+        end
+      end
+
+      result
+    end
+  end
+end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 65a56cf..8bf6842 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, 2009-2016 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,25 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/from_file'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/enforce_ownership_and_permissions'
-require 'chef/mixin/why_run'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/provides'
-require 'chef/platform/service_helpers'
-require 'chef/node_map'
+require "chef/mixin/from_file"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/mixin/why_run"
+require "chef/mixin/shell_out"
+require "chef/mixin/powershell_out"
+require "chef/mixin/provides"
+require "chef/platform/service_helpers"
+require "chef/node_map"
+require "forwardable"
 
 class Chef
   class Provider
+    require "chef/mixin/why_run"
+    require "chef/mixin/shell_out"
+    require "chef/mixin/provides"
     include Chef::Mixin::WhyRun
     include Chef::Mixin::ShellOut
+    include Chef::Mixin::PowershellOut
     extend Chef::Mixin::Provides
 
     # supports the given resource and action (late binding)
@@ -60,6 +66,7 @@ class Chef
 
       @recipe_name = nil
       @cookbook_name = nil
+      self.class.include_resource_dsl_module(new_resource)
     end
 
     def whyrun_mode?
@@ -83,8 +90,11 @@ class Chef
       new_resource.cookbook_name
     end
 
+    def check_resource_semantics!
+    end
+
     def load_current_resource
-      raise Chef::Exceptions::Override, "You must override load_current_resource in #{self.to_s}"
+      raise Chef::Exceptions::Override, "You must override load_current_resource in #{self}"
     end
 
     def define_resource_requirements
@@ -94,7 +104,7 @@ class Chef
     end
 
     def action_nothing
-      Chef::Log.debug("Doing nothing for #{@new_resource.to_s}")
+      Chef::Log.debug("Doing nothing for #{@new_resource}")
       true
     end
 
@@ -102,18 +112,20 @@ class Chef
       run_context.events
     end
 
-    def run_action(action=nil)
+    def run_action(action = nil)
       @action = action unless action.nil?
 
       # TODO: it would be preferable to get the action to be executed in the
       # constructor...
 
+      check_resource_semantics!
+
       # user-defined LWRPs may include unsafe load_current_resource methods that cannot be run in whyrun mode
-      if !whyrun_mode? || whyrun_supported?
+      if whyrun_mode? && !whyrun_supported?
+        events.resource_current_state_load_bypassed(@new_resource, @action, @current_resource)
+      else
         load_current_resource
         events.resource_current_state_loaded(@new_resource, @action, @current_resource)
-      elsif whyrun_mode? && !whyrun_supported?
-        events.resource_current_state_load_bypassed(@new_resource, @action, @current_resource)
       end
 
       define_resource_requirements
@@ -126,9 +138,7 @@ class Chef
       # we can't execute the action.
       # in non-whyrun mode, this will still cause the action to be
       # executed normally.
-      if whyrun_supported? && !requirements.action_blocked?(@action)
-        send("action_#{@action}")
-      elsif whyrun_mode?
+      if whyrun_mode? && (!whyrun_supported? || requirements.action_blocked?(@action))
         events.resource_bypassed(@new_resource, @action, self)
       else
         send("action_#{@action}")
@@ -165,6 +175,226 @@ class Chef
       converge_actions.add_action(descriptions, &block)
     end
 
+    #
+    # Handle patchy convergence safely.
+    #
+    # - Does *not* call the block if the current_resource's properties match
+    #   the properties the user specified on the resource.
+    # - Calls the block if current_resource does not exist
+    # - Calls the block if the user has specified any properties in the resource
+    #   whose values are *different* from current_resource.
+    # - Does *not* call the block if why-run is enabled (just prints out text).
+    # - Prints out automatic green text saying what properties have changed.
+    #
+    # @param properties An optional list of property names (symbols). If not
+    #   specified, `new_resource.class.state_properties` will be used.
+    # @param converge_block The block to do the converging in.
+    #
+    # @return [Boolean] whether the block was executed.
+    #
+    def converge_if_changed(*properties, &converge_block)
+      if !converge_block
+        raise ArgumentError, "converge_if_changed must be passed a block!"
+      end
+
+      properties = new_resource.class.state_properties.map { |p| p.name } if properties.empty?
+      properties = properties.map { |p| p.to_sym }
+      if current_resource
+        # Collect the list of modified properties
+        specified_properties = properties.select { |property| new_resource.property_is_set?(property) }
+        modified = specified_properties.select { |p| new_resource.send(p) != current_resource.send(p) }
+        if modified.empty?
+          properties_str = if sensitive
+                             specified_properties.join(", ")
+                           else
+                             specified_properties.map { |p| "#{p}=#{new_resource.send(p).inspect}" }.join(", ")
+                           end
+          Chef::Log.debug("Skipping update of #{new_resource}: has not changed any of the specified properties #{properties_str}.")
+          return false
+        end
+
+        # Print the pretty green text and run the block
+        property_size = modified.map { |p| p.size }.max
+        modified.map! do |p|
+          properties_str = if sensitive
+                             "(suppressed sensitive property)"
+                           else
+                             "#{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})"
+                           end
+          "  set #{p.to_s.ljust(property_size)} to #{properties_str}"
+        end
+        converge_by([ "update #{current_resource.identity}" ] + modified, &converge_block)
+
+      else
+        # The resource doesn't exist. Mark that we are *creating* this, and
+        # write down any properties we are setting.
+        property_size = properties.map { |p| p.size }.max
+        created = properties.map do |property|
+          default = " (default value)" unless new_resource.property_is_set?(property)
+          properties_str = if sensitive
+                             "(suppressed sensitive property)"
+                           else
+                             new_resource.send(property).inspect
+                           end
+          "  set #{property.to_s.ljust(property_size)} to #{properties_str}#{default}"
+        end
+
+        converge_by([ "create #{new_resource.identity}" ] + created, &converge_block)
+      end
+      true
+    end
+
+    def self.provides(short_name, opts = {}, &block)
+      Chef.provider_handler_map.set(short_name, self, opts, &block)
+    end
+
+    def self.provides?(node, resource)
+      Chef::ProviderResolver.new(node, resource, :nothing).provided_by?(self)
+    end
+
+    #
+    # Include attributes, public and protected methods from this Resource in
+    # the provider.
+    #
+    # If this is set to true, delegate methods are included in the provider so
+    # that you can call (for example) `attrname` and it will call
+    # `new_resource.attrname`.
+    #
+    # The actual include does not happen until the first time the Provider
+    # is instantiated (so that we don't have to worry about load order issues).
+    #
+    # @param include_resource_dsl [Boolean] Whether to include resource DSL or
+    #   not (defaults to `false`).
+    #
+    def self.include_resource_dsl(include_resource_dsl)
+      @include_resource_dsl = include_resource_dsl
+    end
+
+    # Create the resource DSL module that forwards resource methods to new_resource
+    #
+    # @api private
+    def self.include_resource_dsl_module(resource)
+      if @include_resource_dsl && !defined?(@included_resource_dsl_module)
+        provider_class = self
+        @included_resource_dsl_module = Module.new do
+          extend Forwardable
+          define_singleton_method(:to_s) { "forwarder module for #{provider_class}" }
+          define_singleton_method(:inspect) { to_s }
+          # Add a delegator for each explicit property that will get the *current* value
+          # of the property by default instead of the *actual* value.
+          resource.class.properties.each do |name, property|
+            class_eval(<<-EOM, __FILE__, __LINE__)
+              def #{name}(*args, &block)
+                # If no arguments were passed, we process "get" by defaulting
+                # the value to current_resource, not new_resource. This helps
+                # avoid issues where resources accidentally overwrite perfectly
+                # valid stuff with default values.
+                if args.empty? && !block
+                  if !new_resource.property_is_set?(__method__) && current_resource
+                    return current_resource.public_send(__method__)
+                  end
+                end
+                new_resource.public_send(__method__, *args, &block)
+              end
+            EOM
+          end
+          dsl_methods =
+            resource.class.public_instance_methods +
+            resource.class.protected_instance_methods -
+            provider_class.instance_methods -
+            resource.class.properties.keys
+          def_delegators(:new_resource, *dsl_methods)
+        end
+        include @included_resource_dsl_module
+      end
+    end
+
+    # Enables inline evaluation of resources in provider actions.
+    #
+    # Without this option, any resources declared inside the Provider are added
+    # to the resource collection after the current position at the time the
+    # action is executed. Because they are added to the primary resource
+    # collection for the chef run, they can notify other resources outside
+    # the Provider, and potentially be notified by resources outside the Provider
+    # (but this is complicated by the fact that they don't exist until the
+    # provider executes). In this mode, it is impossible to correctly set the
+    # updated_by_last_action flag on the parent Provider resource, since it
+    # executes and returns before its component resources are run.
+    #
+    # With this option enabled, each action creates a temporary run_context
+    # with its own resource collection, evaluates the action's code in that
+    # context, and then converges the resources created. If any resources
+    # were updated, then this provider's new_resource will be marked updated.
+    #
+    # In this mode, resources created within the Provider cannot interact with
+    # external resources via notifies, though notifications to other
+    # resources within the Provider will work. Delayed notifications are executed
+    # at the conclusion of the provider's action, *not* at the end of the
+    # main chef run.
+    #
+    # This mode of evaluation is experimental, but is believed to be a better
+    # set of tradeoffs than the append-after mode, so it will likely become
+    # the default in a future major release of Chef.
+    #
+    def self.use_inline_resources
+      extend InlineResources::ClassMethods
+      include InlineResources
+    end
+
+    # Chef::Provider::InlineResources
+    # Implementation of inline resource convergence for providers. See
+    # Provider.use_inline_resources for a longer explanation.
+    #
+    # This code is restricted to a module so that it can be selectively
+    # applied to providers on an opt-in basis.
+    #
+    # @api private
+    module InlineResources
+
+      # Create a child run_context, compile the block, and converge it.
+      #
+      # @api private
+      def compile_and_converge_action(&block)
+        old_run_context = run_context
+        @run_context = run_context.create_child
+        return_value = instance_eval(&block)
+        Chef::Runner.new(run_context).converge
+        return_value
+      ensure
+        if run_context.resource_collection.any? { |r| r.updated? }
+          new_resource.updated_by_last_action(true)
+        end
+        @run_context = old_run_context
+      end
+
+      # Class methods for InlineResources. Overrides the `action` DSL method
+      # with one that enables inline resource convergence.
+      #
+      # @api private
+      module ClassMethods
+        # Defines an action method on the provider, running the block to
+        # compile the resources, converging them, and then checking if any
+        # were updated (and updating new-resource if so)
+        def action(name, &block)
+          # We need the block directly in a method so that `super` works
+          define_method("compile_action_#{name}", &block)
+          # We try hard to use `def` because define_method doesn't show the method name in the stack.
+          begin
+            class_eval <<-EOM
+              def action_#{name}
+                compile_and_converge_action { compile_action_#{name} }
+              end
+            EOM
+          rescue SyntaxError
+            define_method("action_#{name}") { send("compile_action_#{name}") }
+          end
+        end
+      end
+
+      require "chef/dsl/recipe"
+      include Chef::DSL::Recipe::FullDSL
+    end
+
     protected
 
     def converge_actions
@@ -182,14 +412,50 @@ class Chef
       # manipulating notifies.
 
       converge_by ("evaluate block and run any associated actions") do
-        saved_run_context = @run_context
-        @run_context = @run_context.dup
-        @run_context.resource_collection = Chef::ResourceCollection.new
-        instance_eval(&block)
-        Chef::Runner.new(@run_context).converge
-        @run_context = saved_run_context
+        saved_run_context = run_context
+        begin
+          @run_context = run_context.create_child
+          instance_eval(&block)
+          Chef::Runner.new(run_context).converge
+        ensure
+          @run_context = saved_run_context
+        end
       end
     end
 
+    module DeprecatedLWRPClass
+      def const_missing(class_name)
+        if deprecated_constants[class_name.to_sym]
+          Chef.log_deprecation("Using an LWRP provider by its name (#{class_name}) directly is no longer supported in Chef 12 and will be removed.  Use Chef::ProviderResolver.new(node, resource, action) instead.")
+          deprecated_constants[class_name.to_sym]
+        else
+          raise NameError, "uninitialized constant Chef::Provider::#{class_name}"
+        end
+      end
+
+      # @api private
+      def register_deprecated_lwrp_class(provider_class, class_name)
+        # Register Chef::Provider::MyProvider with deprecation warnings if you
+        # try to access it
+        if Chef::Provider.const_defined?(class_name, false)
+          Chef::Log.warn "Chef::Provider::#{class_name} already exists!  Cannot create deprecation class for #{provider_class}"
+        else
+          deprecated_constants[class_name.to_sym] = provider_class
+        end
+      end
+
+      private
+
+      def deprecated_constants
+        @deprecated_constants ||= {}
+      end
+    end
+    extend DeprecatedLWRPClass
   end
 end
+
+# Requiring things at the bottom breaks cycles
+require "chef/chef_class"
+require "chef/mixin/why_run"
+require "chef/resource_collection"
+require "chef/runner"
diff --git a/lib/chef/provider/apt_update.rb b/lib/chef/provider/apt_update.rb
new file mode 100644
index 0000000..449b298
--- /dev/null
+++ b/lib/chef/provider/apt_update.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Thom May (<thom at chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+require "chef/dsl/declare_resource"
+
+class Chef
+  class Provider
+    class AptUpdate < Chef::Provider
+      include Chef::DSL::DeclareResource
+
+      provides :apt_update, os: "linux"
+
+      APT_CONF_DIR = "/etc/apt/apt.conf.d"
+      STAMP_DIR = "/var/lib/apt/periodic"
+
+      def whyrun_supported?
+        true
+      end
+
+      def load_current_resource
+      end
+
+      def action_periodic
+        if !apt_up_to_date?
+          converge_by "update new lists of packages" do
+            do_update
+          end
+        end
+      end
+
+      def action_update
+        converge_by "force update new lists of packages" do
+          do_update
+        end
+      end
+
+      private
+
+      # Determines whether we need to run `apt-get update`
+      #
+      # @return [Boolean]
+      def apt_up_to_date?
+        ::File.exist?("#{STAMP_DIR}/update-success-stamp") &&
+          ::File.mtime("#{STAMP_DIR}/update-success-stamp") > Time.now - new_resource.frequency
+      end
+
+      def do_update
+        [STAMP_DIR, APT_CONF_DIR].each do |d|
+          build_resource(:directory, d, caller[0]) do
+            recursive true
+          end.run_action(:create)
+        end
+
+        build_resource(:file, "#{APT_CONF_DIR}/15update-stamp", caller[0]) do
+          content "APT::Update::Post-Invoke-Success {\"touch #{STAMP_DIR}/update-success-stamp 2>/dev/null || true\";};"
+        end.run_action(:create_if_missing)
+
+        shell_out!("apt-get -q update")
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/provider/batch.rb b/lib/chef/provider/batch.rb
index b6b386e..bb294af 100644
--- a/lib/chef/provider/batch.rb
+++ b/lib/chef/provider/batch.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/windows_script'
+require "chef/provider/windows_script"
 
 class Chef
   class Provider
@@ -24,12 +24,20 @@ class Chef
 
       provides :batch, os: "windows"
 
-      def initialize (new_resource, run_context)
-        super(new_resource, run_context, '.bat')
+      def initialize(new_resource, run_context)
+        super(new_resource, run_context, ".bat")
+      end
+
+      def command
+        basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+
+        interpreter_path = Chef::Util::PathHelper.join(basepath, interpreter)
+
+        "\"#{interpreter_path}\" #{flags} \"#{script_file.path}\""
       end
 
       def flags
-        @new_resource.flags.nil? ? '/c' : new_resource.flags + ' /c'
+        @new_resource.flags.nil? ? "/c" : new_resource.flags + " /c"
       end
 
     end
diff --git a/lib/chef/provider/breakpoint.rb b/lib/chef/provider/breakpoint.rb
index 663d558..a71c9e3 100644
--- a/lib/chef/provider/breakpoint.rb
+++ b/lib/chef/provider/breakpoint.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/cookbook_file.rb b/lib/chef/provider/cookbook_file.rb
index b501a9b..3ca0bbd 100644
--- a/lib/chef/provider/cookbook_file.rb
+++ b/lib/chef/provider/cookbook_file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/file'
-require 'chef/deprecation/provider/cookbook_file'
-require 'chef/deprecation/warnings'
+require "chef/provider/file"
+require "chef/deprecation/provider/cookbook_file"
+require "chef/deprecation/warnings"
 
 class Chef
   class Provider
diff --git a/lib/chef/provider/cookbook_file/content.rb b/lib/chef/provider/cookbook_file/content.rb
index 9f49ba8..1d24dee 100644
--- a/lib/chef/provider/cookbook_file/content.rb
+++ b/lib/chef/provider/cookbook_file/content.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/file_content_management/content_base'
-require 'chef/file_content_management/tempfile'
+require "chef/file_content_management/content_base"
+require "chef/file_content_management/tempfile"
 
 class Chef
   class Provider
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index 6d86e33..36b67ab 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
 
 class Chef
   class Provider
@@ -67,7 +67,7 @@ class Chef
               if cron_found
                 @current_resource.time($2.to_sym)
                 @current_resource.command($3)
-                cron_found=false
+                cron_found = false
               end
             when CRON_PATTERN
               if cron_found
@@ -77,11 +77,11 @@ class Chef
                 @current_resource.month($4)
                 @current_resource.weekday($5)
                 @current_resource.command($6)
-                cron_found=false
+                cron_found = false
               end
               next
             else
-              cron_found=false # We've got a Chef comment with no following crontab line
+              cron_found = false # We've got a Chef comment with no following crontab line
               next
             end
           end
@@ -199,7 +199,7 @@ class Chef
       private
 
       def set_environment_var(attr_name, attr_value)
-        if %w(MAILTO PATH SHELL HOME).include?(attr_name)
+        if %w{MAILTO PATH SHELL HOME}.include?(attr_name)
           @current_resource.send(attr_name.downcase.to_sym, attr_value)
         else
           @current_resource.environment(@current_resource.environment.merge(attr_name => attr_value))
diff --git a/lib/chef/provider/cron/aix.rb b/lib/chef/provider/cron/aix.rb
index 9cacbc6..015c1f2 100644
--- a/lib/chef/provider/cron/aix.rb
+++ b/lib/chef/provider/cron/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/cron/solaris.rb b/lib/chef/provider/cron/solaris.rb
index 20fa7ab..58d6637 100644
--- a/lib/chef/provider/cron/solaris.rb
+++ b/lib/chef/provider/cron/solaris.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/cron/unix.rb b/lib/chef/provider/cron/unix.rb
index 0750c04..108e73c 100644
--- a/lib/chef/provider/cron/unix.rb
+++ b/lib/chef/provider/cron/unix.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
 # Author:: Toomas Pelberg (toomasp at gmx.net)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2010-2016, Toomas Pelberg
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,9 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/provider'
+require "chef/log"
+require "chef/provider"
+require "chef/provider/cron"
 
 class Chef
   class Provider
@@ -27,12 +28,12 @@ class Chef
       class Unix < Chef::Provider::Cron
         include Chef::Mixin::ShellOut
 
-        provides :cron, os: 'solaris2'
+        provides :cron, os: "solaris2"
 
         private
 
         def read_crontab
-          crontab = shell_out('/usr/bin/crontab -l', :user => @new_resource.user)
+          crontab = shell_out("/usr/bin/crontab -l", :user => @new_resource.user)
           status = crontab.status.exitstatus
 
           Chef::Log.debug crontab.format_for_exception if status > 0
diff --git a/lib/chef/provider/deploy.rb b/lib/chef/provider/deploy.rb
index 19e7c01..7274ab2 100644
--- a/lib/chef/provider/deploy.rb
+++ b/lib/chef/provider/deploy.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -56,7 +56,7 @@ class Chef
         @shared_path = @new_resource.shared_path
       end
 
-      def sudo(command,&block)
+      def sudo(command, &block)
         execute(command, &block)
       end
 
@@ -93,7 +93,6 @@ class Chef
             a.whyrun("Would assume callback file #{callback_file} included in release")
           end
         end
-
       end
 
       def action_deploy
@@ -175,7 +174,7 @@ class Chef
         restart
       end
 
-      def callback(what, callback_code=nil)
+      def callback(what, callback_code = nil)
         @collection = Chef::ResourceCollection.new
         case callback_code
         when Proc
@@ -201,7 +200,7 @@ class Chef
 
           converge_by("execute migration command #{@new_resource.migration_command}") do
             Chef::Log.info "#{@new_resource} migrating #{@new_resource.user} with environment #{env_info}"
-            run_command(run_options(:command => @new_resource.migration_command, :cwd=>release_path, :log_level => :info))
+            shell_out!(@new_resource.migration_command, run_options(:cwd => release_path, :log_level => :info))
           end
         end
       end
@@ -221,7 +220,7 @@ class Chef
           else
             converge_by("restart app using command #{@new_resource.restart_command}") do
               Chef::Log.info("#{@new_resource} restarting app")
-              run_command(run_options(:command => @new_resource.restart_command, :cwd => @new_resource.current_path))
+              shell_out!(@new_resource.restart_command, run_options(:cwd => @new_resource.current_path))
             end
           end
         end
@@ -276,7 +275,7 @@ class Chef
 
       def enforce_ownership
         converge_by("force ownership of #{@new_resource.deploy_to} to #{@new_resource.group}:#{@new_resource.user}") do
-          FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to)
+          FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to, :force => true)
           Chef::Log.info("#{@new_resource} set user to #{@new_resource.user}") if @new_resource.user
           Chef::Log.info("#{@new_resource} set group to #{@new_resource.group}") if @new_resource.group
         end
@@ -365,7 +364,7 @@ class Chef
       end
 
       def release_slug
-        raise Chef::Exceptions::Override, "You must override release_slug in #{self.to_s}"
+        raise Chef::Exceptions::Override, "You must override release_slug in #{self}"
       end
 
       def install_gems
@@ -373,11 +372,9 @@ class Chef
       end
 
       def gem_resource_collection_runner
-        gems_collection = Chef::ResourceCollection.new
-        gem_packages.each { |rbgem| gems_collection.insert(rbgem) }
-        gems_run_context = run_context.dup
-        gems_run_context.resource_collection = gems_collection
-        Chef::Runner.new(gems_run_context)
+        child_context = run_context.create_child
+        gem_packages.each { |rbgem| child_context.resource_collection.insert(rbgem) }
+        Chef::Runner.new(child_context)
       end
 
       def gem_packages
@@ -393,7 +390,7 @@ class Chef
         end
       end
 
-      def run_options(run_opts={})
+      def run_options(run_opts = {})
         run_opts[:user] = @new_resource.user if @new_resource.user
         run_opts[:group] = @new_resource.group if @new_resource.group
         run_opts[:environment] = @new_resource.environment if @new_resource.environment
diff --git a/lib/chef/provider/deploy/revision.rb b/lib/chef/provider/deploy/revision.rb
index 62aa0e8..9e2bb94 100644
--- a/lib/chef/provider/deploy/revision.rb
+++ b/lib/chef/provider/deploy/revision.rb
@@ -1,9 +1,9 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider'
-require 'chef/provider/deploy'
-require 'chef/json_compat'
+require "chef/provider"
+require "chef/provider/deploy"
+require "chef/json_compat"
 
 class Chef
   class Provider
@@ -56,11 +56,11 @@ class Chef
         protected
 
         def release_created(release)
-          sorted_releases {|r| r.delete(release); r << release }
+          sorted_releases { |r| r.delete(release); r << release }
         end
 
         def release_deleted(release)
-          sorted_releases { |r| r.delete(release)}
+          sorted_releases { |r| r.delete(release) }
         end
 
         def release_slug
diff --git a/lib/chef/provider/deploy/timestamped.rb b/lib/chef/provider/deploy/timestamped.rb
index ba3f668..5486b09 100644
--- a/lib/chef/provider/deploy/timestamped.rb
+++ b/lib/chef/provider/deploy/timestamped.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb
index 416393a..3235a28 100644
--- a/lib/chef/provider/directory.rb
+++ b/lib/chef/provider/directory.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/directory'
-require 'chef/provider'
-require 'chef/provider/file'
-require 'fileutils'
+require "chef/config"
+require "chef/log"
+require "chef/resource/directory"
+require "chef/provider"
+require "chef/provider/file"
+require "fileutils"
 
 class Chef
   class Provider
@@ -43,6 +43,9 @@ class Chef
       end
 
       def define_resource_requirements
+        # deep inside FAC we have to assert requirements, so call FACs hook to set that up
+        access_controls.define_resource_requirements
+
         requirements.assert(:create) do |a|
           # Make sure the parent dir exists, or else fail.
           # for why run, print a message explaining the potential error.
@@ -61,7 +64,13 @@ class Chef
               is_parent_writable = lambda do |base_dir|
                 base_dir = ::File.dirname(base_dir)
                 if ::File.exists?(base_dir)
-                  Chef::FileAccessControl.writable?(base_dir)
+                  if Chef::FileAccessControl.writable?(base_dir)
+                    true
+                  elsif Chef::Util::PathHelper.is_sip_path?(base_dir, node)
+                    Chef::Util::PathHelper.writable_sip_path?(base_dir)
+                  else
+                    false
+                  end
                 else
                   is_parent_writable.call(base_dir)
                 end
@@ -71,7 +80,13 @@ class Chef
               # in why run mode & parent directory does not exist no permissions check is required
               # If not in why run, permissions must be valid and we rely on prior assertion that dir exists
               if !whyrun_mode? || ::File.exists?(parent_directory)
-                Chef::FileAccessControl.writable?(parent_directory)
+                if Chef::FileAccessControl.writable?(parent_directory)
+                  true
+                elsif Chef::Util::PathHelper.is_sip_path?(parent_directory, node)
+                  Chef::Util::PathHelper.writable_sip_path?(@new_resource.path)
+                else
+                  false
+                end
               else
                 true
               end
diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb
index 2812c15..eac8a82 100644
--- a/lib/chef/provider/dsc_resource.rb
+++ b/lib/chef/provider/dsc_resource.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,29 +15,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/local_configuration_manager'
-require 'chef/mixin/powershell_type_coercions'
-require 'chef/util/dsc/resource_store'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/local_configuration_manager"
+require "chef/mixin/powershell_type_coercions"
+require "chef/util/dsc/resource_store"
 
 class Chef
   class Provider
     class DscResource < Chef::Provider
       include Chef::Mixin::PowershellTypeCoercions
-
       provides :dsc_resource, os: "windows"
-
       def initialize(new_resource, run_context)
         super
         @new_resource = new_resource
         @module_name = new_resource.module_name
+        @reboot_resource = nil
       end
 
       def action_run
         if ! test_resource
           converge_by(generate_description) do
             result = set_resource
+            reboot_if_required
           end
         end
       end
@@ -53,17 +52,16 @@ class Chef
         requirements.assert(:run) do |a|
           a.assertion { supports_dsc_invoke_resource? }
           err = ["You must have Powershell version >= 5.0.10018.0 to use dsc_resource."]
-          a.failure_message Chef::Exceptions::NoProviderAvailable,
+          a.failure_message Chef::Exceptions::ProviderNotFound,
             err
           a.whyrun err + ["Assuming a previous resource installs Powershell 5.0.10018.0 or higher."]
           a.block_action!
         end
         requirements.assert(:run) do |a|
-          a.assertion {
-            meta_configuration['RefreshMode'] == 'Disabled'
-          }
-          err = ["The LCM must have its RefreshMode set to Disabled. "]
-          a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ')
+          a.assertion { supports_refresh_mode_enabled? || dsc_refresh_mode_disabled? }
+          err = ["The LCM must have its RefreshMode set to Disabled for" \
+                 " PowerShell versions before 5.0.10586.0."]
+          a.failure_message Chef::Exceptions::ProviderNotFound, err.join(" ")
           a.whyrun err + ["Assuming a previous resource sets the RefreshMode."]
           a.block_action!
         end
@@ -74,7 +72,7 @@ class Chef
       def local_configuration_manager
         @local_configuration_manager ||= Chef::Util::DSC::LocalConfigurationManager.new(
           node,
-          nil
+          nil,
         )
       end
 
@@ -86,6 +84,14 @@ class Chef
         run_context && Chef::Platform.supports_dsc_invoke_resource?(node)
       end
 
+      def dsc_refresh_mode_disabled?
+        Chef::Platform.dsc_refresh_mode_disabled?(node)
+      end
+
+      def supports_refresh_mode_enabled?
+        Chef::Platform.supports_refresh_mode_enabled?(node)
+      end
+
       def generate_description
         @converge_description
       end
@@ -97,17 +103,16 @@ class Chef
       def module_name
         @module_name ||= begin
           found = resource_store.find(dsc_resource_name)
-
           r = case found.length
               when 0
                 raise Chef::Exceptions::ResourceNotFound,
                   "Could not find #{dsc_resource_name}. Check to make "\
                   "sure that it shows up when running Get-DscResource"
               when 1
-                if found[0]['Module'].nil?
+                if found[0]["Module"].nil?
                   :none
                 else
-                  found[0]['Module']['Name']
+                  found[0]["Module"]["Name"]
                 end
               else
                 raise Chef::Exceptions::MultipleDscResourcesFound, found
@@ -117,41 +122,79 @@ class Chef
 
       def test_resource
         result = invoke_resource(:test)
-        # We really want this information from the verbose stream,
-        # however Invoke-DscResource is not correctly writing to that
-        # stream and instead just dumping to stdout
-        @converge_description = result.stdout
-        result.return_value[0]["InDesiredState"]
+        add_dsc_verbose_log(result)
+        return_dsc_resource_result(result, "InDesiredState")
       end
 
       def set_resource
         result = invoke_resource(:set)
+        add_dsc_verbose_log(result)
+        create_reboot_resource if return_dsc_resource_result(result, "RebootRequired")
         result.return_value
       end
 
-      def invoke_resource(method, output_format=:object)
+      def add_dsc_verbose_log(result)
+        # We really want this information from the verbose stream,
+        # however in some versions of WMF, Invoke-DscResource is not correctly
+        # writing to that stream and instead just dumping to stdout
+        verbose_output = result.stream(:verbose)
+        verbose_output = result.stdout if verbose_output.empty?
+
+        if @converge_description.nil? || @converge_description.empty?
+          @converge_description = verbose_output
+        else
+          @converge_description << "\n"
+          @converge_description << verbose_output
+        end
+      end
+
+      def invoke_resource(method, output_format = :object)
         properties = translate_type(@new_resource.properties)
-        switches = "-Method #{method.to_s} -Name #{@new_resource.resource}"\
+        switches = "-Method #{method} -Name #{@new_resource.resource}"\
                    " -Property #{properties} -Verbose"
-
         if module_name != :none
           switches += " -Module #{module_name}"
         end
-
         cmdlet = Chef::Util::Powershell::Cmdlet.new(
           node,
           "Invoke-DscResource #{switches}",
-          output_format
+          output_format,
         )
-        cmdlet.run!
+        cmdlet.run!({}, { :timeout => new_resource.timeout })
       end
 
-      def meta_configuration
-        cmdlet = Chef::Util::Powershell::Cmdlet.new(node, "Get-DscLocalConfigurationManager", :object)
-        result = cmdlet.run!
-        result.return_value
+      def return_dsc_resource_result(result, property_name)
+        if result.return_value.is_a?(Array)
+          # WMF Feb 2015 Preview
+          result.return_value[0][property_name]
+        else
+          # WMF April 2015 Preview
+          result.return_value[property_name]
+        end
       end
 
+      def create_reboot_resource
+        @reboot_resource = Chef::Resource::Reboot.new(
+          "Reboot for #{@new_resource.name}",
+          run_context,
+        ).tap do |r|
+          r.reason("Reboot for #{@new_resource.resource}.")
+        end
+      end
+
+      def reboot_if_required
+        reboot_action = @new_resource.reboot_action
+        unless @reboot_resource.nil?
+          case reboot_action
+          when :nothing
+            Chef::Log.debug("A reboot was requested by the DSC resource, but reboot_action is :nothing.")
+            Chef::Log.debug("This dsc_resource will not reboot the node.")
+          else
+            Chef::Log.debug("Requesting node reboot with #{reboot_action}.")
+            @reboot_resource.run_action(reboot_action)
+          end
+        end
+      end
     end
   end
 end
diff --git a/lib/chef/provider/dsc_script.rb b/lib/chef/provider/dsc_script.rb
index a75e68a..79769d9 100644
--- a/lib/chef/provider/dsc_script.rb
+++ b/lib/chef/provider/dsc_script.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/configuration_generator'
-require 'chef/util/dsc/local_configuration_manager'
-require 'chef/util/path_helper'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/configuration_generator"
+require "chef/util/dsc/local_configuration_manager"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
@@ -37,7 +37,7 @@ class Chef
           },
           :test => Proc.new { |config_manager, document, shellout_flags|
             config_manager.test_configuration(document, shellout_flags)
-          }}
+          } }
       end
 
       def action_run
@@ -65,12 +65,12 @@ class Chef
       def define_resource_requirements
         requirements.assert(:run) do |a|
           err = [
-            'Could not find PowerShell DSC support on the system',
+            "Could not find PowerShell DSC support on the system",
             powershell_info_str,
             "Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.",
           ]
           a.assertion { supports_dsc? }
-          a.failure_message Chef::Exceptions::NoProviderAvailable, err.join(' ')
+          a.failure_message Chef::Exceptions::ProviderNotFound, err.join(" ")
           a.whyrun err + ["Assuming a previous resource installs Powershell 4.0 or higher."]
           a.block_action!
         end
@@ -92,14 +92,14 @@ class Chef
         shellout_flags = {
           :cwd => @dsc_resource.cwd,
           :environment => @dsc_resource.environment,
-          :timeout => @dsc_resource.timeout
+          :timeout => @dsc_resource.timeout,
         }
 
         begin
           configuration_document = generate_configuration_document(config_directory, configuration_flags)
           @operations[operation].call(config_manager, configuration_document, shellout_flags)
         rescue Exception => e
-          Chef::Log.error("DSC operation failed: #{e.message.to_s}")
+          Chef::Log.error("DSC operation failed: #{e.message}")
           raise e
         ensure
           ::FileUtils.rm_rf(config_directory)
@@ -119,7 +119,7 @@ class Chef
         shellout_flags = {
           :cwd => @dsc_resource.cwd,
           :environment => @dsc_resource.environment,
-          :timeout => @dsc_resource.timeout
+          :timeout => @dsc_resource.timeout,
         }
 
         generator = Chef::Util::DSC::ConfigurationGenerator.new(@run_context.node, config_directory)
@@ -129,7 +129,7 @@ class Chef
         else
           # If code is also not provided, we mimic what the other script resources do (execute nothing)
           Chef::Log.warn("Neither code or command were provided for dsc_resource[#{@dsc_resource.name}].") unless @dsc_resource.code
-          generator.configuration_document_from_script_code(@dsc_resource.code || '', configuration_flags, @dsc_resource.imports, shellout_flags)
+          generator.configuration_document_from_script_code(@dsc_resource.code || "", configuration_flags, @dsc_resource.imports, shellout_flags)
         end
       end
 
@@ -138,7 +138,7 @@ class Chef
           @dsc_resource.configuration_data_script
         elsif @dsc_resource.configuration_data
           configuration_data_path = "#{config_directory}/chef_dsc_config_data.psd1"
-          ::File.open(configuration_data_path, 'wt') do | script |
+          ::File.open(configuration_data_path, "wt") do |script|
             script.write(@dsc_resource.configuration_data)
           end
           configuration_data_path
@@ -164,8 +164,8 @@ class Chef
           @dsc_resources_info.map do |resource|
             if resource.changes_state?
               # We ignore the last log message because it only contains the time it took, which looks weird
-              cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, '').strip }
-              "converge DSC resource #{resource.name} by #{cleaned_messages.find_all{ |c| c != ''}.join("\n")}"
+              cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, "").strip }
+              "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}"
             else
               # This is needed because a dsc script can have resources that are both converged and not
               "converge DSC resource #{resource.name} by doing nothing because it is already converged"
@@ -177,7 +177,7 @@ class Chef
         if run_context && run_context.node[:languages] && run_context.node[:languages][:powershell]
           install_info = "Powershell #{run_context.node[:languages][:powershell][:version]} was found on the system."
         else
-          install_info = 'Powershell was not found.'
+          install_info = "Powershell was not found."
         end
       end
     end
diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/env.rb
index cf75ff7..5b252dd 100644
--- a/lib/chef/provider/env.rb
+++ b/lib/chef/provider/env.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'chef/resource/env'
+require "chef/provider"
+require "chef/mixin/command"
+require "chef/resource/env"
 
 class Chef
   class Provider
@@ -48,7 +48,7 @@ class Chef
       end
 
       def env_value(key_name)
-        raise Chef::Exceptions::Env, "#{self.to_s} provider does not implement env_value!"
+        raise Chef::Exceptions::Env, "#{self} provider does not implement env_value!"
       end
 
       def env_key_exists(key_name)
@@ -141,11 +141,11 @@ class Chef
       end
 
       def create_env
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :#{@new_resource.action}"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :#{@new_resource.action}"
       end
 
       def delete_env
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :delete"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :delete"
       end
 
       def modify_env
@@ -164,6 +164,6 @@ class Chef
       def new_values
         @new_values ||= @new_resource.value.split(@new_resource.delim)
       end
-     end
+    end
   end
 end
diff --git a/lib/chef/provider/env/windows.rb b/lib/chef/provider/env/windows.rb
index 56cebdb..684386a 100644
--- a/lib/chef/provider/env/windows.rb
+++ b/lib/chef/provider/env/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/windows_env_helper'
+require "chef/mixin/windows_env_helper"
 
 class Chef
   class Provider
@@ -36,7 +36,7 @@ class Chef
           obj.variablevalue = @new_resource.value
           obj.put_
           value = @new_resource.value
-          value = expand_path(value) if @new_resource.key_name.upcase == 'PATH'
+          value = expand_path(value) if @new_resource.key_name.upcase == "PATH"
           ENV[@new_resource.key_name] = value
           broadcast_env_change
         end
diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb
index f5855bc..7167f3b 100644
--- a/lib/chef/provider/erl_call.rb
+++ b/lib/chef/provider/erl_call.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
 
 class Chef
   class Provider
@@ -89,7 +89,7 @@ class Chef
             end
 
             # fail if the first 4 characters aren't "{ok,"
-            unless stdout_output[0..3].include?('{ok,')
+            unless stdout_output[0..3].include?("{ok,")
               raise Chef::Exceptions::ErlCall, stdout_output
             end
 
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index b44112c..45f0ad5 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/provider'
-require 'forwardable'
+require "chef/log"
+require "chef/provider"
+require "forwardable"
 
 class Chef
   class Provider
@@ -40,9 +40,9 @@ class Chef
 
       def define_resource_requirements
          # @todo: this should change to raise in some appropriate major version bump.
-         if creates && creates_relative? && !cwd
-           Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail (CHEF-3819)"
-         end
+        if creates && creates_relative? && !cwd
+          Chef::Log.warn "Providing a relative path for the creates attribute without the cwd is deprecated and will be changed to fail in the future (CHEF-3819)"
+        end
       end
 
       def timeout
@@ -58,7 +58,16 @@ class Chef
         end
 
         converge_by("execute #{description}") do
-          result = shell_out!(command, opts)
+          begin
+            shell_out!(command, opts)
+          rescue Mixlib::ShellOut::ShellCommandFailed
+            if sensitive?
+              raise Mixlib::ShellOut::ShellCommandFailed,
+                "Command execution failed. STDOUT/STDERR suppressed for sensitive resource"
+            else
+              raise
+            end
+          end
           Chef::Log.info("#{new_resource} ran successfully")
         end
       end
@@ -69,6 +78,14 @@ class Chef
         !!new_resource.sensitive
       end
 
+      def live_stream?
+        Chef::Config[:stream_execute_output] || !!new_resource.live_stream
+      end
+
+      def stream_to_stdout?
+        STDOUT.tty? && !Chef::Config[:daemon]
+      end
+
       def opts
         opts = {}
         opts[:timeout]     = timeout
@@ -80,8 +97,12 @@ class Chef
         opts[:umask]       = umask if umask
         opts[:log_level]   = :info
         opts[:log_tag]     = new_resource.to_s
-        if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? && !sensitive?
-          opts[:live_stream] = STDOUT
+        if (Chef::Log.info? || live_stream?) && !sensitive?
+          if run_context.events.formatter?
+            opts[:live_stream] = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
+          elsif stream_to_stdout?
+            opts[:live_stream] = STDOUT
+          end
         end
         opts
       end
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index c070d29..7f85085 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,22 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/file'
-require 'chef/provider'
-require 'etc'
-require 'fileutils'
-require 'chef/scan_access_control'
-require 'chef/mixin/checksum'
-require 'chef/mixin/file_class'
-require 'chef/util/backup'
-require 'chef/util/diff'
-require 'chef/deprecation/provider/file'
-require 'chef/deprecation/warnings'
-require 'chef/file_content_management/deploy'
+require "chef/config"
+require "chef/log"
+require "chef/resource/file"
+require "chef/provider"
+require "etc"
+require "fileutils"
+require "chef/scan_access_control"
+require "chef/mixin/checksum"
+require "chef/mixin/file_class"
+require "chef/mixin/enforce_ownership_and_permissions"
+require "chef/util/backup"
+require "chef/util/diff"
+require "chef/util/selinux"
+require "chef/deprecation/provider/file"
+require "chef/deprecation/warnings"
+require "chef/file_content_management/deploy"
 
 # The Tao of File Providers:
 #  - the content provider must always return a tempfile that we can delete/mv
@@ -128,7 +130,7 @@ class Chef
         if ::File.exist?(@new_resource.path)
           requirements.assert(:delete) do |a|
             a.assertion { ::File.writable?(@new_resource.path) }
-            a.failure_message(Chef::Exceptions::InsufficientPermissions,"File #{@new_resource.path} exists but is not writable so it cannot be deleted")
+            a.failure_message(Chef::Exceptions::InsufficientPermissions, "File #{@new_resource.path} exists but is not writable so it cannot be deleted")
           end
         end
 
@@ -244,7 +246,7 @@ class Chef
         else
           [ Chef::Exceptions::FileTypeMismatch,
             "File #{path} exists, but is a #{file_type_string(@new_resource.path)}, set force_unlink to true to remove",
-            "Assuming #{file_type_string(@new_resource.path)} at #{@new_resource.path} would have been removed by a previous resource"
+            "Assuming #{file_type_string(@new_resource.path)} at #{@new_resource.path} would have been removed by a previous resource",
           ]
         end
       end
@@ -264,8 +266,8 @@ class Chef
         else
           [ Chef::Exceptions::FileTypeMismatch,
             "File #{path} exists, but is a symlink to #{real_path} which is a #{file_type_string(real_path)}. " +
-            "Disable manage_symlink_source and set force_unlink to remove it.",
-            "Assuming symlink #{path} or source file #{real_path} would have been fixed by a previous resource"
+              "Disable manage_symlink_source and set force_unlink to remove it.",
+            "Assuming symlink #{path} or source file #{real_path} would have been fixed by a previous resource",
           ]
         end
       rescue Errno::ELOOP
@@ -386,10 +388,11 @@ class Chef
 
       def update_file_contents
         do_backup unless needs_creating?
-        deployment_strategy.deploy(tempfile.path, ::File.realpath(@new_resource.path))
-        Chef::Log.info("#{@new_resource} updated file contents #{@new_resource.path}")
+        deployment_strategy.deploy(tempfile.path, ::File.realpath(new_resource.path))
+        Chef::Log.info("#{new_resource} updated file contents #{new_resource.path}")
         if managing_content?
-          @new_resource.checksum(checksum(@new_resource.path)) # for reporting
+          # save final checksum for reporting.
+          new_resource.final_checksum = checksum(new_resource.path)
         end
       end
 
@@ -461,7 +464,7 @@ class Chef
 
       def short_cksum(checksum)
         return "none" if checksum.nil?
-        checksum.slice(0,6)
+        checksum.slice(0, 6)
       end
 
       def load_resource_attributes_from_file(resource)
diff --git a/lib/chef/provider/file/content.rb b/lib/chef/provider/file/content.rb
index f82bc49..1b60e10 100644
--- a/lib/chef/provider/file/content.rb
+++ b/lib/chef/provider/file/content.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/file_content_management/content_base'
-require 'chef/file_content_management/tempfile'
+require "chef/file_content_management/content_base"
+require "chef/file_content_management/tempfile"
 
 class Chef
   class Provider
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 8418f22..f8a8dab 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/log'
-require 'chef/provider'
-require 'fileutils'
+require "chef/exceptions"
+require "chef/log"
+require "chef/provider"
+require "fileutils"
 
 class Chef
   class Provider
@@ -53,9 +53,9 @@ class Chef
           a.assertion { !(@new_resource.revision =~ /^origin\//) }
           a.failure_message Chef::Exceptions::InvalidRemoteGitReference,
              "Deploying remote branches is not supported. " +
-             "Specify the remote branch as a local branch for " +
-             "the git repository you're deploying from " +
-             "(ie: '#{@new_resource.revision.gsub('origin/', '')}' rather than '#{@new_resource.revision}')."
+               "Specify the remote branch as a local branch for " +
+               "the git repository you're deploying from " +
+               "(ie: '#{@new_resource.revision.gsub('origin/', '')}' rather than '#{@new_resource.revision}')."
         end
 
         requirements.assert(:all_actions) do |a|
@@ -65,8 +65,8 @@ class Chef
           a.assertion { target_revision != nil }
           a.failure_message Chef::Exceptions::UnresolvableGitReference,
             "Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " +
-            "Verify your (case-sensitive) repository URL and revision.\n" +
-            "`git ls-remote '#{@new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
+              "Verify your (case-sensitive) repository URL and revision.\n" +
+              "`git ls-remote '#{@new_resource.repository}' '#{rev_search_pattern}'` output: #{@resolved_reference}"
         end
       end
 
@@ -86,7 +86,7 @@ class Chef
       def action_export
         action_checkout
         converge_by("complete the export by removing #{@new_resource.destination}.git after checkout") do
-          FileUtils.rm_rf(::File.join(@new_resource.destination,".git"))
+          FileUtils.rm_rf(::File.join(@new_resource.destination, ".git"))
         end
       end
 
@@ -105,7 +105,7 @@ class Chef
       end
 
       def git_minor_version
-        @git_minor_version ||= Gem::Version.new(shell_out!('git --version', run_options).stdout.split.last)
+        @git_minor_version ||= Gem::Version.new(shell_out!("git --version", run_options).stdout.split.last)
       end
 
       def existing_git_clone?
@@ -113,14 +113,14 @@ class Chef
       end
 
       def target_dir_non_existent_or_empty?
-        !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
+        !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == [".", ".."]
       end
 
       def find_current_revision
         Chef::Log.debug("#{@new_resource} finding current git revision")
         if ::File.exist?(::File.join(cwd, ".git"))
           # 128 is returned when we're not in a git repo. this is fine
-          result = shell_out!('git rev-parse HEAD', :cwd => cwd, :returns => [0,128]).stdout.strip
+          result = shell_out!("git rev-parse HEAD", :cwd => cwd, :returns => [0, 128]).stdout.strip
         end
         sha_hash?(result) ? result : nil
       end
@@ -141,9 +141,9 @@ class Chef
           remote = @new_resource.remote
 
           args = []
-          args << "-o #{remote}" unless remote == 'origin'
+          args << "-o #{remote}" unless remote == "origin"
           args << "--depth #{@new_resource.depth}" if @new_resource.depth
-          args << "--no-single-branch" if @new_resource.depth and git_minor_version >= Gem::Version.new('1.7.10')
+          args << "--no-single-branch" if @new_resource.depth and git_minor_version >= Gem::Version.new("1.7.10")
 
           Chef::Log.info "#{@new_resource} cloning repo #{@new_resource.repository} to #{@new_resource.destination}"
 
@@ -189,10 +189,9 @@ class Chef
 
       def setup_remote_tracking_branches(remote_name, remote_url)
         converge_by("set up remote tracking branches for #{remote_url} at #{remote_name}") do
-          Chef::Log.debug "#{@new_resource} configuring remote tracking branches for repository #{remote_url} "+
-            "at remote #{remote_name}"
+          Chef::Log.debug "#{@new_resource} configuring remote tracking branches for repository #{remote_url} " + "at remote #{remote_name}"
           check_remote_command = "git config --get remote.#{remote_name}.url"
-          remote_status = shell_out!(check_remote_command, run_options(:cwd => @new_resource.destination, :returns => [0,1,2]))
+          remote_status = shell_out!(check_remote_command, run_options(:cwd => @new_resource.destination, :returns => [0, 1, 2]))
           case remote_status.exitstatus
           when 0, 2
             # * Status 0 means that we already have a remote with this name, so we should update the url
@@ -200,7 +199,7 @@ class Chef
             # * Status 2 means that we have multiple urls assigned to the same remote (not a good idea)
             #   which we can fix by replacing them all with our target url (hence the --replace-all option)
 
-            if multiple_remotes?(remote_status) || !remote_matches?(remote_url,remote_status)
+            if multiple_remotes?(remote_status) || !remote_matches?(remote_url, remote_status)
               update_remote_url_command = "git config --replace-all remote.#{remote_name}.url #{remote_url}"
               shell_out!(update_remote_url_command, run_options(:cwd => @new_resource.destination))
             end
@@ -250,18 +249,18 @@ class Chef
         # Using such a degenerate annotated tag would be very
         # confusing. We avoid the issue by disallowing the use of
         # annotated tags named 'HEAD'.
-        if rev_search_pattern != 'HEAD'
-          found = find_revision(refs, @new_resource.revision, '^{}')
+        if rev_search_pattern != "HEAD"
+          found = find_revision(refs, @new_resource.revision, "^{}")
         else
-          found = refs_search(refs, 'HEAD')
+          found = refs_search(refs, "HEAD")
         end
         found = find_revision(refs, @new_resource.revision) if found.empty?
         found.size == 1 ? found.first[0] : nil
       end
 
-      def find_revision(refs, revision, suffix="")
-        found = refs_search(refs, rev_match_pattern('refs/tags/', revision) + suffix)
-        found = refs_search(refs, rev_match_pattern('refs/heads/', revision) + suffix) if found.empty?
+      def find_revision(refs, revision, suffix = "")
+        found = refs_search(refs, rev_match_pattern("refs/tags/", revision) + suffix)
+        found = refs_search(refs, rev_match_pattern("refs/heads/", revision) + suffix) if found.empty?
         found = refs_search(refs, revision + suffix) if found.empty?
         found
       end
@@ -275,15 +274,15 @@ class Chef
       end
 
       def rev_search_pattern
-        if ['', 'HEAD'].include? @new_resource.revision
-          'HEAD'
+        if ["", "HEAD"].include? @new_resource.revision
+          "HEAD"
         else
-          @new_resource.revision + '*'
+          @new_resource.revision + "*"
         end
       end
 
       def git_ls_remote(rev_pattern)
-        command = git(%Q(ls-remote "#{@new_resource.repository}" "#{rev_pattern}"))
+        command = git(%Q{ls-remote "#{@new_resource.repository}" "#{rev_pattern}"})
         shell_out!(command, run_options).stdout
       end
 
@@ -293,28 +292,27 @@ class Chef
 
       private
 
-      def run_options(run_opts={})
+      def run_options(run_opts = {})
         env = {}
         if @new_resource.user
           run_opts[:user] = @new_resource.user
           # Certain versions of `git` misbehave if git configuration is
           # inaccessible in $HOME. We need to ensure $HOME matches the
           # user who is executing `git` not the user running Chef.
-          env['HOME'] = begin
-            require 'etc'
+          env["HOME"] = begin
+            require "etc"
             Etc.getpwnam(@new_resource.user).dir
           rescue ArgumentError # user not found
             raise Chef::Exceptions::User, "Could not determine HOME for specified user '#{@new_resource.user}' for resource '#{@new_resource.name}'"
           end
         end
         run_opts[:group] = @new_resource.group if @new_resource.group
-        env['GIT_SSH'] = @new_resource.ssh_wrapper if @new_resource.ssh_wrapper
+        env["GIT_SSH"] = @new_resource.ssh_wrapper if @new_resource.ssh_wrapper
         run_opts[:log_tag] = @new_resource.to_s
         run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
         env.merge!(@new_resource.environment) if @new_resource.environment
         run_opts[:environment] = env unless env.empty?
         run_opts
-
       end
 
       def cwd
diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb
index a802758..efcbef8 100644
--- a/lib/chef/provider/group.rb
+++ b/lib/chef/provider/group.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/provider'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/command'
-require 'etc'
+require "chef/provider"
+require "chef/mixin/shell_out"
+require "chef/mixin/command"
+require "etc"
 
 class Chef
   class Provider
@@ -86,7 +86,7 @@ class Chef
       # <false>:: If a change is not required
       def compare_group
         @change_desc = [ ]
-        if @new_resource.gid.to_s  != @current_resource.gid.to_s
+        if @new_resource.gid.to_s != @current_resource.gid.to_s
           @change_desc << "change gid #{@current_resource.gid} to #{@new_resource.gid}"
         end
 
@@ -125,7 +125,7 @@ class Chef
       def action_create
         case @group_exists
         when false
-          converge_by("create #{@new_resource.group_name}") do
+          converge_by("create group #{@new_resource.group_name}") do
             create_group
             Chef::Log.info("#{@new_resource} created")
           end
diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb
index 6ac9d03..4a02d5e 100644
--- a/lib/chef/provider/group/aix.rb
+++ b/lib/chef/provider/group/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/provider/group/groupadd'
-require 'chef/mixin/shell_out'
+require "chef/provider/group/groupadd"
+require "chef/mixin/shell_out"
 
 class Chef
   class Provider
     class Group
       class Aix < Chef::Provider::Group::Groupadd
+        provides :group, platform: "aix"
 
         def required_binaries
           [ "/usr/bin/mkgroup",
@@ -68,10 +69,10 @@ class Chef
 
         def set_options
           opts = ""
-          { :gid => "id" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option|
+          { :gid => "id" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
             if @current_resource.send(field) != @new_resource.send(field)
               if @new_resource.send(field)
-                Chef::Log.debug("#{@new_resource} setting #{field.to_s} to #{@new_resource.send(field)}")
+                Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field)}")
                 opts << " '#{option}=#{@new_resource.send(field)}'"
               end
             end
diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb
index d7e8f2e..08661f2 100644
--- a/lib/chef/provider/group/dscl.rb
+++ b/lib/chef/provider/group/dscl.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dreamcat4 (<dreamcat4 at gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,8 +35,8 @@ class Chef
         def safe_dscl(*args)
           result = dscl(*args)
           return "" if ( args.first =~ /^delete/ ) && ( result[1].exitstatus != 0 )
-          raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") unless result[1].exitstatus == 0
-          raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") if result[2] =~ /No such key: /
+          raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") unless result[1].exitstatus == 0
+          raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") if result[2] =~ /No such key: /
           return result[2]
         end
 
@@ -53,14 +53,14 @@ class Chef
 
           if group_info
             group_info.each_line do |line|
-              key, val = line.split(': ')
+              key, val = line.split(": ")
               val.strip! if val
               case key.downcase
-              when 'primarygroupid'
+              when "primarygroupid"
                 @new_resource.gid(val) unless @new_resource.gid
                 @current_resource.gid(val)
-              when 'groupmembership'
-                @current_resource.members(val.split(' '))
+              when "groupmembership"
+                @current_resource.members(val.split(" "))
               end
             end
           end
@@ -69,7 +69,7 @@ class Chef
         end
 
         # get a free GID greater than 200
-        def get_free_gid(search_limit=1000)
+        def get_free_gid(search_limit = 1000)
           gid = nil; next_gid_guess = 200
           groups_gids = safe_dscl("list /Groups gid")
           while(next_gid_guess < search_limit + 200)
@@ -90,8 +90,8 @@ class Chef
         end
 
         def set_gid
-          @new_resource.gid(get_free_gid) if [nil,""].include? @new_resource.gid
-          raise(Chef::Exceptions::Group,"gid is already in use") if gid_used?(@new_resource.gid)
+          @new_resource.gid(get_free_gid) if [nil, ""].include? @new_resource.gid
+          raise(Chef::Exceptions::Group, "gid is already in use") if gid_used?(@new_resource.gid)
           safe_dscl("create /Groups/#{@new_resource.group_name} PrimaryGroupID #{@new_resource.gid}")
         end
 
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index 521affa..dcf526b 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
 
 class Chef
   class Provider
     class Group
       class Gpasswd < Chef::Provider::Group::Groupadd
+        provides :group
 
         def load_current_resource
           super
diff --git a/lib/chef/provider/group/groupadd.rb b/lib/chef/provider/group/groupadd.rb
index cb480aa..bc6b5d0 100644
--- a/lib/chef/provider/group/groupadd.rb
+++ b/lib/chef/provider/group/groupadd.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -96,15 +96,15 @@ class Chef
         end
 
         def add_member(member)
-          raise Chef::Exceptions::Group, "you must override add_member in #{self.to_s}"
+          raise Chef::Exceptions::Group, "you must override add_member in #{self}"
         end
 
         def remove_member(member)
-          raise Chef::Exceptions::Group, "you must override remove_member in #{self.to_s}"
+          raise Chef::Exceptions::Group, "you must override remove_member in #{self}"
         end
 
         def set_members(members)
-          raise Chef::Exceptions::Group, "you must override set_members in #{self.to_s}"
+          raise Chef::Exceptions::Group, "you must override set_members in #{self}"
         end
 
         # Little bit of magic as per Adam's useradd provider to pull the assign the command line flags
@@ -113,11 +113,11 @@ class Chef
         # <string>:: A string containing the option and then the quoted value
         def set_options
           opts = ""
-          { :gid => "-g" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option|
+          { :gid => "-g" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
             if @current_resource.send(field) != @new_resource.send(field)
               if @new_resource.send(field)
                 opts << " #{option} '#{@new_resource.send(field)}'"
-                Chef::Log.debug("#{@new_resource} set #{field.to_s} to #{@new_resource.send(field)}")
+                Chef::Log.debug("#{@new_resource} set #{field} to #{@new_resource.send(field)}")
               end
             end
           end
@@ -125,7 +125,7 @@ class Chef
         end
 
         def groupadd_options
-          opts = ''
+          opts = ""
           opts << " -r" if @new_resource.system
           opts << " -o" if @new_resource.non_unique
           opts
diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb
index f929954..379d00e 100644
--- a/lib/chef/provider/group/groupmod.rb
+++ b/lib/chef/provider/group/groupmod.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dan Crosta (<dcrosta at late.am>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -111,7 +111,7 @@ class Chef
         #
         # ==== Returns
         # <string>:: A string containing the option and then the quoted value
-        def set_options(overwrite_gid=false)
+        def set_options(overwrite_gid = false)
           opts = ""
           if overwrite_gid || @new_resource.gid && (@current_resource.gid != @new_resource.gid)
             opts << " -g '#{@new_resource.gid}'"
diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb
index 7a66ab4..4fd78b6 100644
--- a/lib/chef/provider/group/pw.rb
+++ b/lib/chef/provider/group/pw.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,6 +20,7 @@ class Chef
   class Provider
     class Group
       class Pw < Chef::Provider::Group
+        provides :group, platform: "freebsd"
 
         def load_current_resource
           super
@@ -108,7 +109,7 @@ class Chef
           else
             # Append is not set so we're resetting the membership of
             # the group to the given members.
-            members_to_be_added = @new_resource.members
+            members_to_be_added = @new_resource.members.dup
             @current_resource.members.each do |member|
               # No need to re-add a member if it's present in the new
               # list of members
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index 7ac2831..f6f4fa1 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
 
 class Chef
   class Provider
     class Group
       class Suse < Chef::Provider::Group::Groupadd
+        provides :group, platform: "opensuse", platform_version: "< 12.3"
+        provides :group, platform: "suse", platform_version: "< 12.0"
 
         def load_current_resource
           super
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index e50e13c..e4b1918 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/provider/group/groupadd'
+require "chef/provider/group/groupadd"
 
 class Chef
   class Provider
     class Group
       class Usermod < Chef::Provider::Group::Groupadd
 
-        provides :group, os: "openbsd"
+        provides :group, os: %w{openbsd solaris2 hpux}
+        provides :group, platform: "opensuse"
 
         def load_current_resource
           super
@@ -40,13 +41,13 @@ class Chef
 
           requirements.assert(:modify, :manage) do |a|
             a.assertion { @new_resource.members.empty? || @new_resource.append }
-            a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self.to_s}, must set append true in group"
+            a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self}, must set append true in group"
             # No whyrun alternative - this action is simply not supported.
           end
 
           requirements.assert(:all_actions) do |a|
             a.assertion { @new_resource.excluded_members.empty? }
-            a.failure_message Chef::Exceptions::Group, "excluded_members is not supported by #{self.to_s}"
+            a.failure_message Chef::Exceptions::Group, "excluded_members is not supported by #{self}"
             # No whyrun alternative - this action is simply not supported.
           end
         end
@@ -61,7 +62,7 @@ class Chef
               add_member(member)
             end
           else
-            raise Chef::Exceptions::UnsupportedAction, "Setting members directly is not supported by #{self.to_s}"
+            raise Chef::Exceptions::UnsupportedAction, "Setting members directly is not supported by #{self}"
           end
         end
 
@@ -72,7 +73,7 @@ class Chef
         def remove_member(member)
           # This provider only supports adding members with
           # append. This function should never be called.
-          raise Chef::Exceptions::UnsupportedAction, "Removing members members is not supported by #{self.to_s}"
+          raise Chef::Exceptions::UnsupportedAction, "Removing members members is not supported by #{self}"
         end
 
         def append_flags
diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb
index 54e49b0..64b4587 100644
--- a/lib/chef/provider/group/windows.rb
+++ b/lib/chef/provider/group/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/user'
+require "chef/provider/user"
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'chef/util/windows/net_group'
+  require "chef/util/windows/net_group"
 end
 
 class Chef
@@ -28,7 +28,7 @@ class Chef
 
         provides :group, os: "windows"
 
-        def initialize(new_resource,run_context)
+        def initialize(new_resource, run_context)
           super
           @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.group_name)
         end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index 61aff43..b52368f 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'chef/http/simple'
+require "tempfile"
+require "chef/http/simple"
 
 class Chef
   class Provider
@@ -42,7 +42,7 @@ class Chef
         # and false for a "304 Not Modified" response
         modified = @http.head(
           "#{@new_resource.url}",
-          @new_resource.headers
+          @new_resource.headers,
         )
         Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
         Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}")
@@ -59,7 +59,7 @@ class Chef
           message = check_message(@new_resource.message)
           body = @http.get(
             "#{@new_resource.url}",
-            @new_resource.headers
+            @new_resource.headers,
           )
           Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful")
           Chef::Log.debug("#{@new_resource} GET request response: #{body}")
@@ -73,7 +73,7 @@ class Chef
           body = @http.put(
             "#{@new_resource.url}",
             message,
-            @new_resource.headers
+            @new_resource.headers,
           )
           Chef::Log.info("#{@new_resource} PUT to #{@new_resource.url} successful")
           Chef::Log.debug("#{@new_resource} PUT request response: #{body}")
@@ -87,7 +87,7 @@ class Chef
           body = @http.post(
             "#{@new_resource.url}",
             message,
-            @new_resource.headers
+            @new_resource.headers,
           )
           Chef::Log.info("#{@new_resource} POST to #{@new_resource.url} message: #{message.inspect} successful")
           Chef::Log.debug("#{@new_resource} POST request response: #{body}")
@@ -99,7 +99,7 @@ class Chef
         converge_by("#{@new_resource} DELETE to #{@new_resource.url}") do
           body = @http.delete(
             "#{@new_resource.url}",
-            @new_resource.headers
+            @new_resource.headers,
           )
           @new_resource.updated_by_last_action(true)
           Chef::Log.info("#{@new_resource} DELETE to #{@new_resource.url} successful")
@@ -109,13 +109,13 @@ class Chef
 
       private
 
-        def check_message(message)
-          if message.kind_of?(Proc)
-            message.call
-          else
-            message
-          end
+      def check_message(message)
+        if message.kind_of?(Proc)
+          message.call
+        else
+          message
         end
+      end
 
     end
   end
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 06080c9..d00d5cd 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jason K. Jackson (jasonjackson at gmail.com)
-# Copyright:: Copyright (c) 2009 Jason K. Jackson
+# Copyright:: Copyright 2009-2016, Jason K. Jackson
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
-require 'chef/provider'
-require 'chef/resource/file'
-require 'chef/exceptions'
-require 'erb'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/mixin/shell_out"
+require "chef/provider"
+require "chef/resource/file"
+require "chef/exceptions"
+require "erb"
 
 #  Recipe example:
 #
@@ -39,6 +39,8 @@ require 'erb'
 class Chef
   class Provider
     class Ifconfig < Chef::Provider
+      provides :ifconfig
+
       include Chef::Mixin::ShellOut
       include Chef::Mixin::Command
 
@@ -65,7 +67,7 @@ class Chef
         @status.stdout.each_line do |line|
           if !line[0..9].strip.empty?
             @int_name = line[0..9].strip
-            @interfaces[@int_name] = {"hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp }
+            @interfaces[@int_name] = { "hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp }
           else
             @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? ($1) : "nil") if line =~ /inet addr:/
             @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? ($1) : "nil") if line =~ /Bcast:/
@@ -107,7 +109,7 @@ class Chef
             command = add_command
             converge_by ("run #{command} to add #{@new_resource}") do
               run_command(
-                :command => command
+                :command => command,
               )
               Chef::Log.info("#{@new_resource} added")
             end
@@ -125,7 +127,7 @@ class Chef
             command = enable_command
             converge_by ("run #{command} to enable #{@new_resource}") do
               run_command(
-                :command => command
+                :command => command,
               )
               Chef::Log.info("#{@new_resource} enabled")
             end
@@ -139,7 +141,7 @@ class Chef
           command = delete_command
           converge_by ("run #{command} to delete #{@new_resource}") do
             run_command(
-              :command => command
+              :command => command,
             )
             Chef::Log.info("#{@new_resource} deleted")
           end
@@ -156,7 +158,7 @@ class Chef
           command = disable_command
           converge_by ("run #{command} to disable #{@new_resource}") do
             run_command(
-              :command => command
+              :command => command,
             )
             Chef::Log.info("#{@new_resource} disabled")
           end
@@ -191,8 +193,9 @@ class Chef
       end
 
       private
+
       def add_command
-        command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
+        command = "ifconfig #{@new_resource.device} #{@new_resource.target}"
         command << " netmask #{@new_resource.mask}" if @new_resource.mask
         command << " metric #{@new_resource.metric}" if @new_resource.metric
         command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
@@ -200,7 +203,7 @@ class Chef
       end
 
       def enable_command
-        command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
+        command = "ifconfig #{@new_resource.device} #{@new_resource.target}"
         command << " netmask #{@new_resource.mask}" if @new_resource.mask
         command << " metric #{@new_resource.metric}" if @new_resource.metric
         command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
@@ -216,7 +219,7 @@ class Chef
       end
 
       def loopback_device
-        'lo'
+        "lo"
       end
     end
   end
diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb
index 8fead44..81164db 100644
--- a/lib/chef/provider/ifconfig/aix.rb
+++ b/lib/chef/provider/ifconfig/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (kaustubh at clogeny.com)
-# Copyright:: Copyright (c) 2013 Opscode, Inc
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/ifconfig'
+require "chef/provider/ifconfig"
 
 class Chef
   class Provider
     class Ifconfig
       class Aix < Chef::Provider::Ifconfig
+        provides :ifconfig, platform: %w{aix}
 
         def load_current_resource
           @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name)
@@ -66,6 +67,7 @@ class Chef
         end
 
         private
+
         def add_command
           # ifconfig changes are temporary, chdev persist across reboots.
           raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if @new_resource.metric
@@ -87,7 +89,7 @@ class Chef
         def hex_to_dec_netmask(netmask)
           # example '0xffff0000' -> '255.255.0.0'
           dec = netmask[2..3].to_i(16).to_s(10)
-          [4,6,8].each { |n| dec = dec + "." + netmask[n..n+1].to_i(16).to_s(10) }
+          [4, 6, 8].each { |n| dec = dec + "." + netmask[n..n + 1].to_i(16).to_s(10) }
           dec
         end
 
diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb
index 7589971..872b0db 100644
--- a/lib/chef/provider/ifconfig/debian.rb
+++ b/lib/chef/provider/ifconfig/debian.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/provider/ifconfig'
-require 'chef/util/file_edit'
+require "chef/provider/ifconfig"
+require "chef/util/file_edit"
 
 class Chef
   class Provider
     class Ifconfig
       class Debian < Chef::Provider::Ifconfig
+        provides :ifconfig, platform: %w{ubuntu}, platform_version: ">= 11.10"
+        provides :ifconfig, platform: %w{debian}, platform_version: ">= 7.0"
 
         INTERFACES_FILE = "/etc/network/interfaces"
         INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d"
@@ -65,7 +67,7 @@ iface <%= @new_resource.device %> inet static
           dir.run_action(:create)
           new_resource.updated_by_last_action(true) if dir.updated_by_last_action?
           # roll our own file_edit resource, this will not get reported until we have a file_edit resource
-          interfaces_dot_d_for_regexp = INTERFACES_DOT_D_DIR.gsub(/\./, '\.')  # escape dots for the regexp
+          interfaces_dot_d_for_regexp = INTERFACES_DOT_D_DIR.gsub(/\./, '\.') # escape dots for the regexp
           regexp = %r{^\s*source\s+#{interfaces_dot_d_for_regexp}/\*\s*$}
           unless ::File.exists?(INTERFACES_FILE) && regexp.match(IO.read(INTERFACES_FILE))
             converge_by("modifying #{INTERFACES_FILE} to source #{INTERFACES_DOT_D_DIR}") do
diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb
index ef35b0e..0c28e64 100644
--- a/lib/chef/provider/ifconfig/redhat.rb
+++ b/lib/chef/provider/ifconfig/redhat.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/ifconfig'
+require "chef/provider/ifconfig"
 
 class Chef
   class Provider
     class Ifconfig
       class Redhat < Chef::Provider::Ifconfig
+        provides :ifconfig, platform_family: %w{fedora rhel}
 
         def initialize(new_resource, run_context)
           super(new_resource, run_context)
diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb
index c811c13..116efcc 100644
--- a/lib/chef/provider/link.rb
+++ b/lib/chef/provider/link.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/log'
-require 'chef/mixin/file_class'
-require 'chef/resource/link'
-require 'chef/provider'
-require 'chef/scan_access_control'
-require 'chef/util/path_helper'
+require "chef/config"
+require "chef/log"
+require "chef/mixin/file_class"
+require "chef/resource/link"
+require "chef/provider"
+require "chef/scan_access_control"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
@@ -75,18 +75,18 @@ class Chef
           a.assertion do
             if @current_resource.to
               @current_resource.link_type == @new_resource.link_type and
-              (@current_resource.link_type == :symbolic  or @current_resource.to != '')
+                (@current_resource.link_type == :symbolic or @current_resource.to != "")
             else
               true
             end
           end
-          a.failure_message Chef::Exceptions::Link, "Cannot delete #{@new_resource} at #{@new_resource.target_file}! Not a #{@new_resource.link_type.to_s} link."
+          a.failure_message Chef::Exceptions::Link, "Cannot delete #{@new_resource} at #{@new_resource.target_file}! Not a #{@new_resource.link_type} link."
           a.whyrun("Would assume the link at #{@new_resource.target_file} was previously created")
         end
       end
 
       def canonicalize(path)
-        Chef::Platform.windows? ? path.gsub('/', '\\') : path
+        Chef::Platform.windows? ? path.gsub("/", '\\') : path
       end
 
       def action_create
@@ -118,7 +118,7 @@ class Chef
           end
           if @new_resource.link_type == :symbolic
             converge_by("create symlink at #{@new_resource.target_file} to #{@new_resource.to}") do
-              file_class.symlink(canonicalize(@new_resource.to), at new_resource.target_file)
+              file_class.symlink(canonicalize(@new_resource.to), @new_resource.target_file)
               Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.target_file} -> #{@new_resource.to}")
               Chef::Log.info("#{@new_resource} created")
             end
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index 40eaf0a..eef4077 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Cary Penniman (<cary at rightscale.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/lwrp_base.rb b/lib/chef/provider/lwrp_base.rb
index 492ddda..f5ba30b 100644
--- a/lib/chef/provider/lwrp_base.rb
+++ b/lib/chef/provider/lwrp_base.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008-2012 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider'
+require "chef/provider"
+require "chef/dsl/recipe"
+require "chef/dsl/include_recipe"
 
 class Chef
   class Provider
@@ -27,124 +29,71 @@ class Chef
     # Base class from which LWRP providers inherit.
     class LWRPBase < Provider
 
-      # Chef::Provider::LWRPBase::InlineResources
-      # Implementation of inline resource convergence for LWRP providers. See
-      # Provider::LWRPBase.use_inline_resources for a longer explanation.
-      #
-      # This code is restricted to a module so that it can be selectively
-      # applied to providers on an opt-in basis.
-      module InlineResources
-
-        # Class methods for InlineResources. Overrides the `action` DSL method
-        # with one that enables inline resource convergence.
-        module ClassMethods
-          # Defines an action method on the provider, using
-          # recipe_eval_with_update_check to execute the given block.
-          def action(name, &block)
-            define_method("action_#{name}") do
-              recipe_eval_with_update_check(&block)
-            end
-          end
-        end
-
-        # Executes the given block in a temporary run_context with its own
-        # resource collection. After the block is executed, any resources
-        # declared inside are converged, and if any are updated, the
-        # new_resource will be marked updated.
-        def recipe_eval_with_update_check(&block)
-          saved_run_context = @run_context
-          temp_run_context = @run_context.dup
-          @run_context = temp_run_context
-          @run_context.resource_collection = Chef::ResourceCollection.new
-
-          return_value = instance_eval(&block)
-          Chef::Runner.new(@run_context).converge
-          return_value
-        ensure
-          @run_context = saved_run_context
-          if temp_run_context.resource_collection.any? {|r| r.updated? }
-            new_resource.updated_by_last_action(true)
-          end
-        end
-
-      end
-
-      extend Chef::Mixin::ConvertToClassName
-      extend Chef::Mixin::FromFile
-
       include Chef::DSL::Recipe
 
       # These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore.
-      # They are not included by its replacment, Chef::DSL::Recipe, but
+      # They are not included by its replacement, Chef::DSL::Recipe, but
       # they may be used in existing LWRPs.
       include Chef::DSL::PlatformIntrospection
       include Chef::DSL::DataQuery
 
-      def self.build_from_file(cookbook_name, filename, run_context)
-        provider_class = nil
-        provider_name = filename_to_qualified_string(cookbook_name, filename)
+      # Allow include_recipe from within LWRP provider code
+      include Chef::DSL::IncludeRecipe
+
+      # no-op `load_current_resource`. Allows simple LWRP providers to work
+      # without defining this method explicitly (silences
+      # Chef::Exceptions::Override exception)
+      def load_current_resource
+      end
+
+      # class methods
+      class <<self
+        include Chef::Mixin::ConvertToClassName
+        include Chef::Mixin::FromFile
+
+        def build_from_file(cookbook_name, filename, run_context)
+          if LWRPBase.loaded_lwrps[filename]
+            Chef::Log.debug("LWRP provider #{filename} from cookbook #{cookbook_name} has already been loaded!  Skipping the reload.")
+            return loaded_lwrps[filename]
+          end
 
-        class_name = convert_to_class_name(provider_name)
+          resource_name = filename_to_qualified_string(cookbook_name, filename)
 
-        if Chef::Provider.const_defined?(class_name, false)
-          Chef::Log.info("#{class_name} light-weight provider is already initialized -- Skipping loading #{filename}!")
-          Chef::Log.debug("Overriding already defined LWRPs is not supported anymore starting with Chef 12.")
-          provider_class = Chef::Provider.const_get(class_name)
-        else
+          # We load the class first to give it a chance to set its own name
           provider_class = Class.new(self)
-          Chef::Provider.const_set(class_name, provider_class)
+          provider_class.provides resource_name.to_sym
           provider_class.class_from_file(filename)
-          Chef::Log.debug("Loaded contents of #{filename} into a provider named #{provider_name} defined in Chef::Provider::#{class_name}")
-        end
 
-        provider_class
-      end
+          # Respect resource_name set inside the LWRP
+          provider_class.instance_eval do
+            define_singleton_method(:to_s) do
+              "LWRP provider #{resource_name} from cookbook #{cookbook_name}"
+            end
+            define_singleton_method(:inspect) { to_s }
+          end
 
-      # Enables inline evaluation of resources in provider actions.
-      #
-      # Without this option, any resources declared inside the LWRP are added
-      # to the resource collection after the current position at the time the
-      # action is executed. Because they are added to the primary resource
-      # collection for the chef run, they can notify other resources outside
-      # the LWRP, and potentially be notified by resources outside the LWRP
-      # (but this is complicated by the fact that they don't exist until the
-      # provider executes). In this mode, it is impossible to correctly set the
-      # updated_by_last_action flag on the parent LWRP resource, since it
-      # executes and returns before its component resources are run.
-      #
-      # With this option enabled, each action creates a temporary run_context
-      # with its own resource collection, evaluates the action's code in that
-      # context, and then converges the resources created. If any resources
-      # were updated, then this provider's new_resource will be marked updated.
-      #
-      # In this mode, resources created within the LWRP cannot interact with
-      # external resources via notifies, though notifications to other
-      # resources within the LWRP will work. Delayed notifications are executed
-      # at the conclusion of the provider's action, *not* at the end of the
-      # main chef run.
-      #
-      # This mode of evaluation is experimental, but is believed to be a better
-      # set of tradeoffs than the append-after mode, so it will likely become
-      # the default in a future major release of Chef.
-      #
-      def self.use_inline_resources
-        extend InlineResources::ClassMethods
-        include InlineResources
-      end
+          Chef::Log.debug("Loaded contents of #{filename} into provider #{resource_name} (#{provider_class})")
 
-      # DSL for defining a provider's actions.
-      def self.action(name, &block)
-        define_method("action_#{name}") do
-          instance_eval(&block)
+          LWRPBase.loaded_lwrps[filename] = true
+
+          Chef::Provider.register_deprecated_lwrp_class(provider_class, convert_to_class_name(resource_name))
+
+          provider_class
         end
-      end
 
-      # no-op `load_current_resource`. Allows simple LWRP providers to work
-      # without defining this method explicitly (silences
-      # Chef::Exceptions::Override exception)
-      def load_current_resource
-      end
+        # DSL for defining a provider's actions.
+        def action(name, &block)
+          define_method("action_#{name}") do
+            instance_eval(&block)
+          end
+        end
+
+        protected
 
+        def loaded_lwrps
+          @loaded_lwrps ||= {}
+        end
+      end
     end
   end
 end
diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb
index 325f1b5..d047b69 100644
--- a/lib/chef/provider/mdadm.rb
+++ b/lib/chef/provider/mdadm.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/provider'
+require "chef/log"
+require "chef/provider"
 
 class Chef
   class Provider
@@ -39,7 +39,7 @@ class Chef
         Chef::Log.debug("#{@new_resource} checking for software raid device #{@current_resource.raid_device}")
 
         device_not_found = 4
-        mdadm = shell_out!("mdadm --detail --test #{@new_resource.raid_device}", :returns => [0,device_not_found])
+        mdadm = shell_out!("mdadm --detail --test #{@new_resource.raid_device}", :returns => [0, device_not_found])
         exists = (mdadm.status == 0)
         @current_resource.exists(exists)
       end
diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb
index 1631d87..cc4a548 100644
--- a/lib/chef/provider/mount.rb
+++ b/lib/chef/provider/mount.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2009-2014 Chef Software, Inc.
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,14 +17,13 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/mixin/shell_out'
-require 'chef/provider'
+require "chef/log"
+require "chef/mixin/shell_out"
+require "chef/provider"
 
 class Chef
   class Provider
     class Mount < Chef::Provider
-
       include Chef::Mixin::ShellOut
 
       attr_accessor :unmount_retries
@@ -43,13 +42,17 @@ class Chef
       end
 
       def action_mount
-        unless current_resource.mounted
+        if current_resource.mounted
+          if mount_options_unchanged?
+            Chef::Log.debug("#{new_resource} is already mounted")
+          else
+            action_remount
+          end
+        else
           converge_by("mount #{current_resource.device} to #{current_resource.mount_point}") do
             mount_fs
             Chef::Log.info("#{new_resource} mounted")
           end
-        else
-          Chef::Log.debug("#{new_resource} is already mounted")
         end
       end
 
@@ -115,12 +118,12 @@ class Chef
 
       # should actually check if the filesystem is mounted (not just return current_resource) and return true/false
       def mounted?
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not implement #mounted?"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not implement #mounted?"
       end
 
       # should check new_resource against current_resource to see if mount options need updating, returns true/false
       def mount_options_unchanged?
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not implement #mount_options_unchanged?"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not implement #mount_options_unchanged?"
       end
 
       #
@@ -131,28 +134,28 @@ class Chef
 
       # should implement mounting of the filesystem, raises if action does not succeed
       def mount_fs
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :mount"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :mount"
       end
 
       # should implement unmounting of the filesystem, raises if action does not succeed
       def umount_fs
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :umount"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :umount"
       end
 
       # should implement remounting of the filesystem (via a -o remount or some other atomic-ish action that isn't
       # simply a umount/mount style remount), raises if action does not succeed
       def remount_fs
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :remount"
       end
 
       # should implement enabling of the filesystem (e.g. in /etc/fstab), raises if action does not succeed
       def enable_fs
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :enable"
       end
 
       # should implement disabling of the filesystem (e.g. in /etc/fstab), raises if action does not succeed
       def disable_fs
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :disable"
       end
 
       private
diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb
index 0d7e11a..12f0d67 100644
--- a/lib/chef/provider/mount/aix.rb
+++ b/lib/chef/provider/mount/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author::
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/mount'
+require "chef/provider/mount"
 
 class Chef
   class Provider
     class Mount
       class Aix < Chef::Provider::Mount::Mount
+        provides :mount, platform: %w{aix}
 
         # Override for aix specific handling
         def initialize(new_resource, run_context)
@@ -31,7 +32,7 @@ class Chef
             @new_resource.options.clear
           end
           if @new_resource.fstype == "auto"
-            @new_resource.fstype = nil
+            @new_resource.send(:clear_fstype)
           end
         end
 
@@ -41,7 +42,7 @@ class Chef
 
           # lsfs o/p = #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
           # search only for current mount point
-          shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do | line |
+          shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do |line|
             case line
             when /^#\s/
               next
@@ -60,7 +61,7 @@ class Chef
               Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems")
               next
             when /^#{Regexp.escape(@new_resource.mount_point)}/
-              enabled=false
+              enabled = false
               Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/filesystems")
             end
           end
@@ -98,13 +99,13 @@ class Chef
             end
 
             command << case @new_resource.device_type
-            when :device
-              " #{device_real}"
-            when :label
-              " -L #{@new_resource.device}"
-            when :uuid
-              " -U #{@new_resource.device}"
-            end
+                       when :device
+                         " #{device_real}"
+                       when :label
+                         " -L #{@new_resource.device}"
+                       when :uuid
+                         " -U #{@new_resource.device}"
+                       end
             command << " #{@new_resource.mount_point}"
             shell_out!(command)
             Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}")
@@ -166,14 +167,14 @@ class Chef
               end
             end
             ::File.open("/etc/filesystems", "w") do |fstab|
-              contents.each { |line| fstab.puts line}
+              contents.each { |line| fstab.puts line }
             end
           else
             Chef::Log.debug("#{@new_resource} is not enabled - nothing to do")
           end
         end
 
+      end
     end
-   end
   end
 end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index 0a6e269..f8b8684 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/provider/mount'
-require 'chef/log'
+require "chef/provider/mount"
+require "chef/log"
 
 class Chef
   class Provider
     class Mount
       class Mount < Chef::Provider::Mount
 
+        provides :mount
+
         def initialize(new_resource, run_context)
           super
           @real_device = nil
@@ -102,13 +104,13 @@ class Chef
             command = "mount -t #{@new_resource.fstype}"
             command << " -o #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty?
             command << case @new_resource.device_type
-            when :device
-              " #{device_real}"
-            when :label
-              " -L #{@new_resource.device}"
-            when :uuid
-              " -U #{@new_resource.device}"
-            end
+                       when :device
+                         " #{device_real}"
+                       when :label
+                         " -L #{@new_resource.device}"
+                       when :uuid
+                         " -U #{@new_resource.device}"
+                       end
             command << " #{@new_resource.mount_point}"
             shell_out!(command)
             Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}")
@@ -177,7 +179,7 @@ class Chef
             end
 
             ::File.open("/etc/fstab", "w") do |fstab|
-              contents.reverse_each { |line| fstab.puts line}
+              contents.reverse_each { |line| fstab.puts line }
             end
           else
             Chef::Log.debug("#{@new_resource} is not enabled - nothing to do")
@@ -191,7 +193,7 @@ class Chef
         def device_should_exist?
           ( @new_resource.device != "none" ) &&
             ( not network_device? ) &&
-            ( not %w[ cgroup tmpfs fuse ].include? @new_resource.fstype )
+            ( not %w{ cgroup tmpfs fuse }.include? @new_resource.fstype )
         end
 
         private
@@ -235,13 +237,13 @@ class Chef
         def device_mount_regex
           if network_device?
             # ignore trailing slash
-            Regexp.escape(device_real)+"/?"
+            Regexp.escape(device_real) + "/?"
           elsif ::File.symlink?(device_real)
             # This regular expression tries to match device_real. If that does not match it will try to match the target of device_real.
             # So given a symlink like this:
             # /dev/mapper/vgroot-tmp.vol -> /dev/dm-9
             # First it will try to match "/dev/mapper/vgroot-tmp.vol". If there is no match it will try matching for "/dev/dm-9".
-            "(?:#{Regexp.escape(device_real)}|#{Regexp.escape(::File.expand_path(::File.readlink(device_real),::File.dirname(device_real)))})"
+            "(?:#{Regexp.escape(device_real)}|#{Regexp.escape(::File.expand_path(::File.readlink(device_real), ::File.dirname(device_real)))})"
           else
             Regexp.escape(device_real)
           end
@@ -257,9 +259,9 @@ class Chef
 
         def mount_options_unchanged?
           @current_resource.fstype == @new_resource.fstype and
-          @current_resource.options == @new_resource.options and
-          @current_resource.dump == @new_resource.dump and
-          @current_resource.pass == @new_resource.pass
+            @current_resource.options == @new_resource.options and
+            @current_resource.dump == @new_resource.dump and
+            @current_resource.pass == @new_resource.pass
         end
 
       end
diff --git a/lib/chef/provider/mount/solaris.rb b/lib/chef/provider/mount/solaris.rb
index d8cec24..a5a7a32 100644
--- a/lib/chef/provider/mount/solaris.rb
+++ b/lib/chef/provider/mount/solaris.rb
@@ -1,8 +1,8 @@
 # Encoding: utf-8
 # Author:: Hugo Fichter
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Author:: Joshua Timberman (<joshua at getchef.com>)
-# Copyright:: Copyright (c) 2009-2014 Chef Software, Inc
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,18 +18,20 @@
 # limitations under the License.
 #
 
-require 'chef/provider/mount'
-require 'chef/log'
-require 'forwardable'
+require "chef/provider/mount"
+require "chef/log"
+require "forwardable"
 
 class Chef
   class Provider
     class Mount
       # Mount Solaris File systems
       class Solaris < Chef::Provider::Mount
+        provides :mount, platform: %w{openindiana opensolaris nexentacore omnios solaris2 smartos}
+
         extend Forwardable
 
-        VFSTAB = '/etc/vfstab'.freeze
+        VFSTAB = "/etc/vfstab".freeze
 
         def_delegator :@new_resource, :device, :device
         def_delegator :@new_resource, :device_type, :device_type
@@ -56,7 +58,7 @@ class Chef
             a.whyrun("Assuming device #{device} would have been created")
           end
 
-          unless fsck_device == '-'
+          unless fsck_device == "-"
             requirements.assert(:mount, :remount) do |a|
               a.assertion { ::File.exist?(fsck_device) }
               a.failure_message(Chef::Exceptions::Mount, "Device #{fsck_device} does not exist")
@@ -73,7 +75,7 @@ class Chef
 
         def mount_fs
           actual_options = options || []
-          actual_options.delete('noauto')
+          actual_options.delete("noauto")
           command = "mount -F #{fstype}"
           command << " -o #{actual_options.join(',')}" unless actual_options.empty?
           command << " #{device} #{mount_point}"
@@ -87,8 +89,8 @@ class Chef
         def remount_fs
           # FIXME: Should remount always do the remount or only if the options change?
           actual_options = options || []
-          actual_options.delete('noauto')
-          mount_options = actual_options.empty? ? '' : ",#{actual_options.join(',')}"
+          actual_options.delete("noauto")
+          mount_options = actual_options.empty? ? "" : ",#{actual_options.join(',')}"
           shell_out!("mount -o remount#{mount_options} #{mount_point}")
         end
 
@@ -115,7 +117,7 @@ class Chef
         end
 
         def etc_tempfile
-          yield Tempfile.open('vfstab', '/etc')
+          yield Tempfile.open("vfstab", "/etc")
         end
 
         def mount_options_unchanged?
@@ -127,7 +129,7 @@ class Chef
             current_options == new_options &&
             current_resource.dump == dump &&
             current_resource.pass == pass &&
-            current_resource.options.include?('noauto') == !mount_at_boot?
+            current_resource.options.include?("noauto") == !mount_at_boot?
         end
 
         def update_current_resource_state
@@ -148,7 +150,7 @@ class Chef
         # /dev/dsk/c1t0d0s0 on / type ufs read/write/setuid/devices/intr/largefiles/logging/xattr/onerror=panic/dev=700040 on Tue May  1 11:33:55 2012
         def mounted?
           mounted = false
-          shell_out!('mount -v').stdout.each_line do |line|
+          shell_out!("mount -v").stdout.each_line do |line|
             case line
             when /^#{device_regex}\s+on\s+#{Regexp.escape(mount_point)}\s+/
               Chef::Log.debug("Special device #{device} is mounted as #{mount_point}")
@@ -180,14 +182,14 @@ class Chef
               options = Regexp.last_match[4]
               # Store the 'mount at boot' column from vfstab as the 'noauto' option
               # in current_resource.options (linux style)
-              if Regexp.last_match[3] == 'no'
+              if Regexp.last_match[3] == "no"
                 if options.nil? || options.empty?
-                  options = 'noauto'
+                  options = "noauto"
                 else
-                  options += ',noauto'
+                  options += ",noauto"
                 end
               end
-              pass = (Regexp.last_match[2] == '-') ? 0 : Regexp.last_match[2].to_i
+              pass = (Regexp.last_match[2] == "-") ? 0 : Regexp.last_match[2].to_i
               Chef::Log.debug("Found mount #{device} to #{mount_point} in #{VFSTAB}")
               next
             when /^[-\/\w]+\s+[-\/\w]+\s+#{Regexp.escape(mount_point)}\s+/
@@ -200,16 +202,16 @@ class Chef
         end
 
         def device_should_exist?
-          !%w(tmpfs nfs ctfs proc mntfs objfs sharefs fd smbfs vxfs).include?(fstype)
+          !%w{tmpfs nfs ctfs proc mntfs objfs sharefs fd smbfs vxfs}.include?(fstype)
         end
 
         def mount_at_boot?
-          options.nil? || !options.include?('noauto')
+          options.nil? || !options.include?("noauto")
         end
 
         def vfstab_write(contents)
           etc_tempfile do |f|
-            f.write(contents.join(''))
+            f.write(contents.join(""))
             f.close
             # move, preserving modes of destination file
             mover = Chef::FileContentManagement::Deploy.strategy(true)
@@ -219,13 +221,13 @@ class Chef
 
         def vfstab_entry
           actual_options = unless options.nil?
-            tempops = options.dup
-            tempops.delete('noauto')
-            tempops
-          end
-          autostr = mount_at_boot? ? 'yes' : 'no'
-          passstr = pass == 0 ? '-' : pass
-          optstr = (actual_options.nil? || actual_options.empty?) ? '-' : actual_options.join(',')
+                             tempops = options.dup
+                             tempops.delete("noauto")
+                             tempops
+                           end
+          autostr = mount_at_boot? ? "yes" : "no"
+          passstr = pass == 0 ? "-" : pass
+          optstr = (actual_options.nil? || actual_options.empty?) ? "-" : actual_options.join(",")
           "\n#{device}\t#{fsck_device}\t#{mount_point}\t#{fstype}\t#{passstr}\t#{autostr}\t#{optstr}\n"
         end
 
@@ -252,7 +254,7 @@ class Chef
         def options_remove_noauto(temp_options)
           new_options = []
           new_options += temp_options.nil? ? [] : temp_options
-          new_options.delete('noauto')
+          new_options.delete("noauto")
           new_options
         end
 
diff --git a/lib/chef/provider/mount/windows.rb b/lib/chef/provider/mount/windows.rb
index 8787347..3ffe326 100644
--- a/lib/chef/provider/mount/windows.rb
+++ b/lib/chef/provider/mount/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/provider/mount'
+require "chef/provider/mount"
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'chef/util/windows/net_use'
-  require 'chef/util/windows/volume'
+  require "chef/util/windows/net_use"
+  require "chef/util/windows/volume"
 end
 
 class Chef
diff --git a/lib/chef/provider/ohai.rb b/lib/chef/provider/ohai.rb
index a6b5ab5..6b5a605 100644
--- a/lib/chef/provider/ohai.rb
+++ b/lib/chef/provider/ohai.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Michael Leianrtas (<mleinartas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,12 @@
 # limitations under the License.
 #
 
-require 'ohai'
+require "ohai"
 
 class Chef
   class Provider
     class Ohai < Chef::Provider
+      provides :ohai
 
       def whyrun_supported?
         true
diff --git a/lib/chef/provider/osx_profile.rb b/lib/chef/provider/osx_profile.rb
new file mode 100644
index 0000000..e93d29b
--- /dev/null
+++ b/lib/chef/provider/osx_profile.rb
@@ -0,0 +1,256 @@
+#
+# Author:: Nate Walck (<nate.walck at gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/log"
+require "chef/provider"
+require "chef/resource"
+require "chef/resource/file"
+require "uuidtools"
+
+class Chef
+  class Provider
+    class OsxProfile < Chef::Provider
+      include Chef::Mixin::Command
+      provides :osx_profile, os: "darwin"
+      provides :osx_config_profile, os: "darwin"
+
+      def whyrun_supported?
+        true
+      end
+
+      def load_current_resource
+        @current_resource = Chef::Resource::OsxProfile.new(@new_resource.name)
+        @current_resource.profile_name(@new_resource.profile_name)
+
+        all_profiles = get_installed_profiles
+        @new_resource.profile(
+          @new_resource.profile ||
+          @new_resource.profile_name
+        )
+
+        @new_profile_hash = get_profile_hash(@new_resource.profile)
+        @new_profile_hash["PayloadUUID"] =
+          config_uuid(@new_profile_hash) if @new_profile_hash
+
+        if @new_profile_hash
+          @new_profile_identifier = @new_profile_hash["PayloadIdentifier"]
+        else
+          @new_profile_identifier = @new_resource.identifier ||
+                                    @new_resource.profile_name
+        end
+
+        if all_profiles.empty?
+          current_profile = nil
+        else
+          current_profile = all_profiles["_computerlevel"].find do |item|
+            item["ProfileIdentifier"] == @new_profile_identifier
+          end
+        end
+        @current_resource.profile(current_profile)
+      end
+
+      def define_resource_requirements
+        requirements.assert(:remove) do |a|
+          if @new_profile_identifier
+            a.assertion {
+              !@new_profile_identifier.nil? and
+                !@new_profile_identifier.end_with?(".mobileconfig") and
+                /^\w+(?:\.\w+)+$/.match(@new_profile_identifier)
+            }
+            a.failure_message RuntimeError, "when removing using the identifier attribute, it must match the profile identifier"
+          else
+            new_profile_name = @new_resource.profile_name
+            a.assertion {
+              !new_profile_name.end_with?(".mobileconfig") and
+                /^\w+(?:\.\w+)+$/.match(new_profile_name)
+            }
+            a.failure_message RuntimeError, "When removing by resource name, it must match the profile identifier "
+          end
+        end
+
+        requirements.assert(:install) do |a|
+          if @new_profile_hash.is_a?(Hash)
+            a.assertion {
+              @new_profile_hash.include?("PayloadIdentifier")
+            }
+            a.failure_message RuntimeError, "The specified profile does not seem to be valid"
+          end
+          if @new_profile_hash.is_a?(String)
+            a.assertion {
+              @new_profile_hash.end_with?(".mobileconfig")
+            }
+            a.failure_message RuntimeError, "#{new_profile_hash}' is not a valid profile"
+          end
+        end
+      end
+
+      def action_install
+        unless profile_installed?
+          converge_by("install profile #{@new_profile_identifier}") do
+            profile_path = write_profile_to_disk
+            install_profile(profile_path)
+            get_installed_profiles(true)
+          end
+        end
+      end
+
+      def action_remove
+        # Clean up profile after removing it
+        if profile_installed?
+          converge_by("remove profile #{@new_profile_identifier}") do
+            remove_profile
+            get_installed_profiles(true)
+          end
+        end
+      end
+
+      def load_profile_hash(new_profile)
+        # file must exist in cookbook
+        if new_profile.end_with?(".mobileconfig")
+          unless cookbook_file_available?(new_profile)
+            error_string = "#{self}: '#{new_profile}' not found in cookbook"
+            raise Chef::Exceptions::FileNotFound, error_string
+          end
+          cookbook_profile = cache_cookbook_profile(new_profile)
+          return read_plist(cookbook_profile)
+        else
+          return nil
+        end
+      end
+
+      def cookbook_file_available?(cookbook_file)
+        run_context.has_cookbook_file_in_cookbook?(
+          @new_resource.cookbook_name, cookbook_file
+        )
+      end
+
+      def get_cache_dir
+        cache_dir = Chef::FileCache.create_cache_path(
+          "profiles/#{@new_resource.cookbook_name}"
+        )
+      end
+
+      def cache_cookbook_profile(cookbook_file)
+        Chef::FileCache.create_cache_path(
+          ::File.join(
+            "profiles",
+            @new_resource.cookbook_name,
+            ::File.dirname(cookbook_file),
+          )
+        )
+        remote_file = Chef::Resource::CookbookFile.new(
+          ::File.join(
+            get_cache_dir,
+            "#{cookbook_file}.remote",
+          ),
+          run_context,
+        )
+        remote_file.cookbook_name = @new_resource.cookbook_name
+        remote_file.source(cookbook_file)
+        remote_file.backup(false)
+        remote_file.run_action(:create)
+        remote_file.path
+      end
+
+      def get_profile_hash(new_profile)
+        if new_profile.is_a?(Hash)
+          return new_profile
+        elsif new_profile.is_a?(String)
+          return load_profile_hash(new_profile)
+        end
+      end
+
+      def config_uuid(profile)
+        # Make a UUID of the profile contents and return as string
+        UUIDTools::UUID.sha1_create(
+          UUIDTools::UUID_DNS_NAMESPACE,
+          profile.to_s,
+        ).to_s
+      end
+
+      def write_profile_to_disk
+        @new_resource.path(Chef::FileCache.create_cache_path("profiles"))
+        tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
+        tempfile.write(@new_profile_hash.to_plist)
+        tempfile.close
+        tempfile.path
+      end
+
+      def install_profile(profile_path)
+        cmd = "profiles -I -F '#{profile_path}'"
+        Chef::Log.debug("cmd: #{cmd}")
+        shellout_results = shell_out(cmd)
+        shellout_results.exitstatus
+      end
+
+      def remove_profile
+        cmd = "profiles -R -p '#{@new_profile_identifier}'"
+        Chef::Log.debug("cmd: #{cmd}")
+        shellout_results = shell_out(cmd)
+        shellout_results.exitstatus
+      end
+
+      def get_installed_profiles(update = nil)
+        if update
+          node.run_state[:config_profiles] = query_installed_profiles
+        else
+          node.run_state[:config_profiles] ||= query_installed_profiles
+        end
+      end
+
+      def query_installed_profiles
+        # Dump all profile metadata to a tempfile
+        tempfile = generate_tempfile
+        write_installed_profiles(tempfile)
+        installed_profiles = read_plist(tempfile)
+        Chef::Log.debug("Saved profiles to run_state")
+        # Clean up the temp file as we do not need it anymore
+        ::File.unlink(tempfile)
+        installed_profiles
+      end
+
+      def generate_tempfile
+        tempfile = ::Dir::Tmpname.create("allprofiles.plist") {}
+      end
+
+      def write_installed_profiles(tempfile)
+        cmd = "profiles -P -o '#{tempfile}'"
+        shell_out!(cmd)
+      end
+
+      def read_plist(xml_file)
+        Plist::parse_xml(xml_file)
+      end
+
+      def profile_installed?
+        # Profile Identifier and UUID must match a currently installed profile
+        if @current_resource.profile.nil? or @current_resource.profile.empty?
+          false
+        else
+          if @new_resource.action.include?(:remove)
+            true
+          else
+            @current_resource.profile["ProfileUUID"] ==
+              @new_profile_hash["PayloadUUID"]
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index 2e8e299..ca9b526 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,24 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/shell_out'
-require 'chef/mixin/command'
-require 'chef/log'
-require 'chef/file_cache'
-require 'chef/platform'
+require "chef/mixin/shell_out"
+require "chef/mixin/command"
+require "chef/mixin/subclass_directive"
+require "chef/log"
+require "chef/file_cache"
+require "chef/platform"
 
 class Chef
   class Provider
     class Package < Chef::Provider
       include Chef::Mixin::Command
       include Chef::Mixin::ShellOut
+      extend Chef::Mixin::SubclassDirective
+
+      # subclasses declare this if they want all their arguments as arrays of packages and names
+      subclass_directive :use_multipackage_api
+      # subclasses declare this if they want sources (filenames) pulled from their package names
+      subclass_directive :use_package_name_for_source
 
       #
       # Hook that subclasses use to populate the candidate_version(s)
@@ -43,6 +50,14 @@ class Chef
         true
       end
 
+      def check_resource_semantics!
+        # FIXME: this is not universally true and subclasses are needing to override this and no-ops it.  It should be turned into
+        # another "subclass_directive" and the apt and yum providers should declare that they need this behavior.
+        if new_resource.package_name.is_a?(Array) && new_resource.source != nil
+          raise Chef::Exceptions::InvalidResourceSpecification, "You may not specify both multipackage and source"
+        end
+      end
+
       def load_current_resource
       end
 
@@ -59,7 +74,7 @@ class Chef
         # not, but as with the above comment, we don't yet enforce such a thing,
         # so we'll just leave things as-is for now.
         requirements.assert(:upgrade, :install) do |a|
-          a.assertion  { candidates_exist_for_all_uninstalled? || new_resource.source }
+          a.assertion { candidates_exist_for_all_uninstalled? || new_resource.source }
           a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(", ")}")
           a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(", ")} would have been configured")
         end
@@ -80,11 +95,10 @@ class Chef
           end
         end
 
-        # XXX: mutating the new resource is generally bad
-        @new_resource.version(versions_for_new_resource)
-
         converge_by(install_description) do
-          install_package(package_names_for_targets, versions_for_targets)
+          multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
+            install_package(name, version)
+          end
           Chef::Log.info("#{@new_resource} installed #{package_names_for_targets} at #{versions_for_targets}")
         end
       end
@@ -107,18 +121,17 @@ class Chef
           return
         end
 
-        # XXX: mutating the new resource is generally bad
-        @new_resource.version(versions_for_new_resource)
-
         converge_by(upgrade_description) do
-          upgrade_package(package_names_for_targets, versions_for_targets)
-          log_allow_downgrade = allow_downgrade ? '(allow_downgrade)' : ''
+          multipackage_api_adapter(package_names_for_targets, versions_for_targets) do |name, version|
+            upgrade_package(name, version)
+          end
+          log_allow_downgrade = allow_downgrade ? "(allow_downgrade)" : ""
           Chef::Log.info("#{@new_resource} upgraded#{log_allow_downgrade} #{package_names_for_targets} to #{versions_for_targets}")
         end
       end
 
       def upgrade_description
-        log_allow_downgrade = allow_downgrade ? '(allow_downgrade)' : ''
+        log_allow_downgrade = allow_downgrade ? "(allow_downgrade)" : ""
         description = []
         target_version_array.each_with_index do |target_version, i|
           next if target_version.nil?
@@ -132,12 +145,13 @@ class Chef
 
       private :upgrade_description
 
-      # @todo: ability to remove an array of packages
       def action_remove
         if removing_package?
-          description = @new_resource.version ? "version #{@new_resource.version} of " :  ""
-          converge_by("remove #{description} package #{@current_resource.package_name}") do
-            remove_package(@current_resource.package_name, @new_resource.version)
+          description = @new_resource.version ? "version #{@new_resource.version} of " : ""
+          converge_by("remove #{description}package #{@current_resource.package_name}") do
+            multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
+              remove_package(name, version)
+            end
             Chef::Log.info("#{@new_resource} removed")
           end
         else
@@ -166,18 +180,18 @@ class Chef
         end
       end
 
-      # @todo: ability to purge an array of packages
       def action_purge
         if removing_package?
           description = @new_resource.version ? "version #{@new_resource.version} of" : ""
           converge_by("purge #{description} package #{@current_resource.package_name}") do
-            purge_package(@current_resource.package_name, @new_resource.version)
+            multipackage_api_adapter(@current_resource.package_name, @new_resource.version) do |name, version|
+              purge_package(name, version)
+            end
             Chef::Log.info("#{@new_resource} purged")
           end
         end
       end
 
-      # @todo: ability to reconfigure an array of packages
       def action_reconfig
         if @current_resource.version == nil then
           Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
@@ -192,7 +206,10 @@ class Chef
         if preseed_file = get_preseed_file(@new_resource.package_name, @current_resource.version)
           converge_by("reconfigure package #{@new_resource.package_name}") do
             preseed_package(preseed_file)
-            reconfig_package(@new_resource.package_name, @current_resource.version)
+            multipackage_api_adapter(@new_resource.package_name, @current_resource.version) do |name, version|
+              reconfig_package(name, version)
+
+            end
             Chef::Log.info("#{@new_resource} reconfigured")
           end
         else
@@ -201,31 +218,40 @@ class Chef
       end
 
       # @todo use composition rather than inheritance
+
+      def multipackage_api_adapter(name, version)
+        if use_multipackage_api?
+          yield [name].flatten, [version].flatten
+        else
+          yield name, version
+        end
+      end
+
       def install_package(name, version)
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :install"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :install"
       end
 
       def upgrade_package(name, version)
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :upgrade"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :upgrade"
       end
 
       def remove_package(name, version)
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remove"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :remove"
       end
 
       def purge_package(name, version)
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :purge"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :purge"
       end
 
       def preseed_package(file)
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support pre-seeding package install/upgrade instructions"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support pre-seeding package install/upgrade instructions"
       end
 
       def reconfig_package(name, version)
-        raise( Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reconfig" )
+        raise( Chef::Exceptions::UnsupportedAction, "#{self} does not support :reconfig" )
       end
 
-      # this is heavily used by subclasses
+      # used by subclasses.  deprecated.  use #a_to_s instead.
       def expand_options(options)
         options ? " #{options}" : ""
       end
@@ -316,18 +342,6 @@ class Chef
         multipackage? ? versions_for_targets : versions_for_targets[0]
       end
 
-      # We need to mutate @new_resource.version() for some reason and this is a helper so that we inject the right
-      # class (String or Array) into that attribute based on if we're handling an array of package names or not.
-      #
-      # @return [String, Array<String>] target_versions coerced into the correct type for back-compat
-      def versions_for_new_resource
-        if multipackage?
-          target_version_array
-        else
-          target_version_array[0]
-        end
-      end
-
       # Return an array indexed the same as *_version_array which contains either the target version to install/upgrade to
       # or else nil if the package is not being modified.
       #
@@ -464,10 +478,38 @@ class Chef
 
       # @return [Array] new_version(s) as an array
       def new_version_array
-        @new_version_array ||=
-            [ new_resource.version ].flatten.map do |v|
-              ( v.nil? || v.empty? ) ? nil : v
+        [ new_resource.version ].flatten.map { |v| v.to_s.empty? ? nil : v }
+      end
+
+      # TIP: less error prone to simply always call resolved_source_array, even if you
+      # don't think that you need to.
+      #
+      # @return [Array] new_resource.source as an array
+      def source_array
+        if new_resource.source.nil?
+          package_name_array.map { nil }
+        else
+          [ new_resource.source ].flatten
+        end
+      end
+
+      # Helper to handle use_package_name_for_source to convert names into local packages to install.
+      #
+      # @return [Array] Array of sources with package_names converted to sources
+      def resolved_source_array
+        @resolved_source_array ||=
+          begin
+            source_array.each_with_index.map do |source, i|
+              package_name = package_name_array[i]
+              # we require at least one '/' in the package_name to avoid [XXX_]package 'foo' breaking due to a random 'foo' file in cwd
+              if use_package_name_for_source? && source.nil? && package_name.match(/#{::File::SEPARATOR}/) && ::File.exist?(package_name)
+                Chef::Log.debug("No package source specified, but #{package_name} exists on filesystem, using #{package_name} as source.")
+                package_name
+              else
+                source
+              end
             end
+          end
       end
 
       # @todo: extract apt/dpkg specific preseeding to a helper class
@@ -487,6 +529,37 @@ class Chef
           false
         end
       end
+
+      def shell_out_with_timeout(*command_args)
+        shell_out(*add_timeout_option(command_args))
+      end
+
+      def shell_out_with_timeout!(*command_args)
+        shell_out!(*add_timeout_option(command_args))
+      end
+
+      def add_timeout_option(command_args)
+        args = command_args.dup
+        if args.last.is_a?(Hash)
+          options = args.pop.dup
+          options[:timeout] = new_resource.timeout if new_resource.timeout
+          options[:timeout] = 900 unless options.has_key?(:timeout)
+          args << options
+        else
+          args << { :timeout => new_resource.timeout ? new_resource.timeout : 900 }
+        end
+        args
+      end
+
+      # Helper for sublcasses to convert an array of string args into a string.  It
+      # will compact nil or empty strings in the array and will join the array elements
+      # with spaces, without introducing any double spaces for nil/empty elements.
+      #
+      # @param args [String] variable number of string arguments
+      # @return [String] nicely concatenated string or empty string
+      def a_to_s(*args)
+        args.reject { |i| i.nil? || i == "" }.join(" ")
+      end
     end
   end
 end
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
index 107f914..a1709c4 100644
--- a/lib/chef/provider/package/aix.rb
+++ b/lib/chef/provider/package/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Deepali Jagtap
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,17 @@
 # limitations under the License.
 #
 #
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
     class Package
       class Aix < Chef::Provider::Package
 
+        provides :package, os: "aix"
         provides :bff_package, os: "aix"
 
         include Chef::Mixin::GetSourceFromPackage
@@ -46,26 +47,26 @@ class Chef
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
-          @new_resource.version(nil)
 
           if @new_resource.source
             @package_source_found = ::File.exists?(@new_resource.source)
             if @package_source_found
               Chef::Log.debug("#{@new_resource} checking pkg status")
-              ret = shell_out("installp -L -d #{@new_resource.source}")
-              ret.stdout.each_line do | line |
+              ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}")
+              ret.stdout.each_line do |line|
                 case line
                 when /#{@new_resource.package_name}:/
                   fields = line.split(":")
                   @new_resource.version(fields[2])
                 end
               end
+              raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version
             end
           end
 
           Chef::Log.debug("#{@new_resource} checking install state")
-          ret = shell_out("lslpp -lcq #{@current_resource.package_name}")
-          ret.stdout.each_line do | line |
+          ret = shell_out_with_timeout("lslpp -lcq #{@current_resource.package_name}")
+          ret.stdout.each_line do |line|
             case line
             when /#{@current_resource.package_name}/
               fields = line.split(":")
@@ -83,8 +84,8 @@ class Chef
 
         def candidate_version
           return @candidate_version if @candidate_version
-          ret = shell_out("installp -L -d #{@new_resource.source}")
-          ret.stdout.each_line do | line |
+          ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}")
+          ret.stdout.each_line do |line|
             case line
             when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/
               fields = line.split(":")
@@ -109,10 +110,10 @@ class Chef
         def install_package(name, version)
           Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
           if @new_resource.options.nil?
-            shell_out!( "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}" )
+            shell_out_with_timeout!( "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}" )
             Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
           else
-            shell_out!( "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" )
+            shell_out_with_timeout!( "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" )
             Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
           end
         end
@@ -121,10 +122,10 @@ class Chef
 
         def remove_package(name, version)
           if @new_resource.options.nil?
-            shell_out!( "installp -u #{name}" )
+            shell_out_with_timeout!( "installp -u #{name}" )
             Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
           else
-            shell_out!( "installp -u #{expand_options(@new_resource.options)} #{name}" )
+            shell_out_with_timeout!( "installp -u #{expand_options(@new_resource.options)} #{name}" )
             Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
           end
         end
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index e426b51..ac73020 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
 
 class Chef
   class Provider
     class Package
       class Apt < Chef::Provider::Package
 
+        provides :package, platform_family: "debian"
         provides :apt_package, os: "linux"
 
         # return [Hash] mapping of package name to Boolean value
@@ -47,7 +48,7 @@ class Chef
 
           requirements.assert(:all_actions) do |a|
             a.assertion { !@new_resource.source }
-            a.failure_message(Chef::Exceptions::Package, 'apt package provider cannot handle source attribute. Use dpkg provider instead')
+            a.failure_message(Chef::Exceptions::Package, "apt package provider cannot handle source attribute. Use dpkg provider instead")
           end
         end
 
@@ -62,11 +63,11 @@ class Chef
           installed_version  = nil
           candidate_version  = nil
 
-          shell_out!("apt-cache#{expand_options(default_release_options)} policy #{pkg}", {:timeout=>900}).stdout.each_line do |line|
+          shell_out_with_timeout!("apt-cache#{expand_options(default_release_options)} policy #{pkg}").stdout.each_line do |line|
             case line
             when /^\s{2}Installed: (.+)$/
               installed_version = $1
-              if installed_version == '(none)'
+              if installed_version == "(none)"
                 Chef::Log.debug("#{@new_resource} current version is nil")
                 installed_version = nil
               else
@@ -75,10 +76,10 @@ class Chef
               end
             when /^\s{2}Candidate: (.+)$/
               candidate_version = $1
-              if candidate_version == '(none)'
+              if candidate_version == "(none)"
                 # This may not be an appropriate assumption, but it shouldn't break anything that already worked -- btm
                 is_virtual_package = true
-                showpkg = shell_out!("apt-cache showpkg #{pkg}", {:timeout => 900}).stdout
+                showpkg = shell_out_with_timeout!("apt-cache showpkg #{pkg}").stdout
                 providers = Hash.new
                 showpkg.rpartition(/Reverse Provides: ?#{$/}/)[2].each_line do |line|
                   provider, version = line.split
@@ -140,7 +141,7 @@ class Chef
           version_array = [ version ].flatten
           package_name = name_array.zip(version_array).map do |n, v|
             is_virtual_package[n] ? n : "#{n}=#{v}"
-          end.join(' ')
+          end.join(" ")
           run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}")
         end
 
@@ -149,12 +150,12 @@ class Chef
         end
 
         def remove_package(name, version)
-          package_name = [ name ].flatten.join(' ')
+          package_name = [ name ].flatten.join(" ")
           run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}")
         end
 
         def purge_package(name, version)
-          package_name = [ name ].flatten.join(' ')
+          package_name = [ name ].flatten.join(" ")
           run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{package_name}")
         end
 
@@ -164,7 +165,7 @@ class Chef
         end
 
         def reconfig_package(name, version)
-          package_name = [ name ].flatten.join(' ')
+          package_name = [ name ].flatten.join(" ")
           Chef::Log.info("#{@new_resource} reconfiguring")
           run_noninteractive("dpkg-reconfigure #{package_name}")
         end
@@ -175,7 +176,7 @@ class Chef
         # interactive prompts. Command is run with default localization rather
         # than forcing locale to "C", so command output may not be stable.
         def run_noninteractive(command)
-          shell_out!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, :timeout => @new_resource.timeout)
+          shell_out_with_timeout!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil })
         end
 
       end
diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb
new file mode 100644
index 0000000..14613b0
--- /dev/null
+++ b/lib/chef/provider/package/chocolatey.rb
@@ -0,0 +1,277 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/package"
+require "chef/resource/chocolatey_package"
+require "chef/mixin/powershell_out"
+
+class Chef
+  class Provider
+    class Package
+      class Chocolatey < Chef::Provider::Package
+        include Chef::Mixin::PowershellOut
+
+        provides :chocolatey_package, os: "windows"
+
+        # Declare that our arguments should be arrays
+        use_multipackage_api
+
+        PATHFINDING_POWERSHELL_COMMAND = "[System.Environment]::GetEnvironmentVariable('ChocolateyInstall', 'MACHINE')"
+        CHOCO_MISSING_MSG = <<-EOS
+Could not locate your Chocolatey install. To install chocolatey, we recommend
+the 'chocolatey' cookbook (https://github.com/chocolatey/chocolatey-cookbook).
+If Chocolatey is installed, ensure that the 'ChocolateyInstall' environment
+variable is correctly set. You can verify this with the PowerShell command
+'#{PATHFINDING_POWERSHELL_COMMAND}'.
+EOS
+
+        # Responsible for building the current_resource.
+        #
+        # @return [Chef::Resource::ChocolateyPackage] the current_resource
+        def load_current_resource
+          @current_resource = Chef::Resource::ChocolateyPackage.new(new_resource.name)
+          current_resource.package_name(new_resource.package_name)
+          current_resource.version(build_current_versions)
+          current_resource
+        end
+
+        def define_resource_requirements
+          super
+
+          requirements.assert(:all_actions) do |a|
+            # GetEnvironmentVariable returns "" on failure.
+            a.assertion { !choco_install_path.to_s.empty? }
+            a.failure_message(Chef::Exceptions::MissingLibrary, CHOCO_MISSING_MSG)
+            a.whyrun("Assuming Chocolatey is installed")
+          end
+
+          # Chocolatey source attribute points to an alternate feed
+          # and not a package specific alternate source like other providers
+          # so we want to assert candidates exist for the alternate source
+          requirements.assert(:upgrade, :install) do |a|
+            a.assertion { candidates_exist_for_all_uninstalled? }
+            a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{packages_missing_candidates.join(", ")}")
+            a.whyrun("Assuming a repository that offers #{packages_missing_candidates.join(", ")} would have been configured")
+          end
+        end
+
+        # Lazy initializer for candidate_version.  A nil value means that there is no candidate
+        # version and the package is not installable (generally an error).
+        #
+        # @return [Array] list of candidate_versions indexed same as new_resource.package_name/version
+        def candidate_version
+          @candidate_version ||= build_candidate_versions
+        end
+
+        # Install multiple packages via choco.exe
+        #
+        # @param names [Array<String>] array of package names to install
+        # @param versions [Array<String>] array of versions to install
+        def install_package(names, versions)
+          name_versions_to_install = desired_name_versions.select { |n, v| lowercase_names(names).include?(n) }
+
+          name_nil_versions = name_versions_to_install.select { |n, v| v.nil? }
+          name_has_versions = name_versions_to_install.reject { |n, v| v.nil? }
+
+          # choco does not support installing multiple packages with version pins
+          name_has_versions.each do |name, version|
+            choco_command("install -y -version", version, cmd_args, name)
+          end
+
+          # but we can do all the ones without version pins at once
+          unless name_nil_versions.empty?
+            cmd_names = name_nil_versions.keys
+            choco_command("install -y", cmd_args, *cmd_names)
+          end
+        end
+
+        # Upgrade multiple packages via choco.exe
+        #
+        # @param names [Array<String>] array of package names to install
+        # @param versions [Array<String>] array of versions to install
+        def upgrade_package(names, versions)
+          name_versions_to_install = desired_name_versions.select { |n, v| lowercase_names(names).include?(n) }
+
+          name_nil_versions = name_versions_to_install.select { |n, v| v.nil? }
+          name_has_versions = name_versions_to_install.reject { |n, v| v.nil? }
+
+          # choco does not support installing multiple packages with version pins
+          name_has_versions.each do |name, version|
+            choco_command("upgrade -y -version", version, cmd_args, name)
+          end
+
+          # but we can do all the ones without version pins at once
+          unless name_nil_versions.empty?
+            cmd_names = name_nil_versions.keys
+            choco_command("upgrade -y", cmd_args, *cmd_names)
+          end
+        end
+
+        # Remove multiple packages via choco.exe
+        #
+        # @param names [Array<String>] array of package names to install
+        # @param versions [Array<String>] array of versions to install
+        def remove_package(names, versions)
+          choco_command("uninstall -y", cmd_args, *names)
+        end
+
+        # Support :uninstall as an action in order for users to easily convert
+        # from the `chocolatey` provider in the cookbook.  It is, however,
+        # already deprecated.
+        def action_uninstall
+          Chef::Log.deprecation "The use of action :uninstall on the chocolatey_package provider is deprecated, please use :remove"
+          action_remove
+        end
+
+        # Choco does not have dpkg's distinction between purge and remove
+        alias_method :purge_package, :remove_package
+
+        # Override the superclass check.  The semantics for our new_resource.source is not files to
+        # install from, but like the rubygem provider's sources which are more like repos.
+        def check_resource_semantics!
+        end
+
+        private
+
+        # Magic to find where chocolatey is installed in the system, and to
+        # return the full path of choco.exe
+        #
+        # @return [String] full path of choco.exe
+        def choco_exe
+          @choco_exe ||= ::File.join(
+            choco_install_path,
+            "bin",
+            "choco.exe",
+            )
+        end
+
+        # lets us mock out an incorrect value for testing.
+        def choco_install_path
+          @choco_install_path ||= powershell_out!(
+            PATHFINDING_POWERSHELL_COMMAND
+            ).stdout.chomp
+        end
+
+        # Helper to dispatch a choco command through shell_out using the timeout
+        # set on the new resource, with nice command formatting.
+        #
+        # @param args [String] variable number of string arguments
+        # @return [Mixlib::ShellOut] object returned from shell_out!
+        def choco_command(*args)
+          shell_out_with_timeout!(args_to_string(choco_exe, *args))
+        end
+
+        # Use the available_packages Hash helper to create an array suitable for
+        # using in candidate_version
+        #
+        # @return [Array] list of candidate_version, same index as new_resource.package_name/version
+        def build_candidate_versions
+          new_resource.package_name.map do |package_name|
+            available_packages[package_name.downcase]
+          end
+        end
+
+        # Use the installed_packages Hash helper to create an array suitable for
+        # using in current_resource.version
+        #
+        # @return [Array] list of candidate_version, same index as new_resource.package_name/version
+        def build_current_versions
+          new_resource.package_name.map do |package_name|
+            installed_packages[package_name.downcase]
+          end
+        end
+
+        # Helper to construct Hash of names-to-versions, requested on the new_resource.
+        # If new_resource.version is nil, then all values will be nil.
+        #
+        # @return [Hash] Mapping of requested names to versions
+        def desired_name_versions
+          desired_versions = new_resource.version || new_resource.package_name.map { nil }
+          Hash[*lowercase_names(new_resource.package_name).zip(desired_versions).flatten]
+        end
+
+        # Helper to construct optional args out of new_resource
+        #
+        # @return [String] options from new_resource or empty string
+        def cmd_args
+          cmd_args = [ new_resource.options ]
+          cmd_args.push( "-source #{new_resource.source}" ) if new_resource.source
+          args_to_string(*cmd_args)
+        end
+
+        # Helper to nicely convert variable string args into a single command line.  It
+        # will compact nulls or empty strings and join arguments with single spaces, without
+        # introducing any double-spaces for missing args.
+        #
+        # @param args [String] variable number of string arguments
+        # @return [String] nicely concatenated string or empty string
+        def args_to_string(*args)
+          args.reject { |i| i.nil? || i == "" }.join(" ")
+        end
+
+        # Available packages in chocolatey as a Hash of names mapped to versions
+        # If pinning a package to a specific version, filter out all non matching versions
+        # (names are downcased for case-insensitive matching)
+        #
+        # @return [Hash] name-to-version mapping of available packages
+        def available_packages
+          @available_packages ||=
+            begin
+              cmd = [ "list -ar #{package_name_array.join ' '}" ]
+              cmd.push( "-source #{new_resource.source}" ) if new_resource.source
+              parse_list_output(*cmd).each_with_object({}) do |name_version, available|
+                name, version = name_version
+                if desired_name_versions[name].nil? || desired_name_versions[name] == version
+                  available[name] = version
+                end
+              end
+            end
+        end
+
+        # Installed packages in chocolatey as a Hash of names mapped to versions
+        # (names are downcased for case-insensitive matching)
+        #
+        # @return [Hash] name-to-version mapping of installed packages
+        def installed_packages
+          @installed_packages ||= Hash[*parse_list_output("list -l -r").flatten]
+        end
+
+        # Helper to convert choco.exe list output to a Hash
+        # (names are downcased for case-insenstive matching)
+        #
+        # @param cmd [String] command to run
+        # @return [Array] list output converted to ruby Hash
+        def parse_list_output(*args)
+          list = []
+          choco_command(*args).stdout.each_line do |line|
+            name, version = line.split("|")
+            list << [ name.downcase, version.chomp ]
+          end
+          list
+        end
+
+        # Helper to downcase all names in an array
+        #
+        # @param names [Array] original mixed case names
+        # @return [Array] same names in lower case
+        def lowercase_names(names)
+          names.map { |name| name.downcase }
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb
index 11691a2..a5a80e1 100644
--- a/lib/chef/provider/package/dpkg.rb
+++ b/lib/chef/provider/package/dpkg.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,131 +16,208 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/resource/package"
 
 class Chef
   class Provider
     class Package
       class Dpkg < Chef::Provider::Package
-        # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
-        DPKG_INFO = /([a-z\d\-\+\.]+)\t([\w\d.~:-]+)/
+        DPKG_REMOVED = /^Status: deinstall ok config-files/
         DPKG_INSTALLED = /^Status: install ok installed/
         DPKG_VERSION = /^Version: (.+)$/
 
         provides :dpkg_package, os: "linux"
 
-        include Chef::Mixin::GetSourceFromPackage
+        use_multipackage_api
+        use_package_name_for_source
 
         def define_resource_requirements
           super
-          requirements.assert(:install) do |a|
-            a.assertion{ not @new_resource.source.nil? }
-            a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
+
+          requirements.assert(:install, :upgrade) do |a|
+            a.assertion { !resolved_source_array.compact.empty? }
+            a.failure_message Chef::Exceptions::Package, "#{new_resource} the source property is required for action :install or :upgrade"
           end
 
-          # TODO this was originally written for any action in which .source is provided
-          # but would it make more sense to only look at source if the action is :install?
-          requirements.assert(:all_actions) do |a|
-            a.assertion { @source_exists }
-            a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
-            a.whyrun "Assuming it would have been previously downloaded."
+          requirements.assert(:install, :upgrade) do |a|
+            a.assertion { source_files_exist? }
+            a.failure_message Chef::Exceptions::Package, "#{new_resource} source file(s) do not exist: #{missing_sources}"
+            a.whyrun "Assuming they would have been previously created."
           end
         end
 
         def load_current_resource
-          @source_exists = true
-          @current_resource = Chef::Resource::Package.new(@new_resource.name)
-          @current_resource.package_name(@new_resource.package_name)
-          @new_resource.version(nil)
-
-          if @new_resource.source
-            @source_exists = ::File.exists?(@new_resource.source)
-            if @source_exists
-              # Get information from the package if supplied
-              Chef::Log.debug("#{@new_resource} checking dpkg status")
-
-              shell_out("dpkg-deb -W #{@new_resource.source}").stdout.each_line do |line|
-                if pkginfo = DPKG_INFO.match(line)
-                  @current_resource.package_name(pkginfo[1])
-                  @new_resource.version(pkginfo[2])
-                  @candidate_version = pkginfo[2]
-                end
-              end
-            else
-              # Source provided but not valid means we can't safely do further processing
-              return
-            end
-
+          @current_resource = Chef::Resource::Package.new(new_resource.name)
+          current_resource.package_name(new_resource.package_name)
+
+          if source_files_exist?
+            @candidate_version = get_candidate_version
+            current_resource.package_name(get_package_name)
+            # if the source file exists then our package_name is right
+            current_resource.version(get_current_version_from(current_package_name_array))
+          elsif !installing?
+            # we can't do this if we're installing with no source, because our package_name
+            # is probably not right.
+            #
+            # if we're removing or purging we don't use source, and our package_name must
+            # be right so we can do this.
+            #
+            # we don't error here on the dpkg command since we'll handle the exception or
+            # the why-run message in define_resource_requirements.
+            current_resource.version(get_current_version_from(current_package_name_array))
           end
 
-          # Check to see if it is installed
-          package_installed = nil
-          Chef::Log.debug("#{@new_resource} checking install state")
-          status = shell_out("dpkg -s #{@current_resource.package_name}")
+          current_resource
+        end
+
+        def install_package(name, version)
+          sources = name.map { |n| name_sources[n] }
+          Chef::Log.info("#{new_resource} installing package(s): #{name.join(' ')}")
+          run_noninteractive("dpkg -i", new_resource.options, *sources)
+        end
+
+        def remove_package(name, version)
+          Chef::Log.info("#{new_resource} removing package(s): #{name.join(' ')}")
+          run_noninteractive("dpkg -r", new_resource.options, *name)
+        end
+
+        def purge_package(name, version)
+          Chef::Log.info("#{new_resource} purging packages(s): #{name.join(' ')}")
+          run_noninteractive("dpkg -P", new_resource.options, *name)
+        end
+
+        def upgrade_package(name, version)
+          install_package(name, version)
+        end
+
+        def preseed_package(preseed_file)
+          Chef::Log.info("#{new_resource} pre-seeding package installation instructions")
+          run_noninteractive("debconf-set-selections", *preseed_file)
+        end
+
+        def reconfig_package(name, version)
+          Chef::Log.info("#{new_resource} reconfiguring")
+          run_noninteractive("dpkg-reconfigure", *name)
+        end
+
+        # Override the superclass check.  Multiple sources are required here.
+        def check_resource_semantics!
+        end
+
+        private
+
+        def read_current_version_of_package(package_name)
+          Chef::Log.debug("#{new_resource} checking install state of #{package_name}")
+          status = shell_out_with_timeout!("dpkg -s #{package_name}", returns: [0, 1])
+          package_installed = false
           status.stdout.each_line do |line|
             case line
+            when DPKG_REMOVED
+              # if we are 'purging' then we consider 'removed' to be 'installed'
+              package_installed = true if action == :purge
             when DPKG_INSTALLED
               package_installed = true
             when DPKG_VERSION
               if package_installed
-                Chef::Log.debug("#{@new_resource} current version is #{$1}")
-                @current_resource.version($1)
+                Chef::Log.debug("#{new_resource} current version is #{$1}")
+                return $1
               end
             end
           end
+          return nil
+        end
 
-          unless status.exitstatus == 0 || status.exitstatus == 1
-            raise Chef::Exceptions::Package, "dpkg failed - #{status.inspect}!"
+        def get_current_version_from(array)
+          array.map do |name|
+            read_current_version_of_package(name)
           end
+        end
 
-          @current_resource
+        # Runs command via shell_out_with_timeout with magic environment to disable
+        # interactive prompts.
+        def run_noninteractive(*command)
+          shell_out_with_timeout!(a_to_s(*command), :env => { "DEBIAN_FRONTEND" => "noninteractive" })
         end
 
-        def install_package(name, version)
-          Chef::Log.info("#{@new_resource} installing #{@new_resource.source}")
-          run_noninteractive(
-            "dpkg -i#{expand_options(@new_resource.options)} #{@new_resource.source}"
-          )
+        # Returns true if all sources exist.  Returns false if any do not, or if no
+        # sources were specified.
+        #
+        # @return [Boolean] True if all sources exist
+        def source_files_exist?
+          resolved_source_array.all? { |s| s && ::File.exist?(s) }
         end
 
-        def remove_package(name, version)
-          Chef::Log.info("#{@new_resource} removing #{@new_resource.package_name}")
-          run_noninteractive(
-            "dpkg -r#{expand_options(@new_resource.options)} #{@new_resource.package_name}"
-          )
+        # Helper to return all the nanes of the missing sources for error messages.
+        #
+        # @return [Array<String>] Array of missing sources
+        def missing_sources
+          resolved_source_array.select { |s| s.nil? || !::File.exist?(s) }
         end
 
-        def purge_package(name, version)
-          Chef::Log.info("#{@new_resource} purging #{@new_resource.package_name}")
-          run_noninteractive(
-            "dpkg -P#{expand_options(@new_resource.options)} #{@new_resource.package_name}"
-          )
+        def current_package_name_array
+          [ current_resource.package_name ].flatten
         end
 
-        def upgrade_package(name, version)
-          install_package(name, version)
+        # Helper to construct Hash of names-to-sources.
+        #
+        # @return [Hash] Mapping of package names to sources
+        def name_sources
+          @name_sources =
+            begin
+              Hash[*package_name_array.zip(resolved_source_array).flatten]
+            end
         end
 
-        def preseed_package(preseed_file)
-          Chef::Log.info("#{@new_resource} pre-seeding package installation instructions")
-          run_noninteractive("debconf-set-selections #{preseed_file}")
+        # Helper to construct Hash of names-to-package-information.
+        #
+        # @return [Hash] Mapping of package names to package information
+        def name_pkginfo
+          @name_pkginfo ||=
+            begin
+              pkginfos = resolved_source_array.map do |src|
+                Chef::Log.debug("#{new_resource} checking #{src} dpkg status")
+                status = shell_out_with_timeout!("dpkg-deb -W #{src}")
+                status.stdout
+              end
+              Hash[*package_name_array.zip(pkginfos).flatten]
+            end
         end
 
-        def reconfig_package(name, version)
-          Chef::Log.info("#{@new_resource} reconfiguring")
-          run_noninteractive("dpkg-reconfigure #{name}")
+        def name_candidate_version
+          @name_candidate_version ||=
+            begin
+              Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[1].strip : nil] }]
+            end
+        end
+
+        def name_package_name
+          @name_package_name ||=
+            begin
+              Hash[name_pkginfo.map { |k, v| [k, v ? v.split("\t")[0] : nil] }]
+            end
+        end
+
+        # Return candidate version array from pkg-deb -W against the source file(s).
+        #
+        # @return [Array] Array of candidate versions read from the source files
+        def get_candidate_version
+          package_name_array.map { |name| name_candidate_version[name] }
+        end
+
+        # Return package names from the candidate source file(s).
+        #
+        # @return [Array] Array of actual package names read from the source files
+        def get_package_name
+          package_name_array.map { |name| name_package_name[name] }
         end
 
-        # Runs command via shell_out with magic environment to disable
-        # interactive prompts. Command is run with default localization rather
-        # than forcing locale to "C", so command output may not be stable.
+        # Since upgrade just calls install, this is a helper to determine
+        # if our action means that we'll be calling install_package.
         #
-        # FIXME: This should be "LC_ALL" => "en_US.UTF-8" in order to stabilize the output and get UTF-8
-        def run_noninteractive(command)
-          shell_out!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil })
+        # @return [Boolean] true if we're doing :install or :upgrade
+        def installing?
+          [:install, :upgrade].include?(action)
         end
 
       end
diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb
index 90727b7..a876258 100644
--- a/lib/chef/provider/package/easy_install.rb
+++ b/lib/chef/provider/package/easy_install.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
 
 class Chef
   class Provider
@@ -32,10 +32,10 @@ class Chef
 
           begin
             # first check to see if we can import it
-            output = shell_out!("#{python_binary_path} -c \"import #{name}\"", :returns=>[0,1]).stderr
+            output = shell_out_with_timeout!("#{python_binary_path} -c \"import #{name}\"", :returns => [0, 1]).stderr
             if output.include? "ImportError"
               # then check to see if its on the path
-              output = shell_out!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout
+              output = shell_out_with_timeout!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns => [0, 1]).stdout
               if output.downcase.include? "#{name.downcase}"
                 check = true
               end
@@ -51,12 +51,12 @@ class Chef
 
         def easy_install_binary_path
           path = @new_resource.easy_install_binary
-          path ? path : 'easy_install'
+          path ? path : "easy_install"
         end
 
         def python_binary_path
           path = @new_resource.python_binary
-          path ? path : 'python'
+          path ? path : "python"
         end
 
         def module_name
@@ -67,18 +67,17 @@ class Chef
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
-          @current_resource.version(nil)
 
           # get the currently installed version if installed
           package_version = nil
           if install_check(module_name)
             begin
-              output = shell_out!("#{python_binary_path} -c \"import #{module_name}; print #{module_name}.__version__\"").stdout
+              output = shell_out_with_timeout!("#{python_binary_path} -c \"import #{module_name}; print #{module_name}.__version__\"").stdout
               package_version = output.strip
             rescue
-              output = shell_out!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout
+              output = shell_out_with_timeout!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns => [0, 1]).stdout
 
-              output_array = output.gsub(/[\[\]]/,'').split(/\s*,\s*/)
+              output_array = output.gsub(/[\[\]]/, "").split(/\s*,\s*/)
               package_path = ""
 
               output_array.each do |entry|
@@ -104,12 +103,12 @@ class Chef
         end
 
         def candidate_version
-           return @candidate_version if @candidate_version
+          return @candidate_version if @candidate_version
 
            # do a dry run to get the latest version
-           result = shell_out!("#{easy_install_binary_path} -n #{@new_resource.package_name}", :returns=>[0,1])
-           @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3]
-           @candidate_version
+          result = shell_out_with_timeout!("#{easy_install_binary_path} -n #{@new_resource.package_name}", :returns => [0, 1])
+          @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3]
+          @candidate_version
         end
 
         def install_package(name, version)
diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb
index 6a3b97a..7104a71 100644
--- a/lib/chef/provider/package/freebsd/base.rb
+++ b/lib/chef/provider/package/freebsd/base.rb
@@ -2,8 +2,8 @@
 # Authors:: Bryan McLellan (btm at loftninjas.org)
 #           Matthew Landauer (matthew at openaustralia.org)
 #           Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/resource/package"
+require "chef/provider/package"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
@@ -47,7 +47,7 @@ class Chef
 
             # Otherwise look up the path to the ports directory using 'whereis'
             else
-              whereis = shell_out!("whereis -s #{port}", :env => nil)
+              whereis = shell_out_with_timeout!("whereis -s #{port}", :env => nil)
               unless path = whereis.stdout[/^#{Regexp.escape(port)}:\s+(.+)$/, 1]
                 raise Chef::Exceptions::Package, "Could not find port with the name #{port}"
               end
@@ -57,8 +57,8 @@ class Chef
 
           def makefile_variable_value(variable, dir = nil)
             options = dir ? { :cwd => dir } : {}
-            make_v = shell_out!("make -V #{variable}", options.merge!(:env => nil, :returns => [0,1]))
-            make_v.exitstatus.zero? ? make_v.stdout.strip.split($\).first : nil   # $\ is the line separator, i.e. newline.
+            make_v = shell_out_with_timeout!("make -V #{variable}", options.merge!(:env => nil, :returns => [0, 1]))
+            make_v.exitstatus.zero? ? make_v.stdout.strip.split($\).first : nil # $\ is the line separator, i.e. newline.
           end
         end
 
diff --git a/lib/chef/provider/package/freebsd/pkg.rb b/lib/chef/provider/package/freebsd/pkg.rb
index ebbfbb1..b42bd62 100644
--- a/lib/chef/provider/package/freebsd/pkg.rb
+++ b/lib/chef/provider/package/freebsd/pkg.rb
@@ -2,8 +2,8 @@
 # Authors:: Bryan McLellan (btm at loftninjas.org)
 #           Matthew Landauer (matthew at openaustralia.org)
 #           Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package/freebsd/base'
-require 'chef/util/path_helper'
+require "chef/provider/package/freebsd/base"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
@@ -34,24 +34,24 @@ class Chef
               case @new_resource.source
               when /^http/, /^ftp/
                 if @new_resource.source =~ /\/$/
-                  shell_out!("pkg_add -r #{package_name}", :env => { "PACKAGESITE" => @new_resource.source, 'LC_ALL' => nil }).status
+                  shell_out_with_timeout!("pkg_add -r #{package_name}", :env => { "PACKAGESITE" => @new_resource.source, "LC_ALL" => nil }).status
                 else
-                  shell_out!("pkg_add -r #{package_name}", :env => { "PACKAGEROOT" => @new_resource.source, 'LC_ALL' => nil }).status
+                  shell_out_with_timeout!("pkg_add -r #{package_name}", :env => { "PACKAGEROOT" => @new_resource.source, "LC_ALL" => nil }).status
                 end
                 Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
 
               when /^\//
-                shell_out!("pkg_add #{file_candidate_version_path}", :env => { "PKG_PATH" => @new_resource.source , 'LC_ALL'=>nil}).status
+                shell_out_with_timeout!("pkg_add #{file_candidate_version_path}", :env => { "PKG_PATH" => @new_resource.source , "LC_ALL" => nil }).status
                 Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
 
               else
-                shell_out!("pkg_add -r #{latest_link_name}", :env => nil).status
+                shell_out_with_timeout!("pkg_add -r #{latest_link_name}", :env => nil).status
               end
             end
           end
 
           def remove_package(name, version)
-            shell_out!("pkg_delete #{package_name}-#{version || @current_resource.version}", :env => nil).status
+            shell_out_with_timeout!("pkg_delete #{package_name}-#{version || @current_resource.version}", :env => nil).status
           end
 
           # The name of the package (without the version number) as understood by pkg_add and pkg_info.
@@ -72,7 +72,7 @@ class Chef
           end
 
           def current_installed_version
-            pkg_info = shell_out!("pkg_info -E \"#{package_name}*\"", :env => nil, :returns => [0,1])
+            pkg_info = shell_out_with_timeout!("pkg_info -E \"#{package_name}*\"", :env => nil, :returns => [0, 1])
             pkg_info.stdout[/^#{Regexp.escape(package_name)}-(.+)/, 1]
           end
 
diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb
index bfe6dca..de7bea6 100644
--- a/lib/chef/provider/package/freebsd/pkgng.rb
+++ b/lib/chef/provider/package/freebsd/pkgng.rb
@@ -1,6 +1,6 @@
 #
 # Authors:: Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package/freebsd/base'
+require "chef/provider/package/freebsd/base"
 
 class Chef
   class Provider
@@ -28,23 +28,23 @@ class Chef
             unless @current_resource.version
               case @new_resource.source
               when /^(http|ftp|\/)/
-                shell_out!("pkg add#{expand_options(@new_resource.options)} #{@new_resource.source}", :env => { 'LC_ALL' => nil }).status
+                shell_out_with_timeout!("pkg add#{expand_options(@new_resource.options)} #{@new_resource.source}", :env => { "LC_ALL" => nil }).status
                 Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}")
 
               else
-                shell_out!("pkg install -y#{expand_options(@new_resource.options)} #{name}", :env => { 'LC_ALL' => nil }).status
+                shell_out_with_timeout!("pkg install -y#{expand_options(@new_resource.options)} #{name}", :env => { "LC_ALL" => nil }).status
               end
             end
           end
 
           def remove_package(name, version)
-            options = @new_resource.options && @new_resource.options.sub(repo_regex, '')
+            options = @new_resource.options && @new_resource.options.sub(repo_regex, "")
             options && !options.empty? || options = nil
-            shell_out!("pkg delete -y#{expand_options(options)} #{name}#{version ? '-' + version : ''}", :env => nil).status
+            shell_out_with_timeout!("pkg delete -y#{expand_options(options)} #{name}#{version ? '-' + version : ''}", :env => nil).status
           end
 
           def current_installed_version
-            pkg_info = shell_out!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0,70])
+            pkg_info = shell_out_with_timeout!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0, 70])
             pkg_info.stdout[/^Version +: (.+)$/, 1]
           end
 
@@ -63,7 +63,7 @@ class Chef
               options = $1
             end
 
-            pkg_query = shell_out!("pkg rquery#{expand_options(options)} '%v' #{@new_resource.package_name}", :env => nil)
+            pkg_query = shell_out_with_timeout!("pkg rquery#{expand_options(options)} '%v' #{@new_resource.package_name}", :env => nil)
             pkg_query.exitstatus.zero? ? pkg_query.stdout.strip.split(/\n/).last : nil
           end
 
diff --git a/lib/chef/provider/package/freebsd/port.rb b/lib/chef/provider/package/freebsd/port.rb
index 8b19117..3eb3c5a 100644
--- a/lib/chef/provider/package/freebsd/port.rb
+++ b/lib/chef/provider/package/freebsd/port.rb
@@ -1,6 +1,6 @@
 #
 # Authors:: Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package/freebsd/base'
+require "chef/provider/package/freebsd/base"
 
 class Chef
   class Provider
@@ -26,18 +26,18 @@ class Chef
           include PortsHelper
 
           def install_package(name, version)
-            shell_out!("make -DBATCH install clean", :timeout => 1800, :env => nil, :cwd => port_dir).status
+            shell_out_with_timeout!("make -DBATCH install clean", :timeout => 1800, :env => nil, :cwd => port_dir).status
           end
 
           def remove_package(name, version)
-            shell_out!("make deinstall", :timeout => 300, :env => nil, :cwd => port_dir).status
+            shell_out_with_timeout!("make deinstall", :timeout => 300, :env => nil, :cwd => port_dir).status
           end
 
           def current_installed_version
             pkg_info = if @new_resource.supports_pkgng?
-                         shell_out!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0,70])
+                         shell_out_with_timeout!("pkg info \"#{@new_resource.package_name}\"", :env => nil, :returns => [0, 70])
                        else
-                         shell_out!("pkg_info -E \"#{@new_resource.package_name}*\"", :env => nil, :returns => [0,1])
+                         shell_out_with_timeout!("pkg_info -E \"#{@new_resource.package_name}*\"", :env => nil, :returns => [0, 1])
                        end
             pkg_info.stdout[/^#{Regexp.escape(@new_resource.package_name)}-(.+)/, 1]
           end
diff --git a/lib/chef/provider/package/homebrew.rb b/lib/chef/provider/package/homebrew.rb
index 6038996..c032881 100644
--- a/lib/chef/provider/package/homebrew.rb
+++ b/lib/chef/provider/package/homebrew.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
+# Author:: Joshua Timberman (<joshua at chef.io>)
 # Author:: Graeme Mathieson (<mathie at woss.name>)
 #
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal at getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,16 +18,16 @@
 # limitations under the License.
 #
 
-require 'etc'
-require 'chef/mixin/homebrew_user'
+require "etc"
+require "chef/mixin/homebrew_user"
 
 class Chef
   class Provider
     class Package
       class Homebrew < Chef::Provider::Package
 
+        provides :package, os: "darwin", override: true
         provides :homebrew_package
-        provides :package, os: "darwin"
 
         include Chef::Mixin::HomebrewUser
 
@@ -46,7 +46,7 @@ class Chef
 
         def install_package(name, version)
           unless current_resource.version == version
-            brew('install', new_resource.options, name)
+            brew("install", new_resource.options, name)
           end
         end
 
@@ -56,19 +56,19 @@ class Chef
           if current_version.nil? or current_version.empty?
             install_package(name, version)
           elsif current_version != version
-            brew('upgrade', new_resource.options, name)
+            brew("upgrade", new_resource.options, name)
           end
         end
 
         def remove_package(name, version)
           if current_resource.version
-            brew('uninstall', new_resource.options, name)
+            brew("uninstall", new_resource.options, name)
           end
         end
 
         # Homebrew doesn't really have a notion of purging, do a "force remove"
         def purge_package(name, version)
-          new_resource.options((new_resource.options || '') << ' --force').strip
+          new_resource.options((new_resource.options || "") << " --force").strip
           remove_package(name, version)
         end
 
@@ -85,7 +85,7 @@ class Chef
         #
         # https://github.com/Homebrew/homebrew/wiki/Querying-Brew
         def brew_info
-          @brew_info ||= Chef::JSONCompat.from_json(brew('info', '--json=v1', new_resource.package_name)).first
+          @brew_info ||= Chef::JSONCompat.from_json(brew("info", "--json=v1", new_resource.package_name)).first
         end
 
         # Some packages (formula) are "keg only" and aren't linked,
@@ -95,14 +95,14 @@ class Chef
         # that brew thinks is linked as the current version.
         #
         def current_installed_version
-          if brew_info['keg_only']
-            if brew_info['installed'].empty?
+          if brew_info["keg_only"]
+            if brew_info["installed"].empty?
               nil
             else
-              brew_info['installed'].last['version']
+              brew_info["installed"].last["version"]
             end
           else
-            brew_info['linked_keg']
+            brew_info["linked_keg"]
           end
         end
 
@@ -116,7 +116,7 @@ class Chef
         #
         # https://github.com/Homebrew/homebrew/wiki/Acceptable-Formulae#stable-versions
         def candidate_version
-          brew_info['versions']['stable']
+          brew_info["versions"]["stable"]
         end
 
         private
@@ -126,7 +126,8 @@ class Chef
           homebrew_user = Etc.getpwuid(homebrew_uid)
 
           Chef::Log.debug "Executing '#{command}' as user '#{homebrew_user.name}'"
-          output = shell_out!(command, :timeout => 1800, :user => homebrew_uid, :environment => { 'HOME' => homebrew_user.dir, 'RUBYOPT' => nil })
+          # FIXME: this 1800 second default timeout should be deprecated
+          output = shell_out_with_timeout!(command, :timeout => 1800, :user => homebrew_uid, :environment => { "HOME" => homebrew_user.dir, "RUBYOPT" => nil })
           output.stdout.chomp
         end
 
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 87022d7..dc83e4a 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jason J. W. Williams (<williamsjj at digitar.com>)
-# Author:: Stephen Nelson-Smith (<sns at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Stephen Nelson-Smith (<sns at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,16 +17,17 @@
 # limitations under the License.
 #
 
-require 'open3'
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "open3"
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
 
 class Chef
   class Provider
     class Package
       class Ips < Chef::Provider::Package
 
+        provides :package, platform: %w{openindiana opensolaris omnios solaris2}
         provides :ips_package, os: "solaris2"
 
         attr_accessor :virtual
@@ -42,14 +43,14 @@ class Chef
         end
 
         def get_current_version
-          shell_out("pkg info #{@new_resource.package_name}").stdout.each_line do |line|
+          shell_out_with_timeout("pkg info #{@new_resource.package_name}").stdout.each_line do |line|
             return $1.split[0] if line =~ /^\s+Version: (.*)/
           end
           return nil
         end
 
         def get_candidate_version
-          shell_out!("pkg info -r #{new_resource.package_name}").stdout.each_line do |line|
+          shell_out_with_timeout!("pkg info -r #{new_resource.package_name}").stdout.each_line do |line|
             return $1.split[0] if line =~ /Version: (.*)/
           end
           return nil
@@ -69,11 +70,11 @@ class Chef
           normal_command = "pkg#{expand_options(@new_resource.options)} install -q #{package_name}"
           command =
             if @new_resource.respond_to?(:accept_license) and @new_resource.accept_license
-              normal_command.gsub('-q', '-q --accept')
+              normal_command.gsub("-q", "-q --accept")
             else
               normal_command
             end
-          shell_out(command)
+          shell_out_with_timeout(command)
         end
 
         def upgrade_package(name, version)
@@ -82,7 +83,7 @@ class Chef
 
         def remove_package(name, version)
           package_name = "#{name}@#{version}"
-          shell_out!( "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}" )
+          shell_out_with_timeout!( "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}" )
         end
       end
     end
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index b252344..b110207 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -3,8 +3,8 @@ class Chef
     class Package
       class Macports < Chef::Provider::Package
 
-        provides :macports_package
         provides :package, os: "darwin"
+        provides :macports_package
 
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
@@ -49,21 +49,21 @@ class Chef
           unless @current_resource.version == version
             command = "port#{expand_options(@new_resource.options)} install #{name}"
             command << " @#{version}" if version and !version.empty?
-            shell_out!(command)
+            shell_out_with_timeout!(command)
           end
         end
 
         def purge_package(name, version)
           command = "port#{expand_options(@new_resource.options)} uninstall #{name}"
           command << " @#{version}" if version and !version.empty?
-          shell_out!(command)
+          shell_out_with_timeout!(command)
         end
 
         def remove_package(name, version)
           command = "port#{expand_options(@new_resource.options)} deactivate #{name}"
           command << " @#{version}" if version and !version.empty?
 
-          shell_out!(command)
+          shell_out_with_timeout!(command)
         end
 
         def upgrade_package(name, version)
@@ -76,14 +76,15 @@ class Chef
             # that hasn't been installed.
             install_package(name, version)
           elsif current_version != version
-            shell_out!( "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}" )
+            shell_out_with_timeout!( "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}" )
           end
         end
 
         private
+
         def get_response_from_command(command)
           output = nil
-          status = shell_out(command)
+          status = shell_out_with_timeout(command)
           begin
             output = status.stdout
           rescue Exception
diff --git a/lib/chef/provider/package/openbsd.rb b/lib/chef/provider/package/openbsd.rb
index 82048c3..2120b9a 100644
--- a/lib/chef/provider/package/openbsd.rb
+++ b/lib/chef/provider/package/openbsd.rb
@@ -3,8 +3,8 @@
 #           Matthew Landauer (matthew at openaustralia.org)
 #           Richard Manyanza (liseki at nyikacraftsmen.com)
 #           Scott Bonds (scott at ggr.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,11 +20,10 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/get_source_from_package'
-require 'chef/exceptions'
+require "chef/resource/package"
+require "chef/provider/package"
+require "chef/mixin/get_source_from_package"
+require "chef/exceptions"
 
 class Chef
   class Provider
@@ -32,6 +31,7 @@ class Chef
       class Openbsd < Chef::Provider::Package
 
         provides :package, os: "openbsd"
+        provides :openbsd_package
 
         include Chef::Mixin::ShellOut
         include Chef::Mixin::GetSourceFromPackage
@@ -53,7 +53,7 @@ class Chef
           # Below are incomplete/missing features for this package provider
           requirements.assert(:all_actions) do |a|
             a.assertion { !new_resource.source }
-            a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support the source attribute')
+            a.failure_message(Chef::Exceptions::Package, "The openbsd package provider does not support the source attribute")
           end
           requirements.assert(:all_actions) do |a|
             a.assertion do
@@ -63,7 +63,7 @@ class Chef
                 true
               end
             end
-            a.failure_message(Chef::Exceptions::Package, 'The openbsd package provider does not support providing a version and flavor')
+            a.failure_message(Chef::Exceptions::Package, "The openbsd package provider does not support providing a version and flavor")
           end
         end
 
@@ -72,18 +72,16 @@ class Chef
             if parts = name.match(/^(.+?)--(.+)/) # use double-dash for stems with flavors, see man page for pkg_add
               name = parts[1]
             end
-            shell_out!("pkg_add -r #{name}#{version_string}", :env => {"PKG_PATH" => pkg_path}).status
+            shell_out_with_timeout!("pkg_add -r #{name}#{version_string(version)}", :env => { "PKG_PATH" => pkg_path }).status
             Chef::Log.debug("#{new_resource.package_name} installed")
           end
         end
 
         def remove_package(name, version)
-          version_string  = ''
-          version_string += "-#{version}" if version
           if parts = name.match(/^(.+?)--(.+)/)
             name = parts[1]
           end
-          shell_out!("pkg_delete #{name}#{version_string}", :env => nil).status
+          shell_out_with_timeout!("pkg_delete #{name}#{version_string(version)}", :env => nil).status
         end
 
         private
@@ -94,7 +92,7 @@ class Chef
           else
             name = new_resource.package_name
           end
-          pkg_info = shell_out!("pkg_info -e \"#{name}->0\"", :env => nil, :returns => [0,1])
+          pkg_info = shell_out_with_timeout!("pkg_info -e \"#{name}->0\"", :env => nil, :returns => [0, 1])
           result = pkg_info.stdout[/^inst:#{Regexp.escape(name)}-(.+?)\s/, 1]
           Chef::Log.debug("installed_version of '#{new_resource.package_name}' is '#{result}'")
           result
@@ -103,7 +101,7 @@ class Chef
         def candidate_version
           @candidate_version ||= begin
             results = []
-            shell_out!("pkg_info -I \"#{new_resource.package_name}#{version_string}\"", :env => nil, :returns => [0,1]).stdout.each_line do |line|
+            shell_out_with_timeout!("pkg_info -I \"#{new_resource.package_name}#{version_string(new_resource.version)}\"", :env => nil, :returns => [0, 1]).stdout.each_line do |line|
               if parts = new_resource.package_name.match(/^(.+?)--(.+)/)
                 results << line[/^#{Regexp.escape(parts[1])}-(.+?)\s/, 1]
               else
@@ -111,7 +109,7 @@ class Chef
               end
             end
             results = results.reject(&:nil?)
-            Chef::Log.debug("candidate versions of '#{new_resource.package_name}' are '#{results}'")
+            Chef::Log.debug("Candidate versions of '#{new_resource.package_name}' are '#{results}'")
             case results.length
             when 0
               []
@@ -123,13 +121,13 @@ class Chef
           end
         end
 
-        def version_string
-          ver  = ''
-          ver += "-#{new_resource.version}" if new_resource.version
+        def version_string(version)
+          ver  = ""
+          ver += "-#{version}" if version
         end
 
         def pkg_path
-          ENV['PKG_PATH'] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/"
+          ENV["PKG_PATH"] || "http://ftp.OpenBSD.org/pub/#{node.kernel.name}/#{node.kernel.release}/packages/#{node.kernel.machine}/"
         end
 
       end
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index f16fc81..22fa9c2 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,24 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
 
 class Chef
   class Provider
     class Package
       class Pacman < Chef::Provider::Package
 
+        provides :package, platform: "arch"
         provides :pacman_package, os: "linux"
 
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
 
-          @current_resource.version(nil)
-
           Chef::Log.debug("#{@new_resource} checking pacman for #{@new_resource.package_name}")
-          status = shell_out("pacman -Qi #{@new_resource.package_name}")
+          status = shell_out_with_timeout("pacman -Qi #{@new_resource.package_name}")
           status.stdout.each_line do |line|
             case line
             when /^Version(\s?)*: (.+)$/
@@ -53,16 +52,16 @@ class Chef
         def candidate_version
           return @candidate_version if @candidate_version
 
-          repos = ["extra","core","community"]
+          repos = ["extra", "core", "community"]
 
           if(::File.exists?("/etc/pacman.conf"))
             pacman = ::File.read("/etc/pacman.conf")
             repos = pacman.scan(/\[(.+)\]/).flatten
           end
 
-          package_repos = repos.map {|r| Regexp.escape(r) }.join('|')
+          package_repos = repos.map { |r| Regexp.escape(r) }.join("|")
 
-          status = shell_out("pacman -Sl")
+          status = shell_out_with_timeout("pacman -Sl")
           status.stdout.each_line do |line|
             case line
               when /^(#{package_repos}) #{Regexp.escape(@new_resource.package_name)} (.+)$/
@@ -81,11 +80,10 @@ class Chef
           end
 
           @candidate_version
-
         end
 
         def install_package(name, version)
-          shell_out!( "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
+          shell_out_with_timeout!( "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
         end
 
         def upgrade_package(name, version)
@@ -93,7 +91,7 @@ class Chef
         end
 
         def remove_package(name, version)
-          shell_out!( "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
+          shell_out_with_timeout!( "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" )
         end
 
         def purge_package(name, version)
diff --git a/lib/chef/provider/package/paludis.rb b/lib/chef/provider/package/paludis.rb
index 407e0d0..e1b2ea1 100644
--- a/lib/chef/provider/package/paludis.rb
+++ b/lib/chef/provider/package/paludis.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Vasiliy Tolstov (<v.tolstov at selfip.ru>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,38 +16,36 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/resource/package"
 
 class Chef
   class Provider
     class Package
       class Paludis < Chef::Provider::Package
 
+        provides :package, platform: "exherbo"
         provides :paludis_package, os: "linux"
 
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.package_name)
           @current_resource.package_name(@new_resource.package_name)
 
-          @current_resource.version(nil)
-
           Chef::Log.debug("Checking package status for #{@new_resource.package_name}")
           installed = false
-          re = Regexp.new('(.*)[[:blank:]](.*)[[:blank:]](.*)$')
+          re = Regexp.new("(.*)[[:blank:]](.*)[[:blank:]](.*)$")
 
           shell_out!("cave -L warning print-ids -M none -m \"#{@new_resource.package_name}\" -f \"%c/%p %v %r\n\"").stdout.each_line do |line|
             res = re.match(line)
             unless res.nil?
               case res[3]
-              when 'accounts', 'installed-accounts'
+              when "accounts", "installed-accounts"
                 next
-              when 'installed'
+              when "installed"
                 installed = true
                 @current_resource.version(res[2])
               else
                 @candidate_version = res[2]
-                @current_resource.version(nil)
               end
             end
           end
@@ -61,7 +59,7 @@ class Chef
           else
             pkg = "#{@new_resource.package_name}"
           end
-          shell_out!("cave -L warning resolve -x#{expand_options(@new_resource.options)} \"#{pkg}\"",:timeout => @new_resource.timeout)
+          shell_out!("cave -L warning resolve -x#{expand_options(@new_resource.options)} \"#{pkg}\"", :timeout => @new_resource.timeout)
         end
 
         def upgrade_package(name, version)
diff --git a/lib/chef/provider/package/portage.rb b/lib/chef/provider/package/portage.rb
index bb047ad..6885098 100644
--- a/lib/chef/provider/package/portage.rb
+++ b/lib/chef/provider/package/portage.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Ezra Zygmuntowicz (<ezra at engineyard.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,30 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/util/path_helper'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
     class Package
       class Portage < Chef::Provider::Package
+
+        provides :package, platform: "gentoo"
+        provides :portage_package
+
         PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)}
 
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
 
-          @current_resource.version(nil)
-
-          category, pkg = %r{^#{PACKAGE_NAME_PATTERN}$}.match(@new_resource.package_name)[1,2]
+          category, pkg = %r{^#{PACKAGE_NAME_PATTERN}$}.match(@new_resource.package_name)[1, 2]
 
           globsafe_category = category ? Chef::Util::PathHelper.escape_glob(category) : nil
           globsafe_pkg = Chef::Util::PathHelper.escape_glob(pkg)
-          possibilities = Dir["/var/db/pkg/#{globsafe_category || "*"}/#{globsafe_pkg}-*"].map {|d| d.sub(%r{/var/db/pkg/}, "") }
+          possibilities = Dir["/var/db/pkg/#{globsafe_category || "*"}/#{globsafe_pkg}-*"].map { |d| d.sub(%r{/var/db/pkg/}, "") }
           versions = possibilities.map do |entry|
             if(entry =~ %r{[^/]+/#{Regexp.escape(pkg)}\-(\d[\.\d]*((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)})
               [$&, $1]
@@ -45,8 +47,8 @@ class Chef
           end.compact
 
           if versions.size > 1
-            atoms = versions.map {|v| v.first }.sort
-            categories = atoms.map {|v| v.split('/')[0] }.uniq
+            atoms = versions.map { |v| v.first }.sort
+            categories = atoms.map { |v| v.split("/")[0] }.uniq
             if !category && categories.size > 1
               raise Chef::Exceptions::Package, "Multiple packages found for #{@new_resource.package_name}: #{atoms.join(" ")}. Specify a category."
             end
@@ -64,7 +66,7 @@ class Chef
 
           txt.each_line do |line|
             if line =~ /\*\s+#{PACKAGE_NAME_PATTERN}/
-              found_package_name = $&.gsub(/\*/, '').strip
+              found_package_name = $&.gsub(/\*/, "").strip
               if package =~ /\// #the category is specified
                 if found_package_name == package
                   availables[found_package_name] = nil
@@ -101,7 +103,6 @@ class Chef
           end
 
           @candidate_version
-
         end
 
         def install_package(name, version)
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index f10fe23..c72c955 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
@@ -51,7 +50,6 @@ class Chef
 
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
-          @new_resource.version(nil)
 
           if @new_resource.source
             unless uri_scheme?(@new_resource.source) || ::File.exists?(@new_resource.source)
@@ -60,9 +58,9 @@ class Chef
             end
 
             Chef::Log.debug("#{@new_resource} checking rpm status")
-            shell_out!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}").stdout.each_line do |line|
+            shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}").stdout.each_line do |line|
               case line
-              when /^([\w\d+_.-]+)\s([\w\d_.-]+)$/
+              when /^(\S+)\s(\S+)$/
                 @current_resource.package_name($1)
                 @new_resource.version($2)
                 @candidate_version = $2
@@ -76,10 +74,10 @@ class Chef
           end
 
           Chef::Log.debug("#{@new_resource} checking install state")
-          @rpm_status = shell_out("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}")
+          @rpm_status = shell_out_with_timeout("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}")
           @rpm_status.stdout.each_line do |line|
             case line
-            when /^([\w\d+_.-]+)\s([\w\d_.-]+)$/
+            when /^(\S+)\s(\S+)$/
               Chef::Log.debug("#{@new_resource} current version is #{$2}")
               @current_resource.version($2)
             end
@@ -90,12 +88,12 @@ class Chef
 
         def install_package(name, version)
           unless @current_resource.version
-            shell_out!( "rpm #{@new_resource.options} -i #{@new_resource.source}" )
+            shell_out_with_timeout!( "rpm #{@new_resource.options} -i #{@new_resource.source}" )
           else
             if allow_downgrade
-              shell_out!( "rpm #{@new_resource.options} -U --oldpackage #{@new_resource.source}" )
+              shell_out_with_timeout!( "rpm #{@new_resource.options} -U --oldpackage #{@new_resource.source}" )
             else
-              shell_out!( "rpm #{@new_resource.options} -U #{@new_resource.source}" )
+              shell_out_with_timeout!( "rpm #{@new_resource.options} -U #{@new_resource.source}" )
             end
           end
         end
@@ -104,9 +102,9 @@ class Chef
 
         def remove_package(name, version)
           if version
-            shell_out!( "rpm #{@new_resource.options} -e #{name}-#{version}" )
+            shell_out_with_timeout!( "rpm #{@new_resource.options} -e #{name}-#{version}" )
           else
-            shell_out!( "rpm #{@new_resource.options} -e #{name}" )
+            shell_out_with_timeout!( "rpm #{@new_resource.options} -e #{name}" )
           end
         end
 
@@ -115,7 +113,7 @@ class Chef
         def uri_scheme?(str)
           scheme = URI.split(str).first
           return false unless scheme
-          %w(http https ftp file).include?(scheme.downcase)
+          %w{http https ftp file}.include?(scheme.downcase)
         rescue URI::InvalidURIError
           return false
         end
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index c53aa89..7a2db6b 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, 2010-2016 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,32 +17,25 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "uri"
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
 
 # Class methods on Gem are defined in rubygems
-require 'rubygems'
+require "rubygems"
 # Ruby 1.9's gem_prelude can interact poorly with loading the full rubygems
 # explicitly like this. Make sure rubygems/specification is always last in this
 # list
-require 'rubygems/version'
-require 'rubygems/dependency'
-require 'rubygems/spec_fetcher'
-require 'rubygems/platform'
-
-# Compatibility note: Rubygems 2.0 removes rubygems/format in favor of
-# rubygems/package.
-begin
-  require 'rubygems/format'
-rescue LoadError
-  require 'rubygems/package'
-end
-require 'rubygems/dependency_installer'
-require 'rubygems/uninstaller'
-require 'rubygems/specification'
+require "rubygems/version"
+require "rubygems/dependency"
+require "rubygems/spec_fetcher"
+require "rubygems/platform"
+require "rubygems/package"
+require "rubygems/dependency_installer"
+require "rubygems/uninstaller"
+require "rubygems/specification"
 
 class Chef
   class Provider
@@ -54,7 +47,7 @@ class Chef
           # alternate value and overwrite it with the defaults.
           Gem.configuration
 
-          DEFAULT_UNINSTALLER_OPTS = {:ignore => true, :executables => true}
+          DEFAULT_UNINSTALLER_OPTS = { :ignore => true, :executables => true }
 
           ##
           # The paths where rubygems should search for installed gems.
@@ -93,7 +86,7 @@ class Chef
           # === Returns
           # [Gem::Specification]  an array of Gem::Specification objects
           def installed_versions(gem_dep)
-            if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+            if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
               gem_specification.find_all_by_name(gem_dep.name, gem_dep.requirement)
             else
               gem_source_index.search(gem_dep)
@@ -140,11 +133,11 @@ class Chef
           def candidate_version_from_file(gem_dependency, source)
             spec = spec_from_file(source)
             if spec.satisfies_requirement?(gem_dependency)
-              logger.debug {"#{@new_resource} found candidate gem version #{spec.version} from local gem package #{source}"}
+              logger.debug { "#{@new_resource} found candidate gem version #{spec.version} from local gem package #{source}" }
               spec.version
             else
               # This is probably going to end badly...
-              logger.warn { "#{@new_resource} gem package #{source} does not satisfy the requirements #{gem_dependency.to_s}" }
+              logger.warn { "#{@new_resource} gem package #{source} does not satisfy the requirements #{gem_dependency}" }
               nil
             end
           end
@@ -168,17 +161,17 @@ class Chef
           def find_newest_remote_version(gem_dependency, *sources)
             available_gems = dependency_installer.find_gems_with_sources(gem_dependency)
             spec, source = if available_gems.respond_to?(:last)
-              # DependencyInstaller sorts the results such that the last one is
-              # always the one it considers best.
-              spec_with_source = available_gems.last
-              spec_with_source && spec_with_source
-            else
-              # Rubygems 2.0 returns a Gem::Available set, which is a
-              # collection of AvailableSet::Tuple structs
-              available_gems.pick_best!
-              best_gem = available_gems.set.first
-              best_gem && [best_gem.spec, best_gem.source]
-            end
+                             # DependencyInstaller sorts the results such that the last one is
+                             # always the one it considers best.
+                             spec_with_source = available_gems.last
+                             spec_with_source && spec_with_source
+                           else
+                             # Rubygems 2.0 returns a Gem::Available set, which is a
+                             # collection of AvailableSet::Tuple structs
+                             available_gems.pick_best!
+                             best_gem = available_gems.set.first
+                             best_gem && [best_gem.spec, best_gem.source]
+                           end
 
             version = spec && spec.version
             if version
@@ -196,7 +189,7 @@ class Chef
           # === Options
           # :sources    rubygems servers to use
           # Other options are passed to Gem::DependencyInstaller.new
-          def install(gem_dependency, options={})
+          def install(gem_dependency, options = {})
             with_gem_sources(*options.delete(:sources)) do
               with_correct_verbosity do
                 dependency_installer(options).install(gem_dependency)
@@ -210,7 +203,7 @@ class Chef
           # Otherwise, all versions are uninstalled.
           # === Options
           # Options are passed to Gem::Uninstaller.new
-          def uninstall(gem_name, gem_version=nil, opts={})
+          def uninstall(gem_name, gem_version = nil, opts = {})
             gem_version ? opts[:version] = gem_version : opts[:all] = true
             with_correct_verbosity do
               uninstaller(gem_name, opts).uninstall
@@ -225,11 +218,11 @@ class Chef
             yield
           end
 
-          def dependency_installer(opts={})
+          def dependency_installer(opts = {})
             Gem::DependencyInstaller.new(opts)
           end
 
-          def uninstaller(gem_name, opts={})
+          def uninstaller(gem_name, opts = {})
             Gem::Uninstaller.new(gem_name, DEFAULT_UNINSTALLER_OPTS.merge(opts))
           end
 
@@ -295,7 +288,7 @@ class Chef
           end
 
           def gem_source_index
-            @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + '/specifications' })
+            @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + "/specifications" })
           end
 
           def gem_specification
@@ -327,7 +320,7 @@ class Chef
             else
               gem_environment = shell_out!("#{@gem_binary_location} env").stdout
               if jruby = gem_environment[JRUBY_PLATFORM]
-                self.class.platform_cache[@gem_binary_location] = ['ruby', Gem::Platform.new(jruby)]
+                self.class.platform_cache[@gem_binary_location] = ["ruby", Gem::Platform.new(jruby)]
               else
                 self.class.platform_cache[@gem_binary_location] = Gem.platforms
               end
@@ -365,7 +358,7 @@ class Chef
 
         include Chef::Mixin::GetSourceFromPackage
 
-        def initialize(new_resource, run_context=nil)
+        def initialize(new_resource, run_context = nil)
           super
           @cleanup_gem_env = true
           if new_resource.gem_binary
@@ -401,11 +394,11 @@ class Chef
         end
 
         def is_omnibus?
-          if RbConfig::CONFIG['bindir'] =~ %r!/opt/(opscode|chef)/embedded/bin!
+          if RbConfig::CONFIG["bindir"] =~ %r{/(opscode|chef|chefdk)/embedded/bin}
             Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
             # Omnibus installs to a static path because of linking on unix, find it.
             true
-          elsif RbConfig::CONFIG['bindir'].sub(/^[\w]:/, '')  == "/opscode/chef/embedded/bin"
+          elsif RbConfig::CONFIG["bindir"].sub(/^[\w]:/, "") == "/opscode/chef/embedded/bin"
             Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}")
             # windows, with the drive letter removed
             true
@@ -417,7 +410,7 @@ class Chef
         def find_gem_by_path
           Chef::Log.debug("#{@new_resource} searching for 'gem' binary in path: #{ENV['PATH']}")
           separator = ::File::ALT_SEPARATOR ? ::File::ALT_SEPARATOR : ::File::SEPARATOR
-          path_to_first_gem = ENV['PATH'].split(::File::PATH_SEPARATOR).select { |path| ::File.exists?(path + separator + "gem") }.first
+          path_to_first_gem = ENV["PATH"].split(::File::PATH_SEPARATOR).select { |path| ::File.exists?(path + separator + "gem") }.first
           raise Chef::Exceptions::FileNotFound, "Unable to find 'gem' binary in path: #{ENV['PATH']}" if path_to_first_gem.nil?
           path_to_first_gem + separator + "gem"
         end
@@ -443,16 +436,16 @@ class Chef
           # is the current version
           if !matching_installed_versions.empty?
             gemspec = matching_installed_versions.last
-            logger.debug { "#{@new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}"}
+            logger.debug { "#{@new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}" }
             gemspec
-          # If no version matching the requirements exists, the latest installed
-          # version is the current version.
+            # If no version matching the requirements exists, the latest installed
+            # version is the current version.
           elsif !all_installed_versions.empty?
             gemspec = all_installed_versions.last
             logger.debug { "#{@new_resource} newest installed version of gem #{gemspec.name} is #{gemspec.version}" }
             gemspec
           else
-            logger.debug { "#{@new_resource} no installed version found for #{gem_dependency.to_s}"}
+            logger.debug { "#{@new_resource} no installed version found for #{gem_dependency}" }
             nil
           end
         end
@@ -463,8 +456,8 @@ class Chef
 
         def all_installed_versions
           @all_installed_versions ||= begin
-            @gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, '>= 0'))
-          end
+                                        @gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, ">= 0"))
+                                      end
         end
 
         def gem_sources
@@ -489,14 +482,14 @@ class Chef
 
         def candidate_version
           @candidate_version ||= begin
-            if target_version_already_installed?(@current_resource.version, @new_resource.version)
-              nil
-            elsif source_is_remote?
-              @gem_env.candidate_version_from_remote(gem_dependency, *gem_sources).to_s
-            else
-              @gem_env.candidate_version_from_file(gem_dependency, @new_resource.source).to_s
-            end
-          end
+                                   if target_version_already_installed?(@current_resource.version, @new_resource.version)
+                                     nil
+                                   elsif source_is_remote?
+                                     @gem_env.candidate_version_from_remote(gem_dependency, *gem_sources).to_s
+                                   else
+                                     @gem_env.candidate_version_from_file(gem_dependency, @new_resource.source).to_s
+                                   end
+                                 end
         end
 
         def target_version_already_installed?(current_version, new_version)
@@ -526,28 +519,28 @@ class Chef
           elsif @new_resource.gem_binary.nil?
             @gem_env.install(@new_resource.source)
           else
-            install_via_gem_command(name,version)
+            install_via_gem_command(name, version)
           end
           true
         end
 
         def gem_binary_path
-          @new_resource.gem_binary || 'gem'
+          @new_resource.gem_binary || "gem"
         end
 
         def install_via_gem_command(name, version)
           if @new_resource.source =~ /\.gem$/i
             name = @new_resource.source
           elsif @new_resource.clear_sources
-            src = ' --clear-sources'
-            src << (@new_resource.source && " --source=#{@new_resource.source}" || '')
+            src = " --clear-sources"
+            src << (@new_resource.source && " --source=#{@new_resource.source}" || "")
           else
             src = @new_resource.source && " --source=#{@new_resource.source} --source=https://rubygems.org"
           end
           if !version.nil? && version.length > 0
-            shell_out!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", :env=>nil)
+            shell_out_with_timeout!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", :env => nil)
           else
-            shell_out!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src}#{opts}", :env=>nil)
+            shell_out_with_timeout!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src}#{opts}", :env => nil)
           end
         end
 
@@ -571,9 +564,9 @@ class Chef
 
         def uninstall_via_gem_command(name, version)
           if version
-            shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", :env=>nil)
+            shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", :env => nil)
           else
-            shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", :env=>nil)
+            shell_out_with_timeout!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", :env => nil)
           end
         end
 
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index 7cef919..3f09bef 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -3,7 +3,7 @@
 #           Bryan McLellan (btm at loftninjas.org)
 #           Matthew Landauer (matthew at openaustralia.org)
 #           Ben Rockwood (benr at joyent.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
@@ -29,13 +29,13 @@ class Chef
       class SmartOS < Chef::Provider::Package
         attr_accessor :is_virtual_package
 
+        provides :package, platform: "smartos"
         provides :smartos_package, os: "solaris2", platform_family: "smartos"
 
         def load_current_resource
           Chef::Log.debug("#{@new_resource} loading current resource")
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
-          @current_resource.version(nil)
           check_package_state(@new_resource.package_name)
           @current_resource # modified by check_package_state
         end
@@ -43,15 +43,13 @@ class Chef
         def check_package_state(name)
           Chef::Log.debug("#{@new_resource} checking package #{name}")
           version = nil
-          info = shell_out!("/opt/local/sbin/pkg_info -E \"#{name}*\"", :env => nil, :returns => [0,1])
+          info = shell_out_with_timeout!("/opt/local/sbin/pkg_info", "-E", "#{name}*", :env => nil, :returns => [0, 1])
 
           if info.stdout
             version = info.stdout[/^#{@new_resource.package_name}-(.+)/, 1]
           end
 
-          if !version
-            @current_resource.version(nil)
-          else
+          if version
             @current_resource.version(version)
           end
         end
@@ -60,11 +58,11 @@ class Chef
           return @candidate_version if @candidate_version
           name = nil
           version = nil
-          pkg = shell_out!("/opt/local/bin/pkgin se #{new_resource.package_name}", :env => nil, :returns => [0,1])
+          pkg = shell_out_with_timeout!("/opt/local/bin/pkgin", "se", new_resource.package_name, :env => nil, :returns => [0, 1])
           pkg.stdout.each_line do |line|
             case line
             when /^#{new_resource.package_name}/
-              name, version = line.split[0].split(/-([^-]+)$/)
+              name, version = line.split(/[; ]/)[0].split(/-([^-]+)$/)
             end
           end
           @candidate_version = version
@@ -74,7 +72,7 @@ class Chef
         def install_package(name, version)
           Chef::Log.debug("#{@new_resource} installing package #{name} version #{version}")
           package = "#{name}-#{version}"
-          out = shell_out!("/opt/local/bin/pkgin -y install #{package}", :env => nil)
+          out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "install", package, :env => nil)
         end
 
         def upgrade_package(name, version)
@@ -85,7 +83,7 @@ class Chef
         def remove_package(name, version)
           Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}")
           package = "#{name}"
-          out = shell_out!("/opt/local/bin/pkgin -y remove #{package}", :env => nil)
+          out = shell_out_with_timeout!("/opt/local/bin/pkgin", "-y", "remove", package, :env => nil)
         end
 
       end
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index a2cfd93..1c393e6 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'chef/mixin/get_source_from_package'
+require "chef/provider/package"
+require "chef/mixin/command"
+require "chef/resource/package"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
@@ -27,6 +27,8 @@ class Chef
 
         include Chef::Mixin::GetSourceFromPackage
 
+        provides :package, platform: "nexentacore"
+        provides :package, platform: "solaris2", platform_version: "< 5.11"
         provides :solaris_package, os: "solaris2"
 
         # def initialize(*args)
@@ -49,13 +51,12 @@ class Chef
         def load_current_resource
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
-          @new_resource.version(nil)
 
           if @new_resource.source
             @package_source_found = ::File.exists?(@new_resource.source)
             if @package_source_found
               Chef::Log.debug("#{@new_resource} checking pkg status")
-              shell_out("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}").stdout.each_line do |line|
+              shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}").stdout.each_line do |line|
                 case line
                 when /VERSION:\s+(.+)/
                   @new_resource.version($1)
@@ -65,7 +66,7 @@ class Chef
           end
 
           Chef::Log.debug("#{@new_resource} checking install state")
-          status = shell_out("pkginfo -l #{@current_resource.package_name}")
+          status = shell_out_with_timeout("pkginfo -l #{@current_resource.package_name}")
           status.stdout.each_line do |line|
             case line
             when /VERSION:\s+(.+)/
@@ -78,16 +79,12 @@ class Chef
             raise Chef::Exceptions::Package, "pkginfo failed - #{status.inspect}!"
           end
 
-          unless @current_resource.version.nil?
-            @current_resource.version(nil)
-          end
-
           @current_resource
         end
 
         def candidate_version
           return @candidate_version if @candidate_version
-          status = shell_out("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}")
+          status = shell_out_with_timeout("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}")
           status.stdout.each_line do |line|
             case line
             when /VERSION:\s+(.+)/
@@ -110,7 +107,7 @@ class Chef
             else
               command = "pkgadd -n -d #{@new_resource.source} all"
             end
-            shell_out!(command)
+            shell_out_with_timeout!(command)
             Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
           else
             if ::File.directory?(@new_resource.source) # CHEF-4469
@@ -118,17 +115,19 @@ class Chef
             else
               command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
             end
-            shell_out!(command)
+            shell_out_with_timeout!(command)
             Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
           end
         end
 
+        alias_method :upgrade_package, :install_package
+
         def remove_package(name, version)
           if @new_resource.options.nil?
-            shell_out!( "pkgrm -n #{name}" )
+            shell_out_with_timeout!( "pkgrm -n #{name}" )
             Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
           else
-            shell_out!( "pkgrm -n#{expand_options(@new_resource.options)} #{name}" )
+            shell_out_with_timeout!( "pkgrm -n#{expand_options(@new_resource.options)} #{name}" )
             Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
           end
         end
diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb
index 143d82f..dc22de7 100644
--- a/lib/chef/provider/package/windows.rb
+++ b/lib/chef/provider/package/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,70 +16,244 @@
 # limitations under the License.
 #
 
-require 'chef/resource/windows_package'
-require 'chef/provider/package'
-require 'chef/util/path_helper'
+require "chef/mixin/uris"
+require "chef/resource/windows_package"
+require "chef/provider/package"
+require "chef/util/path_helper"
+require "chef/mixin/checksum"
 
 class Chef
   class Provider
     class Package
       class Windows < Chef::Provider::Package
+        include Chef::Mixin::Uris
+        include Chef::Mixin::Checksum
 
         provides :package, os: "windows"
         provides :windows_package, os: "windows"
 
-        # Depending on the installer, we may need to examine installer_type or
-        # source attributes, or search for text strings in the installer file
-        # binary to determine the installer type for the user. Since the file
-        # must be on disk to do so, we have to make this choice in the provider.
-        require 'chef/provider/package/windows/msi.rb'
+        require "chef/provider/package/windows/registry_uninstall_entry.rb"
+
+        def define_resource_requirements
+          requirements.assert(:install) do |a|
+            a.assertion { new_resource.source unless package_provider == :msi }
+            a.failure_message Chef::Exceptions::NoWindowsPackageSource, "Source for package #{new_resource.name} must be specified in the resource's source property for package to be installed because the package_name property is used to test for the package installation state for this package type."
+          end
+        end
 
         # load_current_resource is run in Chef::Provider#run_action when not in whyrun_mode?
         def load_current_resource
-          @new_resource.source(Chef::Util::PathHelper.validate_path(@new_resource.source))
+          @current_resource = Chef::Resource::WindowsPackage.new(new_resource.name)
+          if downloadable_file_missing?
+            Chef::Log.debug("We do not know the version of #{new_resource.source} because the file is not downloaded")
+            current_resource.version(:unknown.to_s)
+          else
+            current_resource.version(package_provider.installed_version)
+            new_resource.version(package_provider.package_version) if package_provider.package_version
+          end
 
-          @current_resource = Chef::Resource::WindowsPackage.new(@new_resource.name)
-          @current_resource.version(package_provider.installed_version)
-          @new_resource.version(package_provider.package_version)
-          @current_resource
+          current_resource
         end
 
         def package_provider
           @package_provider ||= begin
             case installer_type
             when :msi
-              Chef::Provider::Package::Windows::MSI.new(@new_resource)
+              Chef::Log.debug("#{new_resource} is MSI")
+              require "chef/provider/package/windows/msi"
+              Chef::Provider::Package::Windows::MSI.new(resource_for_provider, uninstall_registry_entries)
             else
-              raise "Unable to find a Chef::Provider::Package::Windows provider for installer_type '#{installer_type}'"
+              Chef::Log.debug("#{new_resource} is EXE with type '#{installer_type}'")
+              require "chef/provider/package/windows/exe"
+              Chef::Provider::Package::Windows::Exe.new(resource_for_provider, installer_type, uninstall_registry_entries)
             end
           end
         end
 
         def installer_type
+          # Depending on the installer, we may need to examine installer_type or
+          # source attributes, or search for text strings in the installer file
+          # binary to determine the installer type for the user. Since the file
+          # must be on disk to do so, we have to make this choice in the provider.
           @installer_type ||= begin
-            if @new_resource.installer_type
-              @new_resource.installer_type
+            if new_resource.installer_type
+              new_resource.installer_type
+            elsif source_location.nil?
+              inferred_registry_type
             else
-              file_extension = ::File.basename(@new_resource.source).split(".").last.downcase
+              basename = ::File.basename(source_location)
+              file_extension = basename.split(".").last.downcase
 
               if file_extension == "msi"
                 :msi
               else
-                raise ArgumentError, "Installer type for Windows Package '#{@new_resource.name}' not specified and cannot be determined from file extension '#{file_extension}'"
+                # search the binary file for installer type
+                ::Kernel.open(::File.expand_path(source_location), "rb") do |io|
+                  filesize = io.size
+                  bufsize = 4096 # read 4K buffers
+                  overlap = 16 # bytes to overlap between buffer reads
+
+                  until io.eof
+                    contents = io.read(bufsize)
+
+                    case contents
+                    when /inno/i # Inno Setup
+                      return :inno
+                    when /wise/i # Wise InstallMaster
+                      return :wise
+                    when /nullsoft/i # Nullsoft Scriptable Install System
+                      return :nsis
+                    end
+
+                    if (io.tell() < filesize)
+                      io.seek(io.tell() - overlap)
+                    end
+                  end
+                end
+
+                # if file is named 'setup.exe' assume installshield
+                if basename == "setup.exe"
+                  :installshield
+                else
+                  raise Chef::Exceptions::CannotDetermineWindowsInstallerType, "Installer type for Windows Package '#{new_resource.name}' not specified and cannot be determined from file extension '#{file_extension}'"
+                end
               end
             end
           end
         end
 
+        def action_install
+          if uri_scheme?(new_resource.source)
+            download_source_file
+            load_current_resource
+          else
+            validate_content!
+          end
+
+          super
+        end
+
         # Chef::Provider::Package action_install + action_remove call install_package + remove_package
         # Pass those calls to the correct sub-provider
         def install_package(name, version)
-          package_provider.install_package(name, version)
+          package_provider.install_package
         end
 
         def remove_package(name, version)
-          package_provider.remove_package(name, version)
+          package_provider.remove_package
+        end
+
+        # @return [Array] new_version(s) as an array
+        def new_version_array
+          # Because the one in the parent caches things
+          [new_resource.version]
+        end
+
+        # @return [String] candidate_version
+        def candidate_version
+          @candidate_version ||= (new_resource.version || "latest")
+        end
+
+        # @return [Array] current_version(s) as an array
+        # this package provider does not support package arrays
+        # However, There may be multiple versions for a single
+        # package so the first element may be a nested array
+        def current_version_array
+          [ current_resource.version ]
+        end
+
+        # @param current_version<String> one or more versions currently installed
+        # @param new_version<String> version of the new resource
+        #
+        # @return [Boolean] true if new_version is equal to or included in current_version
+        def target_version_already_installed?(current_version, new_version)
+          Chef::Log.debug("Checking if #{new_resource} version '#{new_version}' is already installed. #{current_version} is currently installed")
+          if current_version.is_a?(Array)
+            current_version.include?(new_version)
+          else
+            new_version == current_version
+          end
+        end
+
+        def have_any_matching_version?
+          target_version_already_installed?(current_resource.version, new_resource.version)
+        end
+
+        private
+
+        def uninstall_registry_entries
+          @uninstall_registry_entries ||= Chef::Provider::Package::Windows::RegistryUninstallEntry.find_entries(new_resource.package_name)
         end
+
+        def inferred_registry_type
+          uninstall_registry_entries.each do |entry|
+            return :inno if entry.key.end_with?("_is1")
+            return :msi if entry.uninstall_string.downcase.start_with?("msiexec.exe ")
+            return :nsis if entry.uninstall_string.downcase.end_with?("uninst.exe\"")
+          end
+          nil
+        end
+
+        def downloadable_file_missing?
+          !new_resource.source.nil? && uri_scheme?(new_resource.source) && !::File.exists?(source_location)
+        end
+
+        def resource_for_provider
+          @resource_for_provider = Chef::Resource::WindowsPackage.new(new_resource.name).tap do |r|
+            r.source(Chef::Util::PathHelper.validate_path(source_location)) unless source_location.nil?
+            r.version(new_resource.version)
+            r.timeout(new_resource.timeout)
+            r.returns(new_resource.returns)
+            r.options(new_resource.options)
+          end
+        end
+
+        def download_source_file
+          source_resource.run_action(:create)
+          Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}")
+        end
+
+        def source_resource
+          @source_resource ||= Chef::Resource::RemoteFile.new(default_download_cache_path, run_context).tap do |r|
+            r.source(new_resource.source)
+            r.checksum(new_resource.checksum)
+            r.backup(false)
+
+            if new_resource.remote_file_attributes
+              new_resource.remote_file_attributes.each do |(k, v)|
+                r.send(k.to_sym, v)
+              end
+            end
+          end
+        end
+
+        def default_download_cache_path
+          uri = ::URI.parse(new_resource.source)
+          filename = ::File.basename(::URI.unescape(uri.path))
+          file_cache_dir = Chef::FileCache.create_cache_path("package/")
+          Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}")
+        end
+
+        def source_location
+          if new_resource.source.nil?
+            nil
+          elsif uri_scheme?(new_resource.source)
+            source_resource.path
+          else
+            new_source = Chef::Util::PathHelper.cleanpath(new_resource.source)
+            ::File.exist?(new_source) ? new_source : nil
+          end
+        end
+
+        def validate_content!
+          if new_resource.checksum
+            source_checksum = checksum(source_location)
+            if new_resource.checksum != source_checksum
+              raise Chef::Exceptions::ChecksumMismatch.new(short_cksum(new_resource.checksum), short_cksum(source_checksum))
+            end
+          end
+        end
+
       end
     end
   end
diff --git a/lib/chef/provider/package/windows/exe.rb b/lib/chef/provider/package/windows/exe.rb
new file mode 100644
index 0000000..70c9879
--- /dev/null
+++ b/lib/chef/provider/package/windows/exe.rb
@@ -0,0 +1,117 @@
+#
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Matt Wrock <matt at mattwrock.com>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/mixin/shell_out"
+
+class Chef
+  class Provider
+    class Package
+      class Windows
+        class Exe
+          include Chef::Mixin::ShellOut
+
+          def initialize(resource, installer_type, uninstall_entries)
+            @new_resource = resource
+            @installer_type = installer_type
+            @uninstall_entries = uninstall_entries
+          end
+
+          attr_reader :new_resource
+          attr_reader :installer_type
+          attr_reader :uninstall_entries
+
+          # From Chef::Provider::Package
+          def expand_options(options)
+            options ? " #{options}" : ""
+          end
+
+          # Returns a version if the package is installed or nil if it is not.
+          def installed_version
+            Chef::Log.debug("#{new_resource} checking package version")
+            current_installed_version
+          end
+
+          def package_version
+            new_resource.version
+          end
+
+          def install_package
+            Chef::Log.debug("#{new_resource} installing #{new_resource.installer_type} package '#{new_resource.source}'")
+            shell_out!(
+              [
+                "start",
+                "\"\"",
+                "/wait",
+                "\"#{new_resource.source}\"",
+                unattended_flags,
+                expand_options(new_resource.options),
+                "& exit %%%%ERRORLEVEL%%%%",
+              ].join(" "), timeout: new_resource.timeout, returns: new_resource.returns
+            )
+          end
+
+          def remove_package
+            uninstall_version = new_resource.version || current_installed_version
+            uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
+              .map { |version| version.uninstall_string }.uniq.each do |uninstall_string|
+                Chef::Log.debug("Registry provided uninstall string for #{new_resource} is '#{uninstall_string}'")
+                shell_out!(uninstall_command(uninstall_string), { returns: new_resource.returns })
+              end
+          end
+
+          private
+
+          def uninstall_command(uninstall_string)
+            uninstall_string.delete!('"')
+            uninstall_string = [
+              %q{/d"},
+              ::File.dirname(uninstall_string),
+              %q{" },
+              ::File.basename(uninstall_string),
+              expand_options(new_resource.options),
+              " ",
+              unattended_flags,
+            ].join
+            %Q{start "" /wait #{uninstall_string} & exit %%%%ERRORLEVEL%%%%}
+          end
+
+          def current_installed_version
+            @current_installed_version ||= uninstall_entries.count == 0 ? nil : begin
+              uninstall_entries.map { |entry| entry.display_version }.uniq
+            end
+          end
+
+          # http://unattended.sourceforge.net/installers.php
+          def unattended_flags
+            case installer_type
+            when :installshield
+              "/s /sms"
+            when :nsis
+              "/S /NCRC"
+            when :inno
+              "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART"
+            when :wise
+              "/s"
+            end
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/provider/package/windows/msi.rb b/lib/chef/provider/package/windows/msi.rb
index 9384529..ac77168 100644
--- a/lib/chef/provider/package/windows/msi.rb
+++ b/lib/chef/provider/package/windows/msi.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,21 +18,25 @@
 
 # TODO: Allow @new_resource.source to be a Product Code as a GUID for uninstall / network install
 
-require 'chef/win32/api/installer' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-require 'chef/mixin/shell_out'
+require "chef/win32/api/installer" if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
+require "chef/mixin/shell_out"
 
 class Chef
   class Provider
     class Package
       class Windows
         class MSI
-          include Chef::ReservedNames::Win32::API::Installer if RUBY_PLATFORM =~ /mswin|mingw32|windows/
+          include Chef::ReservedNames::Win32::API::Installer if (RUBY_PLATFORM =~ /mswin|mingw32|windows/) && Chef::Platform.supports_msi?
           include Chef::Mixin::ShellOut
 
-          def initialize(resource)
+          def initialize(resource, uninstall_entries)
             @new_resource = resource
+            @uninstall_entries = uninstall_entries
           end
 
+          attr_reader :new_resource
+          attr_reader :uninstall_entries
+
           # From Chef::Provider::Package
           def expand_options(options)
             options ? " #{options}" : ""
@@ -40,27 +44,47 @@ class Chef
 
           # Returns a version if the package is installed or nil if it is not.
           def installed_version
-            Chef::Log.debug("#{@new_resource} getting product code for package at #{@new_resource.source}")
-            product_code = get_product_property(@new_resource.source, "ProductCode")
-            Chef::Log.debug("#{@new_resource} checking package status and version for #{product_code}")
-            get_installed_version(product_code)
+            if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+              Chef::Log.debug("#{new_resource} getting product code for package at #{new_resource.source}")
+              product_code = get_product_property(new_resource.source, "ProductCode")
+              Chef::Log.debug("#{new_resource} checking package status and version for #{product_code}")
+              get_installed_version(product_code)
+            else
+              uninstall_entries.count == 0 ? nil : begin
+                uninstall_entries.map { |entry| entry.display_version }.uniq
+              end
+            end
           end
 
           def package_version
-            Chef::Log.debug("#{@new_resource} getting product version for package at #{@new_resource.source}")
-            get_product_property(@new_resource.source, "ProductVersion")
+            return new_resource.version if new_resource.version
+            if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+              Chef::Log.debug("#{new_resource} getting product version for package at #{new_resource.source}")
+              get_product_property(new_resource.source, "ProductVersion")
+            end
           end
 
-          def install_package(name, version)
+          def install_package
             # We could use MsiConfigureProduct here, but we'll start off with msiexec
-            Chef::Log.debug("#{@new_resource} installing MSI package '#{@new_resource.source}'")
-            shell_out!("msiexec /qn /i \"#{@new_resource.source}\" #{expand_options(@new_resource.options)}", {:timeout => @new_resource.timeout, :returns => @new_resource.returns})
+            Chef::Log.debug("#{new_resource} installing MSI package '#{new_resource.source}'")
+            shell_out!("msiexec /qn /i \"#{new_resource.source}\" #{expand_options(new_resource.options)}", { :timeout => new_resource.timeout, :returns => new_resource.returns })
           end
-  
-          def remove_package(name, version)
+
+          def remove_package
             # We could use MsiConfigureProduct here, but we'll start off with msiexec
-            Chef::Log.debug("#{@new_resource} removing MSI package '#{@new_resource.source}'")
-            shell_out!("msiexec /qn /x \"#{@new_resource.source}\" #{expand_options(@new_resource.options)}", {:timeout => @new_resource.timeout, :returns => @new_resource.returns})
+            if !new_resource.source.nil? && ::File.exist?(new_resource.source)
+              Chef::Log.debug("#{new_resource} removing MSI package '#{new_resource.source}'")
+              shell_out!("msiexec /qn /x \"#{new_resource.source}\" #{expand_options(new_resource.options)}", { :timeout => new_resource.timeout, :returns => new_resource.returns })
+            else
+              uninstall_version = new_resource.version || installed_version
+              uninstall_entries.select { |entry| [uninstall_version].flatten.include?(entry.display_version) }
+                .map { |version| version.uninstall_string }.uniq.each do |uninstall_string|
+                Chef::Log.debug("#{new_resource} removing MSI package version using '#{uninstall_string}'")
+                uninstall_string += expand_options(new_resource.options)
+                uninstall_string += " /Q" unless uninstall_string =~ / \/Q\b/
+                shell_out!(uninstall_string, { :timeout => new_resource.timeout, :returns => new_resource.returns })
+              end
+            end
           end
         end
       end
diff --git a/lib/chef/provider/package/windows/registry_uninstall_entry.rb b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
new file mode 100644
index 0000000..952a0f7
--- /dev/null
+++ b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
@@ -0,0 +1,89 @@
+#
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Matt Wrock <matt at mattwrock.com>
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "win32/registry" if (RUBY_PLATFORM =~ /mswin|mingw32|windows/)
+
+class Chef
+  class Provider
+    class Package
+      class Windows
+        class RegistryUninstallEntry
+
+          def self.find_entries(package_name)
+            Chef::Log.debug("Finding uninstall entries for #{package_name}")
+            entries = []
+            [
+              [::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0100)],
+              [::Win32::Registry::HKEY_LOCAL_MACHINE, (::Win32::Registry::Constants::KEY_READ | 0x0200)],
+              [::Win32::Registry::HKEY_CURRENT_USER],
+            ].each do |hkey|
+              desired = hkey.length > 1 ? hkey[1] : ::Win32::Registry::Constants::KEY_READ
+              begin
+                ::Win32::Registry.open(hkey[0], UNINSTALL_SUBKEY, desired) do |reg|
+                  reg.each_key do |key, _wtime|
+                    begin
+                      entry = reg.open(key, desired)
+                      display_name = read_registry_property(entry, "DisplayName")
+                      if display_name == package_name
+                        entries.push(RegistryUninstallEntry.new(hkey, key, entry))
+                      end
+                    rescue ::Win32::Registry::Error => ex
+                      Chef::Log.debug("Registry error opening key '#{key}' on node #{desired}: #{ex}")
+                    end
+                  end
+                end
+              rescue ::Win32::Registry::Error => ex
+                Chef::Log.debug("Registry error opening hive '#{hkey[0]}' :: #{desired}: #{ex}")
+              end
+            end
+            entries
+          end
+
+          def self.read_registry_property(data, property)
+            data[property]
+          rescue ::Win32::Registry::Error => ex
+            Chef::Log.debug("Failure to read property '#{property}'")
+            nil
+          end
+
+          def initialize(hive, key, registry_data)
+            Chef::Log.debug("Creating uninstall entry for #{hive}::#{key}")
+            @hive = hive
+            @key = key
+            @data = registry_data
+            @display_name = RegistryUninstallEntry.read_registry_property(registry_data, "DisplayName")
+            @display_version = RegistryUninstallEntry.read_registry_property(registry_data, "DisplayVersion")
+            @uninstall_string = RegistryUninstallEntry.read_registry_property(registry_data, "UninstallString")
+          end
+
+          attr_reader :hive
+          attr_reader :key
+          attr_reader :display_name
+          attr_reader :display_version
+          attr_reader :uninstall_string
+          attr_reader :data
+
+          private
+
+          UNINSTALL_SUBKEY = 'Software\Microsoft\Windows\CurrentVersion\Uninstall'.freeze
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/provider/package/yum-dump.py b/lib/chef/provider/package/yum-dump.py
index c9f6a1f..6183460 100644
--- a/lib/chef/provider/package/yum-dump.py
+++ b/lib/chef/provider/package/yum-dump.py
@@ -1,6 +1,6 @@
 #
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2009, 2011 Matthew Kent
+# Copyright:: Copyright 2009-2016, Matthew Kent
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index 49c6f6b..aeecf38 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -1,6 +1,6 @@
-#
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,19 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/provider/package'
-require 'chef/mixin/shell_out'
-require 'chef/resource/package'
-require 'singleton'
-require 'chef/mixin/get_source_from_package'
+require "chef/config"
+require "chef/provider/package"
+require "chef/mixin/which"
+require "chef/resource/package"
+require "singleton"
+require "chef/mixin/get_source_from_package"
 
 class Chef
   class Provider
     class Package
       class Yum < Chef::Provider::Package
 
+        provides :package, platform_family: %w{rhel fedora}
         provides :yum_package, os: "linux"
 
         class RPMUtils
@@ -62,7 +63,7 @@ class Chef
                 end
               end
 
-              version = evr[lead,tail]
+              version = evr[lead, tail]
               if version.empty?
                 version = nil
               end
@@ -158,12 +159,12 @@ class Chef
                   end
                   # copy the segment but not the unmatched character that x_seg_pos will
                   # refer to
-                  x_comp = x[x_pos,x_seg_pos - x_pos]
+                  x_comp = x[x_pos, x_seg_pos - x_pos]
 
                   while (y_seg_pos <= y_pos_max) and isdigit(y[y_seg_pos])
                     y_seg_pos += 1
                   end
-                  y_comp = y[y_pos,y_seg_pos - y_pos]
+                  y_comp = y[y_pos, y_seg_pos - y_pos]
                 else
                   # we are comparing strings
                   x_seg_is_num = false
@@ -171,12 +172,12 @@ class Chef
                   while (x_seg_pos <= x_pos_max) and isalpha(x[x_seg_pos])
                     x_seg_pos += 1
                   end
-                  x_comp = x[x_pos,x_seg_pos - x_pos]
+                  x_comp = x[x_pos, x_seg_pos - x_pos]
 
                   while (y_seg_pos <= y_pos_max) and isalpha(y[y_seg_pos])
                     y_seg_pos += 1
                   end
-                  y_comp = y[y_pos,y_seg_pos - y_pos]
+                  y_comp = y[y_pos, y_seg_pos - y_pos]
                 end
 
                 # if y_seg_pos didn't advance in the above loop it means the segments are
@@ -239,7 +240,7 @@ class Chef
               @r = args[2]
             else
               raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " +
-                                   "version, release'"
+                "version, release'"
             end
           end
           attr_reader :e, :v, :r
@@ -285,7 +286,7 @@ class Chef
           # 2:1.2-1 == 2:1.2
           # 2:1.2-1 == 2:
           #
-          def compare_versions(y, partial=false)
+          def compare_versions(y, partial = false)
             x = self
 
             # compare epoch
@@ -343,12 +344,12 @@ class Chef
               e = args[1].to_i
               v = args[2]
               r = args[3]
-              @version = RPMVersion.new(e,v,r)
+              @version = RPMVersion.new(e, v, r)
               @a = args[4]
               @provides = args[5]
             else
               raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " +
-                                   "or 'name, epoch, version, release, arch, provides'"
+                "or 'name, epoch, version, release, arch, provides'"
             end
 
             # We always have one, ourselves!
@@ -428,11 +429,11 @@ class Chef
               e = args[1].to_i
               v = args[2]
               r = args[3]
-              @version = RPMVersion.new(e,v,r)
+              @version = RPMVersion.new(e, v, r)
               @flag = args[4] || :==
             else
               raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " +
-                                   "'name, epoch, version, release, flag'"
+                "'name, epoch, version, release, flag'"
             end
           end
           attr_reader :name, :version, :flag
@@ -646,10 +647,12 @@ class Chef
 
         # Cache for our installed and available packages, pulled in from yum-dump.py
         class YumCache
-          include Chef::Mixin::Command
+          include Chef::Mixin::Which
           include Chef::Mixin::ShellOut
           include Singleton
 
+          attr_accessor :yum_binary
+
           def initialize
             @rpmdb = RPMDb.new
 
@@ -687,15 +690,15 @@ class Chef
             when :installed
               reset_installed
               # fast
-              opts=" --installed"
+              opts = " --installed"
             when :all
               reset
               # medium
-              opts=" --options --installed-provides"
+              opts = " --options --installed-provides"
             when :provides
               reset
               # slow!
-              opts=" --options --all-provides"
+              opts = " --options --all-provides"
             else
               raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}"
             end
@@ -709,11 +712,11 @@ class Chef
             one_line = false
             error = nil
 
-            helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py')
+            helper = ::File.join(::File.dirname(__FILE__), "yum-dump.py")
             status = nil
 
             begin
-              status = shell_out!("/usr/bin/python #{helper}#{opts}", :timeout => Chef::Config[:yum_timeout])
+              status = shell_out!("#{python_bin} #{helper}#{opts}", :timeout => Chef::Config[:yum_timeout])
               status.stdout.each_line do |line|
                 one_line = true
 
@@ -779,6 +782,42 @@ class Chef
             @next_refresh = :none
           end
 
+          def python_bin
+            yum_executable = which(yum_binary)
+            if yum_executable && shabang?(yum_executable)
+              shabang_or_fallback(extract_interpreter(yum_executable))
+            else
+              Chef::Log.warn("Yum executable not found or doesn't start with #!. Using default python.")
+              "/usr/bin/python"
+            end
+          rescue StandardError => e
+            Chef::Log.warn("An error occurred attempting to determine correct python executable. Using default.")
+            Chef::Log.debug(e)
+            "/usr/bin/python"
+          end
+
+          def extract_interpreter(file)
+            ::File.open(file, "r", &:readline)[2..-1].strip
+          end
+
+          # dnf based systems have a yum shim that has /bin/bash as the interpreter. Don't use this.
+          def shabang_or_fallback(interpreter)
+            if interpreter == "/bin/bash"
+              Chef::Log.warn("Yum executable interpreter is /bin/bash. Falling back to default python.")
+              "/usr/bin/python"
+            else
+              interpreter
+            end
+          end
+
+          def shabang?(file)
+            ::File.open(file, "r") do |f|
+              f.read(2) == '#!'
+            end
+          rescue Errno::ENOENT
+            false
+          end
+
           def reload
             @next_refresh = :all
           end
@@ -831,7 +870,7 @@ class Chef
           end
 
           # Check if a package-version.arch is available to install
-          def version_available?(package_name, desired_version, arch=nil)
+          def version_available?(package_name, desired_version, arch = nil)
             version(package_name, arch, true, false) do |v|
               return true if desired_version == v
             end
@@ -840,7 +879,7 @@ class Chef
           end
 
           # Return the source repository for a package-version.arch
-          def package_repository(package_name, desired_version, arch=nil)
+          def package_repository(package_name, desired_version, arch = nil)
             package(package_name, arch, true, false) do |pkg|
               return pkg.repoid if desired_version == pkg.version.to_s
             end
@@ -849,13 +888,13 @@ class Chef
           end
 
           # Return the latest available version for a package.arch
-          def available_version(package_name, arch=nil)
+          def available_version(package_name, arch = nil)
             version(package_name, arch, true, false)
           end
           alias :candidate_version :available_version
 
           # Return the currently installed version for a package.arch
-          def installed_version(package_name, arch=nil)
+          def installed_version(package_name, arch = nil)
             version(package_name, arch, false, true)
           end
 
@@ -883,7 +922,7 @@ class Chef
 
           private
 
-          def version(package_name, arch=nil, is_available=false, is_installed=false)
+          def version(package_name, arch = nil, is_available = false, is_installed = false)
             package(package_name, arch, is_available, is_installed) do |pkg|
               if block_given?
                 yield pkg.version.to_s
@@ -900,7 +939,7 @@ class Chef
             end
           end
 
-          def package(package_name, arch=nil, is_available=false, is_installed=false)
+          def package(package_name, arch = nil, is_available = false, is_installed = false)
             refresh
             packages = @rpmdb[package_name]
             if packages
@@ -953,11 +992,31 @@ class Chef
           super
 
           @yum = YumCache.instance
+          @yum.yum_binary = yum_binary
+        end
+
+        def yum_binary
+          @yum_binary ||=
+            begin
+              yum_binary = new_resource.yum_binary if new_resource.is_a?(Chef::Resource::YumPackage)
+              yum_binary ||= ::File.exist?("/usr/bin/yum-deprecated") ? "yum-deprecated" : "yum"
+            end
         end
 
         # Extra attributes
         #
 
+        def arch_for_name(n)
+          if @new_resource.respond_to?("arch")
+            @new_resource.arch
+          elsif @arch
+            idx = package_name_array.index(n)
+            as_array(@arch)[idx]
+          else
+            nil
+          end
+        end
+
         def arch
           if @new_resource.respond_to?("arch")
             @new_resource.arch
@@ -966,6 +1025,12 @@ class Chef
           end
         end
 
+        def set_arch(arch)
+          if @new_resource.respond_to?("arch")
+            @new_resource.arch(arch)
+          end
+        end
+
         def flush_cache
           if @new_resource.respond_to?("flush_cache")
             @new_resource.flush_cache
@@ -977,12 +1042,14 @@ class Chef
         # Helpers
         #
 
-        def yum_arch
+        def yum_arch(arch)
           arch ? ".#{arch}" : nil
         end
 
         def yum_command(command)
-          status = shell_out(command, {:timeout => Chef::Config[:yum_timeout]})
+          command = "#{yum_binary} #{command}"
+          Chef::Log.debug("#{@new_resource}: yum command: \"#{command}\"")
+          status = shell_out_with_timeout(command, { :timeout => Chef::Config[:yum_timeout] })
 
           # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
           # considered fatal - meaning the rpm is still successfully installed. These issue
@@ -999,7 +1066,7 @@ class Chef
               if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
                 Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
                                "so running install again to verify.")
-                status = shell_out(command, {:timeout => Chef::Config[:yum_timeout]})
+                status = shell_out_with_timeout(command, { :timeout => Chef::Config[:yum_timeout] })
                 break
               end
             end
@@ -1059,23 +1126,19 @@ class Chef
             end
           end
 
-          # Don't overwrite an existing arch
-          unless arch
-            parse_arch
-          end
-
           @current_resource = Chef::Resource::Package.new(@new_resource.name)
           @current_resource.package_name(@new_resource.package_name)
 
           installed_version = []
           @candidate_version = []
+          @arch = []
           if @new_resource.source
             unless ::File.exists?(@new_resource.source)
               raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
             end
 
             Chef::Log.debug("#{@new_resource} checking rpm status")
-            shell_out!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line|
+            shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line|
               case line
               when /([\w\d_.-]+)\s([\w\d_.-]+)/
                 @current_resource.package_name($1)
@@ -1085,24 +1148,43 @@ class Chef
             @candidate_version << @new_resource.version
             installed_version << @yum.installed_version(@current_resource.package_name, arch)
           else
-            if @new_resource.version
-              new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}"
-            else
-              new_resource = "#{@new_resource.package_name}#{yum_arch}"
-            end
 
-            Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
+            package_name_array.each_with_index do |pkg, idx|
+              # Don't overwrite an existing arch
+              if arch
+                name, parch = pkg, arch
+              else
+                name, parch = parse_arch(pkg)
+                # if we parsed an arch from the name, update the name
+                # to be just the package name.
+                if parch
+                  if @new_resource.package_name.is_a?(Array)
+                    @new_resource.package_name[idx] = name
+                  else
+                    @new_resource.package_name(name)
+                    # only set the arch if it's a single package
+                    set_arch(parch)
+                  end
+                end
+              end
 
-            package_name_array.each do |pkg|
-              installed_version << @yum.installed_version(pkg, arch)
-              @candidate_version << @yum.candidate_version(pkg, arch)
+              if @new_resource.version
+                new_resource =
+                  "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch(parch)}"
+              else
+                new_resource = "#{@new_resource.package_name}#{yum_arch(parch)}"
+              end
+              Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
+              installed_version << @yum.installed_version(name, parch)
+              @candidate_version << @yum.candidate_version(name, parch)
+              @arch << parch
             end
-
           end
 
           if installed_version.size == 1
             @current_resource.version(installed_version[0])
             @candidate_version = @candidate_version[0]
+            @arch = @arch[0]
           else
             @current_resource.version(installed_version)
           end
@@ -1117,7 +1199,7 @@ class Chef
           # Work around yum not exiting with an error if a package doesn't exist
           # for CHEF-2062
           all_avail = as_array(name).zip(as_array(version)).any? do |n, v|
-            @yum.version_available?(n, v, arch)
+            @yum.version_available?(n, v, arch_for_name(n))
           end
           method = log_method = nil
           methods = []
@@ -1142,7 +1224,7 @@ class Chef
                   else
                     # we bail like yum when the package is older
                     raise Chef::Exceptions::Package, "Installed package #{n}-#{current_version_array[idx]} is newer " +
-                                                     "than candidate package #{n}-#{v}"
+                      "than candidate package #{n}-#{v}"
                   end
                 end
               end
@@ -1159,29 +1241,29 @@ class Chef
 
             repos = []
             pkg_string_bits = []
-            index = 0
             as_array(name).zip(as_array(version)).each do |n, v|
-              s = ''
-              unless v == current_version_array[index]
-                s = "#{n}-#{v}#{yum_arch}"
-                repo = @yum.package_repository(n, v, arch)
+              idx = package_name_array.index(n)
+              a = arch_for_name(n)
+              s = ""
+              unless v == current_version_array[idx]
+                s = "#{n}-#{v}#{yum_arch(a)}"
+                repo = @yum.package_repository(n, v, a)
                 repos << "#{s} from #{repo} repository"
                 pkg_string_bits << s
               end
-              index += 1
             end
-            pkg_string = pkg_string_bits.join(' ')
+            pkg_string = pkg_string_bits.join(" ")
             Chef::Log.info("#{@new_resource} #{log_method} #{repos.join(' ')}")
-            yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{pkg_string}")
+            yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{pkg_string}")
           else
             raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
-                                             "and release? (version-release, e.g. 1.84-10.fc6)"
+              "and release? (version-release, e.g. 1.84-10.fc6)"
           end
         end
 
         def install_package(name, version)
           if @new_resource.source
-            yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
+            yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
           else
             install_remote_package(name, version)
           end
@@ -1219,13 +1301,17 @@ class Chef
 
         def remove_package(name, version)
           if version
-            remove_str = as_array(name).zip(as_array(version)).map do |x|
-              "#{x.join('-')}#{yum_arch}"
-            end.join(' ')
+            remove_str = as_array(name).zip(as_array(version)).map do |n, v|
+              a = arch_for_name(n)
+              "#{[n, v].join('-')}#{yum_arch(a)}"
+            end.join(" ")
           else
-            remove_str = as_array(name).map { |n| "#{n}#{yum_arch}" }.join(' ')
+            remove_str = as_array(name).map do |n|
+              a = arch_for_name(n)
+              "#{n}#{yum_arch(a)}"
+            end.join(" ")
           end
-          yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{remove_str}")
+          yum_command("-d0 -e0 -y#{expand_options(@new_resource.options)} remove #{remove_str}")
 
           if flush_cache[:after]
             @yum.reload
@@ -1240,22 +1326,26 @@ class Chef
 
         private
 
-        def parse_arch
+        def parse_arch(package_name)
           # Allow for foo.x86_64 style package_name like yum uses in it's output
           #
-          if @new_resource.package_name =~ %r{^(.*)\.(.*)$}
+          if package_name =~ %r{^(.*)\.(.*)$}
             new_package_name = $1
             new_arch = $2
             # foo.i386 and foo.beta1 are both valid package names or expressions of an arch.
             # Ensure we don't have an existing package matching package_name, then ensure we at
             # least have a match for the new_package+new_arch before we overwrite. If neither
             # then fall through to standard package handling.
-            if (@yum.installed_version(@new_resource.package_name).nil? and @yum.candidate_version(@new_resource.package_name).nil?) and
-                 (@yum.installed_version(new_package_name, new_arch) or @yum.candidate_version(new_package_name, new_arch))
-               @new_resource.package_name(new_package_name)
-               @new_resource.arch(new_arch)
+            old_installed = @yum.installed_version(package_name)
+            old_candidate = @yum.candidate_version(package_name)
+            new_installed = @yum.installed_version(new_package_name, new_arch)
+            new_candidate = @yum.candidate_version(new_package_name, new_arch)
+            if (old_installed.nil? and old_candidate.nil?) and (new_installed or new_candidate)
+              Chef::Log.debug("Parsed out arch #{new_arch}, new package name is #{new_package_name}")
+              return new_package_name, new_arch
             end
           end
+          return package_name, nil
         end
 
         # If we don't have the package we could have been passed a 'whatprovides' feature
@@ -1268,7 +1358,7 @@ class Chef
         # matching them up with an actual package so the standard resource handling can apply.
         #
         # There is currently no support for filename matching.
-        def parse_dependency(name,version)
+        def parse_dependency(name, version)
           # Transform the package_name into a requirement
 
           # If we are passed a version or a version constraint we have to assume it's a requirement first. If it can't be
@@ -1300,7 +1390,7 @@ class Chef
             new_package_name = packages.first.name
             new_package_version = packages.first.version.to_s
             debug_msg = "#{name}: Unable to match package '#{name}' but matched #{packages.size} "
-            debug_msg << packages.size == 1 ? "package" : "packages"
+            debug_msg << (packages.size == 1 ? "package" : "packages")
             debug_msg << ", selected '#{new_package_name}' version '#{new_package_version}'"
             Chef::Log.debug(debug_msg)
 
@@ -1321,7 +1411,7 @@ class Chef
               new_package_version = nil
             end
 
-            [new_package_name,new_package_version]
+            [new_package_name, new_package_version]
           end
         end
 
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index 2cd3216..2441b46 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 #
-# Authors:: Adam Jacob (<adam at opscode.com>)
+# Authors:: Adam Jacob (<adam at chef.io>)
 #           Ionuț Arțăriși (<iartarisi at suse.cz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-#             Copyright (c) 2013 SUSE Linux GmbH
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+#             Copyright 2013-2016, SUSE Linux GmbH
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,69 +19,75 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/mixin/command'
-require 'chef/resource/package'
-require 'singleton'
+require "chef/provider/package"
+require "chef/resource/zypper_package"
 
 class Chef
   class Provider
     class Package
       class Zypper < Chef::Provider::Package
+        use_multipackage_api
 
-        def load_current_resource
-          @current_resource = Chef::Resource::Package.new(@new_resource.name)
-          @current_resource.package_name(@new_resource.package_name)
-
-          is_installed=false
-          is_out_of_date=false
-          version=''
-          oud_version=''
-          Chef::Log.debug("#{@new_resource} checking zypper")
-          status = shell_out("zypper --non-interactive info #{@new_resource.package_name}")
+        provides :package, platform_family: "suse"
+        provides :zypper_package, os: "linux"
+
+        def get_versions(package_name)
+          candidate_version = current_version = nil
+          is_installed = false
+          Chef::Log.debug("#{new_resource} checking zypper")
+          status = shell_out_with_timeout!("zypper --non-interactive info #{package_name}")
           status.stdout.each_line do |line|
             case line
             when /^Version: (.+)$/
-              version = $1
-              Chef::Log.debug("#{@new_resource} version #{$1}")
+              candidate_version = $1
+              Chef::Log.debug("#{new_resource} version #{$1}")
             when /^Installed: Yes$/
-              is_installed=true
-              Chef::Log.debug("#{@new_resource} is installed")
-
-            when /^Installed: No$/
-              is_installed=false
-              Chef::Log.debug("#{@new_resource} is not installed")
+              is_installed = true
+              Chef::Log.debug("#{new_resource} is installed")
             when /^Status: out-of-date \(version (.+) installed\)$/
-              is_out_of_date=true
-              oud_version=$1
-              Chef::Log.debug("#{@new_resource} out of date version #{$1}")
+              current_version = $1
+              Chef::Log.debug("#{new_resource} out of date version #{$1}")
             end
           end
+          current_version = candidate_version if is_installed
+          { current_version: current_version, candidate_version: candidate_version }
+        end
 
-          if is_installed==false
-            @candidate_version=version
-            @current_resource.version(nil)
-          end
-
-          if is_installed==true
-            if is_out_of_date==true
-              @current_resource.version(oud_version)
-              @candidate_version=version
-            else
-              @current_resource.version(version)
-              @candidate_version=version
+        def versions
+          @versions =
+            begin
+              raw_versions = package_name_array.map do |package_name|
+                get_versions(package_name)
+              end
+              Hash[*package_name_array.zip(raw_versions).flatten]
             end
+        end
+
+        def get_candidate_versions
+          package_name_array.map do |package_name|
+            versions[package_name][:candidate_version]
           end
+        end
 
-          unless status.exitstatus == 0
-            raise Chef::Exceptions::Package, "zypper failed - #{status.inspect}!"
+        def get_current_versions
+          package_name_array.map do |package_name|
+            versions[package_name][:current_version]
           end
+        end
+
+        def load_current_resource
+          @current_resource = Chef::Resource::ZypperPackage.new(new_resource.name)
+          current_resource.package_name(new_resource.package_name)
+
+          @candidate_version = get_candidate_versions
+          current_resource.version(get_current_versions)
 
-          @current_resource
+          current_resource
         end
 
-        def zypper_version()
-          `zypper -V 2>&1`.scan(/\d+/).join(".").to_f
+        def zypper_version
+          @zypper_version ||=
+            `zypper -V 2>&1`.scan(/\d+/).join(".").to_f
         end
 
         def install_package(name, version)
@@ -89,6 +95,7 @@ class Chef
         end
 
         def upgrade_package(name, version)
+          # `zypper install` upgrades packages, we rely on the idempotency checks to get action :install behavior
           install_package(name, version)
         end
 
@@ -101,13 +108,19 @@ class Chef
         end
 
         private
-        def zypper_package(command, pkgname, version)
-          version = "=#{version}" unless version.nil? || version.empty?
+
+        def zip(names, versions)
+          names.zip(versions).map do |n, v|
+            (v.nil? || v.empty?) ? n : "#{n}=#{v}"
+          end
+        end
+
+        def zypper_package(command, names, versions)
+          zipped_names = zip(names, versions)
           if zypper_version < 1.0
-            shell_out!("zypper#{gpg_checks} #{command} -y #{pkgname}")
+            shell_out_with_timeout!(a_to_s("zypper", gpg_checks, command, "-y", names))
           else
-            shell_out!("zypper --non-interactive#{gpg_checks} "+
-                      "#{command} #{pkgname}#{version}")
+            shell_out_with_timeout!(a_to_s("zypper --non-interactive", gpg_checks, command, zipped_names))
           end
         end
 
@@ -116,12 +129,12 @@ class Chef
           when true
             ""
           when false
-            " --no-gpg-checks"
+            "--no-gpg-checks"
           when nil
             Chef::Log.warn("Chef::Config[:zypper_check_gpg] was not set. " +
               "All packages will be installed without gpg signature checks. " +
               "This is a security hazard.")
-            " --no-gpg-checks"
+            "--no-gpg-checks"
           end
         end
       end
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index f9dcd6d..6365f6a 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/provider/windows_script'
+require "chef/platform/query_helpers"
+require "chef/provider/windows_script"
 
 class Chef
   class Provider
@@ -24,71 +25,191 @@ class Chef
 
       provides :powershell_script, os: "windows"
 
+      def initialize(new_resource, run_context)
+        super(new_resource, run_context, ".ps1")
+        add_exit_status_wrapper
+      end
+
+      def action_run
+        validate_script_syntax!
+        super
+      end
+
+      def command
+        basepath = is_forced_32bit ? wow64_directory : run_context.node.kernel.os_info.system_directory
+
+        # Powershell.exe is always in "v1.0" folder (for backwards compatibility)
+        interpreter_path = Chef::Util::PathHelper.join(basepath, "WindowsPowerShell", "v1.0", interpreter)
+
+        # Must use -File rather than -Command to launch the script
+        # file created by the base class that contains the script
+        # code -- otherwise, powershell.exe does not propagate the
+        # error status of a failed Windows process that ran at the
+        # end of the script, it gets changed to '1'.
+        #
+        # Nano only supports -Command
+        cmd = "\"#{interpreter_path}\" #{flags}"
+        if Chef::Platform.windows_nano_server?
+          cmd << " -Command \". '#{script_file.path}'\""
+        else
+          cmd << " -File \"#{script_file.path}\""
+        end
+        cmd
+      end
+
+      def flags
+        interpreter_flags = [*default_interpreter_flags].join(" ")
+
+        if ! (@new_resource.flags.nil?)
+          interpreter_flags = [@new_resource.flags, interpreter_flags].join(" ")
+        end
+
+        interpreter_flags
+      end
+
       protected
-      EXIT_STATUS_EXCEPTION_HANDLER = "\ntrap [Exception] {write-error -exception ($_.Exception.Message);exit 1}".freeze
-      EXIT_STATUS_NORMALIZATION_SCRIPT = "\nif ($? -ne $true) { if ( $LASTEXITCODE ) {exit $LASTEXITCODE} else { exit 1 }}".freeze
-      EXIT_STATUS_RESET_SCRIPT = "\n$global:LASTEXITCODE=$null".freeze
 
-      # Process exit codes are strange with PowerShell. Unless you
-      # explicitly call exit in Powershell, the powershell.exe
-      # interpreter returns only 0 for success or 1 for failure. Since
-      # we'd like to get specific exit codes from executable tools run
-      # with Powershell, we do some work using the automatic variables
-      # $? and $LASTEXITCODE to return the process exit code of the
-      # last process run in the script if it is the last command
-      # executed, otherwise 0 or 1 based on whether $? is set to true
-      # (success, where we return 0) or false (where we return 1).
-      def normalize_script_exit_status( code )
-        target_code = ( EXIT_STATUS_EXCEPTION_HANDLER +
-                        EXIT_STATUS_RESET_SCRIPT +
-                        "\n" +
-                        code.to_s +
-                        EXIT_STATUS_NORMALIZATION_SCRIPT )
-        convert_boolean_return = @new_resource.convert_boolean_return
-        self.code = <<EOH
-new-variable -name interpolatedexitcode -visibility private -value $#{convert_boolean_return}
-new-variable -name chefscriptresult -visibility private
-$chefscriptresult = {
-#{target_code}
-}.invokereturnasis()
-if ($interpolatedexitcode -and $chefscriptresult.gettype().name -eq 'boolean') { exit [int32](!$chefscriptresult) } else { exit 0 }
-EOH
-        Chef::Log.debug("powershell_script provider called with script code:\n\n#{code}\n")
+      # Process exit codes are strange with PowerShell and require
+      # special handling to cover common use cases.
+      def add_exit_status_wrapper
+        self.code = wrapper_script
+        Chef::Log.debug("powershell_script provider called with script code:\n\n#{@new_resource.code}\n")
         Chef::Log.debug("powershell_script provider will execute transformed code:\n\n#{self.code}\n")
       end
 
-      public
+      def validate_script_syntax!
+        interpreter_arguments = default_interpreter_flags.join(" ")
+        Tempfile.open(["chef_powershell_script-user-code", ".ps1"]) do |user_script_file|
+          # Wrap the user's code in a PowerShell script block so that
+          # it isn't executed. However, syntactically invalid script
+          # in that block will still trigger a syntax error which is
+          # exactly what we want here -- verify the syntax without
+          # actually running the script.
+          user_code_wrapped_in_powershell_script_block = <<-EOH
+{
+  #{@new_resource.code}
+}
+EOH
+          user_script_file.puts user_code_wrapped_in_powershell_script_block
+
+          # A .close or explicit .flush required to ensure the file is
+          # written to the file system at this point, which is required since
+          # the intent is to execute the code just written to it.
+          user_script_file.close
+          validation_command = "\"#{interpreter}\" #{interpreter_arguments} -Command \". '#{user_script_file.path}'\""
 
-      def initialize (new_resource, run_context)
-        super(new_resource, run_context, '.ps1')
-        normalize_script_exit_status(new_resource.code)
+          # Note that other script providers like bash allow syntax errors
+          # to be suppressed by setting 'returns' to a value that the
+          # interpreter would return as a status code in the syntax
+          # error case. We explicitly don't do this here -- syntax
+          # errors will not be suppressed, since doing so could make
+          # it harder for users to detect / debug invalid scripts.
+
+          # Therefore, the only return value for a syntactically valid
+          # script is 0. If an exception is raised by shellout, this
+          # means a non-zero return and thus a syntactically invalid script.
+
+          with_os_architecture(node, architecture: new_resource.architecture) do
+            shell_out!(validation_command, { returns: [0] })
+          end
+        end
       end
 
-      def flags
-        default_flags = [
+      def default_interpreter_flags
+        return [] if Chef::Platform.windows_nano_server?
+
+        # Execution policy 'Bypass' is preferable since it doesn't require
+        # user input confirmation for files such as PowerShell modules
+        # downloaded from the Internet. However, 'Bypass' is not supported
+        # prior to PowerShell 3.0, so the fallback is 'Unrestricted'
+        execution_policy = Chef::Platform.supports_powershell_execution_bypass?(run_context.node) ? "Bypass" : "Unrestricted"
+
+        [
           "-NoLogo",
           "-NonInteractive",
           "-NoProfile",
-          "-ExecutionPolicy Unrestricted",
+          "-ExecutionPolicy #{execution_policy}",
           # Powershell will hang if STDIN is redirected
           # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected
           "-InputFormat None",
-          # Must use -File rather than -Command to launch the script
-          # file created by the base class that contains the script
-          # code -- otherwise, powershell.exe does not propagate the
-          # error status of a failed Windows process that ran at the
-          # end of the script, it gets changed to '1'.
-          "-File"
         ]
+      end
+
+      # A wrapper script is used to launch user-supplied script while
+      # still obtaining useful process exit codes. Unless you
+      # explicitly call exit in Powershell, the powershell.exe
+      # interpreter returns only 0 for success or 1 for failure. Since
+      # we'd like to get specific exit codes from executable tools run
+      # with Powershell, we do some work using the automatic variables
+      # $? and $LASTEXITCODE to return the process exit code of the
+      # last process run in the script if it is the last command
+      # executed, otherwise 0 or 1 based on whether $? is set to true
+      # (success, where we return 0) or false (where we return 1).
+      def wrapper_script
+        <<-EOH
+# Chef Client wrapper for powershell_script resources
 
-        interpreter_flags = default_flags.join(' ')
+# LASTEXITCODE can be uninitialized -- make it explictly 0
+# to avoid incorrect detection of failure (non-zero) codes
+$global:LASTEXITCODE = 0
 
-        if ! (@new_resource.flags.nil?)
-          interpreter_flags = [@new_resource.flags, interpreter_flags].join(' ')
-        end
+# Catch any exceptions -- without this, exceptions will result
+# In a zero return code instead of the desired non-zero code
+# that indicates a failure
+trap [Exception] {write-error ($_.Exception.Message);exit 1}
 
-        interpreter_flags
+# Variable state that should not be accessible to the user code
+new-variable -name interpolatedexitcode -visibility private -value $#{@new_resource.convert_boolean_return}
+new-variable -name chefscriptresult -visibility private
+
+# Initialize a variable we use to capture $? inside a block
+$global:lastcmdlet = $null
+
+# Execute the user's code in a script block --
+$chefscriptresult =
+{
+ #{@new_resource.code}
+
+ # This assignment doesn't affect the block's return value
+ $global:lastcmdlet = $?
+}.invokereturnasis()
+
+# Assume failure status of 1 -- success cases
+# will have to override this
+$exitstatus = 1
+
+# If convert_boolean_return is enabled, the block's return value
+# gets precedence in determining our exit status
+if ($interpolatedexitcode -and $chefscriptresult -ne $null -and $chefscriptresult.gettype().name -eq 'boolean')
+{
+  $exitstatus = [int32](!$chefscriptresult)
+}
+elseif ($lastcmdlet)
+{
+  # Otherwise, a successful cmdlet execution defines the status
+  $exitstatus = 0
+}
+elseif ( $LASTEXITCODE -ne $null -and $LASTEXITCODE -ne 0 )
+{
+  # If the cmdlet status is failed, allow the Win32 status
+  # in $LASTEXITCODE to define exit status. This handles the case
+  # where no cmdlets, only Win32 processes have run since $?
+  # will be set to $false whenever a Win32 process returns a non-zero
+  # status.
+  $exitstatus = $LASTEXITCODE
+}
+
+# Print STDOUT for the script execution
+Write-Output $chefscriptresult
+
+# If this script is launched with -File, the process exit
+# status of PowerShell.exe will be $exitstatus. If it was
+# launched with -Command, it will be 0 if $exitstatus was 0,
+# 1 (i.e. failed) otherwise.
+exit $exitstatus
+EOH
       end
+
     end
   end
 end
diff --git a/lib/chef/provider/reboot.rb b/lib/chef/provider/reboot.rb
index 8dde465..11039f8 100644
--- a/lib/chef/provider/reboot.rb
+++ b/lib/chef/provider/reboot.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Chris Doherty <cdoherty at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/provider'
+require "chef/log"
+require "chef/provider"
 
 class Chef
   class Provider
     class Reboot < Chef::Provider
+      provides :reboot
 
       def whyrun_supported?
         true
@@ -39,7 +40,7 @@ class Chef
           :delay_mins => @new_resource.delay_mins,
           :reason => @new_resource.reason,
           :timestamp => Time.now,
-          :requested_by => @new_resource.name
+          :requested_by => @new_resource.name,
           )
       end
 
diff --git a/lib/chef/provider/registry_key.rb b/lib/chef/provider/registry_key.rb
index 94f4e26..2e00fd0 100644
--- a/lib/chef/provider/registry_key.rb
+++ b/lib/chef/provider/registry_key.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
 #
-# Copyright:: 2011, Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,20 +17,22 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/log'
-require 'chef/resource/file'
-require 'chef/mixin/checksum'
-require 'chef/provider'
-require 'etc'
-require 'fileutils'
-require 'chef/scan_access_control'
-require 'chef/win32/registry'
+require "chef/config"
+require "chef/log"
+require "chef/resource/file"
+require "chef/mixin/checksum"
+require "chef/provider"
+require "etc"
+require "fileutils"
+require "chef/scan_access_control"
+require "chef/win32/registry"
 
 class Chef
 
   class Provider
     class RegistryKey < Chef::Provider
+      provides :registry_key
+
       include Chef::Mixin::Checksum
 
       def whyrun_supported?
@@ -62,7 +64,7 @@ class Chef
 
       def values_to_hash(values)
         if values
-          @name_hash = Hash[values.map { |val| [val[:name], val] }]
+          @name_hash = Hash[values.map { |val| [val[:name].downcase, val] }]
         else
           @name_hash = {}
         end
@@ -70,22 +72,22 @@ class Chef
 
       def define_resource_requirements
         requirements.assert(:create, :create_if_missing, :delete, :delete_key) do |a|
-          a.assertion{ registry.hive_exists?(@new_resource.key) }
+          a.assertion { registry.hive_exists?(@new_resource.key) }
           a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{@new_resource.key.split("\\").shift} does not exist")
         end
         requirements.assert(:create) do |a|
-          a.assertion{ registry.key_exists?(@new_resource.key) }
+          a.assertion { registry.key_exists?(@new_resource.key) }
           a.whyrun("Key #{@new_resource.key} does not exist. Unless it would have been created before, attempt to modify its values would fail.")
         end
         requirements.assert(:create, :create_if_missing) do |a|
           #If keys missing in the path and recursive == false
-          a.assertion{ !registry.keys_missing?(@current_resource.key) || @new_resource.recursive }
+          a.assertion { !registry.keys_missing?(@current_resource.key) || @new_resource.recursive }
           a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "Intermediate keys missing but recursive is set to false")
           a.whyrun("Intermediate keys in #{@new_resource.key} go not exist. Unless they would have been created earlier, attempt to modify them would fail.")
         end
         requirements.assert(:delete_key) do |a|
           #If key to be deleted has subkeys but recurssive == false
-          a.assertion{ !registry.key_exists?(@new_resource.key) || !registry.has_subkeys?(@new_resource.key) || @new_resource.recursive }
+          a.assertion { !registry.key_exists?(@new_resource.key) || !registry.has_subkeys?(@new_resource.key) || @new_resource.recursive }
           a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "#{@new_resource.key} has subkeys but recursive is set to false.")
           a.whyrun("#{@current_resource.key} has subkeys, but recursive is set to false. attempt to delete would fails unless subkeys were deleted prior to this action.")
         end
@@ -98,8 +100,8 @@ class Chef
           end
         end
         @new_resource.unscrubbed_values.each do |value|
-          if @name_hash.has_key?(value[:name])
-            current_value = @name_hash[value[:name]]
+          if @name_hash.has_key?(value[:name].downcase)
+            current_value = @name_hash[value[:name].downcase]
             unless current_value[:type] == value[:type] && current_value[:data] == value[:data]
               converge_by("set value #{value}") do
                 registry.set_value(@new_resource.key, value)
@@ -120,7 +122,7 @@ class Chef
           end
         end
         @new_resource.unscrubbed_values.each do |value|
-          unless @name_hash.has_key?(value[:name])
+          unless @name_hash.has_key?(value[:name].downcase)
             converge_by("create value #{value}") do
               registry.set_value(@new_resource.key, value)
             end
@@ -131,7 +133,7 @@ class Chef
       def action_delete
         if registry.key_exists?(@new_resource.key)
           @new_resource.unscrubbed_values.each do |value|
-            if @name_hash.has_key?(value[:name])
+            if @name_hash.has_key?(value[:name].downcase)
               converge_by("delete value #{value}") do
                 registry.delete_value(@new_resource.key, value)
               end
diff --git a/lib/chef/provider/remote_directory.rb b/lib/chef/provider/remote_directory.rb
index eaccce4..b592b13 100644
--- a/lib/chef/provider/remote_directory.rb
+++ b/lib/chef/provider/remote_directory.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,178 +16,266 @@
 # limitations under the License.
 #
 
-require 'chef/provider/file'
-require 'chef/provider/directory'
-require 'chef/resource/directory'
-require 'chef/resource/remote_file'
-require 'chef/mixin/file_class'
-require 'chef/platform'
-require 'uri'
-require 'tempfile'
-require 'net/https'
-require 'set'
-require 'chef/util/path_helper'
+require "chef/provider/directory"
+require "chef/resource/file"
+require "chef/resource/directory"
+require "chef/resource/cookbook_file"
+require "chef/mixin/file_class"
+require "chef/platform/query_helpers"
+require "chef/util/path_helper"
+require "chef/deprecation/warnings"
+require "chef/deprecation/provider/remote_directory"
+
+require "forwardable"
 
 class Chef
   class Provider
     class RemoteDirectory < Chef::Provider::Directory
+      extend Forwardable
+      include Chef::Mixin::FileClass
 
       provides :remote_directory
 
-      include Chef::Mixin::FileClass
+      def_delegators :@new_resource, :purge, :path, :source, :cookbook, :cookbook_name
+      def_delegators :@new_resource, :files_rights, :files_mode, :files_group, :files_owner, :files_backup
+      def_delegators :@new_resource, :rights, :mode, :group, :owner
+
+      # The overwrite property on the resource.  Delegates to new_resource but can be mutated.
+      #
+      # @return [Boolean] if we are overwriting
+      #
+      def overwrite?
+        @overwrite = new_resource.overwrite if @overwrite.nil?
+        !!@overwrite
+      end
+
+      attr_accessor :managed_files
+
+      # Hash containing keys of the paths for all the files that we sync, plus all their
+      # parent directories.
+      #
+      # @return [Set] Ruby Set of the files that we manage
+      #
+      def managed_files
+        @managed_files ||= Set.new
+      end
 
+      # Handle action :create.
+      #
       def action_create
         super
-        # Mark all files as needing to be purged
-        files_to_purge = Set.new(ls(@new_resource.path)) # Make sure each path is clean
 
         # Transfer files
         files_to_transfer.each do |cookbook_file_relative_path|
           create_cookbook_file(cookbook_file_relative_path)
-          # parent directories and file being transferred are removed from the purge list
-          Pathname.new(Chef::Util::PathHelper.cleanpath(::File.join(@new_resource.path, cookbook_file_relative_path))).descend do |d|
-            files_to_purge.delete(d.to_s)
-          end
+          # parent directories and file being transferred need to not be removed in the purge
+          add_managed_file(cookbook_file_relative_path)
         end
 
-        purge_unmanaged_files(files_to_purge)
+        purge_unmanaged_files
       end
 
+      # Handle action :create_if_missing.
+      #
       def action_create_if_missing
         # if this action is called, ignore the existing overwrite flag
-        @new_resource.overwrite(false)
+        @overwrite = false
         action_create
       end
 
-      protected
+      private
 
-      # List all excluding . and ..
-      def ls(path)
-        files = Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), '**', '*'),
-                 ::File::FNM_DOTMATCH)
-
-        # Remove current directory and previous directory
-        files.reject! do |name|
-          basename = Pathname.new(name).basename().to_s
-          ['.', '..'].include?(basename)
+      # Add a file and its parent directories to the managed_files Hash.
+      #
+      # @param [String] cookbook_file_relative_path relative path to the file
+      # @api private
+      #
+      def add_managed_file(cookbook_file_relative_path)
+        if purge
+          Pathname.new(Chef::Util::PathHelper.cleanpath(::File.join(path, cookbook_file_relative_path))).descend do |d|
+            managed_files.add(d.to_s)
+          end
         end
-
-        # Clean all the paths... this is required because of the join
-        files.map {|f| Chef::Util::PathHelper.cleanpath(f)}
       end
 
-      def purge_unmanaged_files(unmanaged_files)
-        if @new_resource.purge
-          unmanaged_files.sort.reverse.each do |f|
-            # file_class comes from Chef::Mixin::FileClass
-            if ::File.directory?(f) && !Chef::Platform.windows? && !file_class.symlink?(f.dup)
-              # Linux treats directory symlinks as files
-              # Remove a directory as a directory when not on windows if it is not a symlink
-              purge_directory(f)
-            elsif ::File.directory?(f) && Chef::Platform.windows?
-              # Windows treats directory symlinks as directories so we delete them here
-              purge_directory(f)
-            else
-              converge_by("delete unmanaged file #{f}") do
-                ::File.delete(f)
-                Chef::Log.debug("#{@new_resource} deleted file #{f}")
+      # Remove all files not in the managed_files Set.
+      #
+      # @api private
+      #
+      def purge_unmanaged_files
+        if purge
+          Dir.glob(::File.join(Chef::Util::PathHelper.escape_glob(path), "**", "*"), ::File::FNM_DOTMATCH).sort!.reverse!.each do |file|
+            # skip '.' and '..'
+            next if [".", ".."].include?(Pathname.new(file).basename().to_s)
+
+            # Clean the path.  This is required because of the ::File.join
+            file = Chef::Util::PathHelper.cleanpath(file)
+
+            # Skip files that we've sync'd and their parent dirs
+            next if managed_files.include?(file)
+
+            if ::File.directory?(file)
+              if !Chef::Platform.windows? && file_class.symlink?(file.dup)
+                # Unix treats dir symlinks as files
+                purge_file(file)
+              else
+                # Unix dirs are dirs, Windows dirs and dir symlinks are dirs
+                purge_directory(file)
               end
+            else
+              purge_file(file)
             end
           end
         end
       end
 
+      # Use a Chef directory sub-resource to remove a directory.
+      #
+      # @param [String] dir The path of the directory to remove
+      # @api private
+      #
       def purge_directory(dir)
-        converge_by("delete unmanaged directory #{dir}") do
-          Dir::rmdir(dir)
-          Chef::Log.debug("#{@new_resource} removed directory #{dir}")
-        end
+        res = Chef::Resource::Directory.new(dir, run_context)
+        res.run_action(:delete)
+        new_resource.updated_by_last_action(true) if res.updated?
       end
 
+      # Use a Chef file sub-resource to remove a file.
+      #
+      # @param [String] file The path of the file to remove
+      # @api private
+      #
+      def purge_file(file)
+        res = Chef::Resource::File.new(file, run_context)
+        res.run_action(:delete)
+        new_resource.updated_by_last_action(true) if res.updated?
+      end
+
+      # Get the files to tranfer.  This returns files in lexicographical sort order.
+      #
+      # FIXME: it should do breadth-first, see CHEF-5080 (please use a performant sort)
+      #
+      # @return Array<String> The list of files to transfer
+      # @api private
+      #
       def files_to_transfer
         cookbook = run_context.cookbook_collection[resource_cookbook]
-        files = cookbook.relative_filenames_in_preferred_directory(node, :files, @new_resource.source)
-        files.sort.reverse
+        files = cookbook.relative_filenames_in_preferred_directory(node, :files, source)
+        files.sort_by! { |x| x.count(::File::SEPARATOR) }
       end
 
-      def directory_root_in_cookbook_cache
-        @directory_root_in_cookbook_cache ||= begin
-          cookbook = run_context.cookbook_collection[resource_cookbook]
-          cookbook.preferred_filename_on_disk_location(node, :files, @new_resource.source, @new_resource.path)
-        end
+      # Either the explicit cookbook that the user sets on the resource, or the implicit
+      # cookbook_name that the resource was declared in.
+      #
+      # @return [String] Cookbook to get file from.
+      # @api private
+      #
+      def resource_cookbook
+        cookbook || cookbook_name
       end
 
-      # Determine the cookbook to get the file from. If new resource sets an
-      # explicit cookbook, use it, otherwise fall back to the implicit cookbook
-      # i.e., the cookbook the resource was declared in.
-      def resource_cookbook
-        @new_resource.cookbook || @new_resource.cookbook_name
+      # If we are overwriting, then cookbook_file sub-resources should all be action :create,
+      # otherwise they should be :create_if_missing
+      #
+      # @return [Symbol] Action to take on cookbook_file sub-resources
+      # @api private
+      #
+      def action_for_cookbook_file
+        overwrite? ? :create : :create_if_missing
       end
 
+      # This creates and uses a cookbook_file resource to sync a single file from the cookbook.
+      #
+      # @param [String] cookbook_file_relative_path The relative path to the cookbook file
+      # @api private
+      #
       def create_cookbook_file(cookbook_file_relative_path)
-        full_path = ::File.join(@new_resource.path, cookbook_file_relative_path)
+        full_path = ::File.join(path, cookbook_file_relative_path)
 
         ensure_directory_exists(::File.dirname(full_path))
 
-        file_to_fetch = cookbook_file_resource(full_path, cookbook_file_relative_path)
-        if @new_resource.overwrite
-          file_to_fetch.run_action(:create)
-        else
-          file_to_fetch.run_action(:create_if_missing)
-        end
-        @new_resource.updated_by_last_action(true) if file_to_fetch.updated?
+        res = cookbook_file_resource(full_path, cookbook_file_relative_path)
+        res.run_action(action_for_cookbook_file)
+        new_resource.updated_by_last_action(true) if res.updated?
       end
 
+      # This creates the cookbook_file resource for use by create_cookbook_file.
+      #
+      # @param [String] target_path Path on the system to create
+      # @param [String] relative_source_path Relative path in the cookbook to the base source
+      # @return [Chef::Resource::CookbookFile] The built cookbook_file resource
+      # @api private
+      #
       def cookbook_file_resource(target_path, relative_source_path)
-        cookbook_file = Chef::Resource::CookbookFile.new(target_path, run_context)
-        cookbook_file.cookbook_name = @new_resource.cookbook || @new_resource.cookbook_name
-        cookbook_file.source(::File.join(@new_resource.source, relative_source_path))
-        if Chef::Platform.windows? && @new_resource.files_rights
-          @new_resource.files_rights.each_pair do |permission, *args|
-            cookbook_file.rights(permission, *args)
+        res = Chef::Resource::CookbookFile.new(target_path, run_context)
+        res.cookbook_name = resource_cookbook
+        res.source(::File.join(source, relative_source_path))
+        if Chef::Platform.windows? && files_rights
+          files_rights.each_pair do |permission, *args|
+            res.rights(permission, *args)
           end
         end
-        cookbook_file.mode(@new_resource.files_mode)       if @new_resource.files_mode
-        cookbook_file.group(@new_resource.files_group)     if @new_resource.files_group
-        cookbook_file.owner(@new_resource.files_owner)     if @new_resource.files_owner
-        cookbook_file.backup(@new_resource.files_backup)   if @new_resource.files_backup
+        res.mode(files_mode)       if files_mode
+        res.group(files_group)     if files_group
+        res.owner(files_owner)     if files_owner
+        res.backup(files_backup)   if files_backup
 
-        cookbook_file
+        res
       end
 
-      def ensure_directory_exists(path)
-        unless ::File.directory?(path)
-          directory_to_create = resource_for_directory(path)
-          directory_to_create.run_action(:create)
-          @new_resource.updated_by_last_action(true) if directory_to_create.updated?
+      # This creates and uses a directory resource to create a directory if it is needed.
+      #
+      # @param [String] dir The path to the directory to create.
+      # @api private
+      #
+      def ensure_directory_exists(dir)
+        # doing the check here and skipping the resource should be more performant
+        unless ::File.directory?(dir)
+          res = directory_resource(dir)
+          res.run_action(:create)
+          new_resource.updated_by_last_action(true) if res.updated?
         end
       end
 
-      def resource_for_directory(path)
-        dir = Chef::Resource::Directory.new(path, run_context)
-        dir.cookbook_name = @new_resource.cookbook || @new_resource.cookbook_name
-        if Chef::Platform.windows? && @new_resource.rights
+      # This creates the directory resource for ensure_directory_exists.
+      #
+      # @param [String] dir Directory path on the system
+      # @return [Chef::Resource::Directory] The built directory resource
+      # @api private
+      #
+      def directory_resource(dir)
+        res = Chef::Resource::Directory.new(dir, run_context)
+        res.cookbook_name = resource_cookbook
+        if Chef::Platform.windows? && rights
           # rights are only meant to be applied to the toppest-level directory;
           # Windows will handle inheritance.
-          if path == @new_resource.path
-            @new_resource.rights.each do |rights| #rights is a hash
-              permissions = rights.delete(:permissions) #delete will return the value or nil if not found
-              principals = rights.delete(:principals)
-              dir.rights(permissions, principals, rights)
+          if dir == path
+            rights.each do |r|
+              r = r.dup # do not update the new_resource
+              permissions = r.delete(:permissions)
+              principals = r.delete(:principals)
+              res.rights(permissions, principals, r)
             end
           end
         end
-        dir.mode(@new_resource.mode) if @new_resource.mode
-        dir.group(@new_resource.group)
-        dir.owner(@new_resource.owner)
-        dir.recursive(true)
-        dir
-      end
+        res.mode(mode) if mode
+        res.group(group) if group
+        res.owner(owner) if owner
+        res.recursive(true)
 
-      def whyrun_supported?
-        true
+        res
       end
 
+      #
+      # Add back deprecated methods and aliases that are internally unused and should be removed in Chef-13
+      #
+      extend Chef::Deprecation::Warnings
+      include Chef::Deprecation::Provider::RemoteDirectory
+      add_deprecation_warnings_for(Chef::Deprecation::Provider::RemoteDirectory.instance_methods)
+
+      alias_method :resource_for_directory, :directory_resource
+      add_deprecation_warnings_for([:resource_for_directory])
+
     end
   end
 end
diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb
index da2573d..9207e62 100644
--- a/lib/chef/provider/remote_file.rb
+++ b/lib/chef/provider/remote_file.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,14 @@
 # limitations under the License.
 #
 
-require 'chef/provider/file'
-require 'chef/deprecation/provider/remote_file'
-require 'chef/deprecation/warnings'
+require "chef/provider/file"
+require "chef/deprecation/provider/remote_file"
+require "chef/deprecation/warnings"
 
 class Chef
   class Provider
     class RemoteFile < Chef::Provider::File
+      provides :remote_file
 
       extend Chef::Deprecation::Warnings
       include Chef::Deprecation::Provider::RemoteFile
diff --git a/lib/chef/provider/remote_file/cache_control_data.rb b/lib/chef/provider/remote_file/cache_control_data.rb
index f9b7293..7aa059f 100644
--- a/lib/chef/provider/remote_file/cache_control_data.rb
+++ b/lib/chef/provider/remote_file/cache_control_data.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Jesse Campbell
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,11 +19,11 @@
 # limitations under the License.
 #
 
-require 'stringio'
-require 'chef/file_cache'
-require 'chef/json_compat'
-require 'chef/digester'
-require 'chef/exceptions'
+require "stringio"
+require "chef/file_cache"
+require "chef/json_compat"
+require "chef/digester"
+require "chef/exceptions"
 
 class Chef
   class Provider
@@ -145,18 +145,50 @@ class Chef
         end
 
         def load_json_data
-          Chef::FileCache.load("remote_file/#{sanitized_cache_file_basename}")
+          path = sanitized_cache_file_path(sanitized_cache_file_basename)
+          if Chef::FileCache.has_key?(path)
+            Chef::FileCache.load(path)
+          else
+            old_path = sanitized_cache_file_path(sanitized_cache_file_basename_md5)
+            if Chef::FileCache.has_key?(old_path)
+              # We found an old cache control data file. We started using sha256 instead of md5
+              # to name these. Upgrade the file to the new name.
+              Chef::Log.debug("Found old cache control data file at #{old_path}. Moving to #{path}.")
+              Chef::FileCache.load(old_path).tap do |data|
+                Chef::FileCache.store(path, data)
+                Chef::FileCache.delete(old_path)
+              end
+            else
+              raise Chef::Exceptions::FileNotFound
+            end
+          end
         end
 
-        def sanitized_cache_file_basename
+        def sanitized_cache_file_path(basename)
+          "remote_file/#{basename}"
+        end
+
+        def scrubbed_uri
           # Scrub and truncate in accordance with the goals of keeping the name
           # human-readable but within the bounds of local file system
           # path length limits
-          scrubbed_uri = uri.gsub(/\W/, '_')[0..63]
+          uri.gsub(/\W/, "_")[0..63]
+        end
+
+        def sanitized_cache_file_basename
+          uri_sha2 = Chef::Digester.instance.generate_checksum(StringIO.new(uri))
+          cache_file_basename(uri_sha2[0, 32])
+        end
+
+        def sanitized_cache_file_basename_md5
+          # Old way of creating the file basename
           uri_md5 = Chef::Digester.instance.generate_md5_checksum(StringIO.new(uri))
-          "#{scrubbed_uri}-#{uri_md5}.json"
+          cache_file_basename(uri_md5)
         end
 
+        def cache_file_basename(checksum)
+          "#{scrubbed_uri}-#{checksum}.json"
+        end
       end
     end
   end
diff --git a/lib/chef/provider/remote_file/content.rb b/lib/chef/provider/remote_file/content.rb
index ef55dd7..e440964 100644
--- a/lib/chef/provider/remote_file/content.rb
+++ b/lib/chef/provider/remote_file/content.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,10 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'tempfile'
-require 'chef/file_content_management/content_base'
+require "uri"
+require "tempfile"
+require "chef/file_content_management/content_base"
+require "chef/mixin/uris"
 
 class Chef
   class Provider
@@ -28,6 +29,8 @@ class Chef
 
         private
 
+        include Chef::Mixin::Uris
+
         def file_for_provider
           Chef::Log.debug("#{@new_resource} checking for changes")
 
@@ -45,10 +48,14 @@ class Chef
           sources = sources.dup
           source = sources.shift
           begin
-            uri = URI.parse(source)
+            uri = if Chef::Provider::RemoteFile::Fetcher.network_share?(source)
+                    source
+                  else
+                    as_uri(source)
+                  end
             raw_file = grab_file_from_uri(uri)
           rescue SocketError, Errno::ECONNREFUSED, Errno::ENOENT, Errno::EACCES, Timeout::Error, Net::HTTPServerException, Net::HTTPFatalError, Net::FTPError => e
-            Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e.to_s}")
+            Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e}")
             if source = sources.shift
               Chef::Log.info("#{@new_resource} trying to download from another mirror")
               retry
diff --git a/lib/chef/provider/remote_file/fetcher.rb b/lib/chef/provider/remote_file/fetcher.rb
index 249b291..dad73cf 100644
--- a/lib/chef/provider/remote_file/fetcher.rb
+++ b/lib/chef/provider/remote_file/fetcher.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,15 +23,29 @@ class Chef
       class Fetcher
 
         def self.for_resource(uri, new_resource, current_resource)
-          case uri.scheme
-          when "http", "https"
-            Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource)
-          when "ftp"
-            Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource)
-          when "file"
-            Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource)
+          if network_share?(uri)
+            Chef::Provider::RemoteFile::NetworkFile.new(uri, new_resource, current_resource)
           else
-            raise ArgumentError, "Invalid uri, Only http(s), ftp, and file are currently supported"
+            case uri.scheme
+            when "http", "https"
+              Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource)
+            when "ftp"
+              Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource)
+            when "file"
+              Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource)
+            else
+              raise ArgumentError, "Invalid uri, Only http(s), ftp, and file are currently supported"
+            end
+          end
+        end
+
+        # Windows network share: \\computername\share\file
+        def self.network_share?(source)
+          case source
+          when String
+            !!(%r{\A\\\\[A-Za-z0-9+\-\.]+} =~ source)
+          else
+            false
           end
         end
 
diff --git a/lib/chef/provider/remote_file/ftp.rb b/lib/chef/provider/remote_file/ftp.rb
index 3f78286..448acdb 100644
--- a/lib/chef/provider/remote_file/ftp.rb
+++ b/lib/chef/provider/remote_file/ftp.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'tempfile'
-require 'net/ftp'
-require 'chef/provider/remote_file'
-require 'chef/file_content_management/tempfile'
+require "uri"
+require "tempfile"
+require "net/ftp"
+require "chef/provider/remote_file"
+require "chef/file_content_management/tempfile"
 
 class Chef
   class Provider
@@ -59,7 +59,7 @@ class Chef
           if uri.userinfo
             URI.unescape(uri.user)
           else
-            'anonymous'
+            "anonymous"
           end
         end
 
@@ -94,11 +94,11 @@ class Chef
         private
 
         def with_proxy_env
-          saved_socks_env = ENV['SOCKS_SERVER']
-          ENV['SOCKS_SERVER'] = proxy_uri(@uri).to_s
+          saved_socks_env = ENV["SOCKS_SERVER"]
+          ENV["SOCKS_SERVER"] = proxy_uri(@uri).to_s
           yield
         ensure
-          ENV['SOCKS_SERVER'] = saved_socks_env
+          ENV["SOCKS_SERVER"] = saved_socks_env
         end
 
         def with_connection
@@ -162,7 +162,7 @@ class Chef
         end
 
         def parse_path
-          path = uri.path.sub(%r{\A/}, '%2F') # re-encode the beginning slash because uri library decodes it.
+          path = uri.path.sub(%r{\A/}, "%2F") # re-encode the beginning slash because uri library decodes it.
           directories = path.split(%r{/}, -1)
           directories.each {|d|
             d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
diff --git a/lib/chef/provider/remote_file/http.rb b/lib/chef/provider/remote_file/http.rb
index f17ab5a..6fa574e 100644
--- a/lib/chef/provider/remote_file/http.rb
+++ b/lib/chef/provider/remote_file/http.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Jesse Campbell
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 # limitations under the License.
 #
 
-require 'chef/http/simple'
-require 'chef/digester'
-require 'chef/provider/remote_file'
-require 'chef/provider/remote_file/cache_control_data'
+require "chef/http/simple"
+require "chef/digester"
+require "chef/provider/remote_file"
+require "chef/provider/remote_file/cache_control_data"
 
 class Chef
   class Provider
@@ -87,15 +87,15 @@ class Chef
         end
 
         def last_modified_time_from(response)
-          response['last_modified'] || response['date']
+          response["last_modified"] || response["date"]
         end
 
         def etag_from(response)
-          response['etag']
+          response["etag"]
         end
 
         def http_client_opts
-          opts={}
+          opts = {}
           # CHEF-3140
           # 1. If it's already compressed, trying to compress it more will
           # probably be counter-productive.
@@ -105,7 +105,7 @@ class Chef
           # case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz,
           # which is not what you wanted.
           if uri.to_s =~ /gz$/
-            Chef::Log.debug("turning gzip compression off due to filename ending in gz")
+            Chef::Log.debug("Turning gzip compression off due to filename ending in gz")
             opts[:disable_gzip] = true
           end
           opts
diff --git a/lib/chef/provider/remote_file/local_file.rb b/lib/chef/provider/remote_file/local_file.rb
index e78311f..613db02 100644
--- a/lib/chef/provider/remote_file/local_file.rb
+++ b/lib/chef/provider/remote_file/local_file.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'tempfile'
-require 'chef/provider/remote_file'
+require "uri"
+require "tempfile"
+require "chef/provider/remote_file"
 
 class Chef
   class Provider
@@ -32,15 +32,21 @@ class Chef
           @new_resource = new_resource
           @uri = uri
         end
-        
+
         # CHEF-4472: Remove the leading slash from windows paths that we receive from a file:// URI
-        def fix_windows_path(path) 
-          path.gsub(/^\/([a-zA-Z]:)/,'\1')  
+        def fix_windows_path(path)
+          path.gsub(/^\/([a-zA-Z]:)/, '\1')
+        end
+
+        def source_path
+          @source_path ||= begin
+            path = URI.unescape(uri.path)
+            Chef::Platform.windows? ? fix_windows_path(path) : path
+          end
         end
 
         # Fetches the file at uri, returning a Tempfile-like File handle
         def fetch
-          source_path = Chef::Platform.windows? ? fix_windows_path(uri.path) : uri.path
           tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
           Chef::Log.debug("#{new_resource} staging #{source_path} to #{tempfile.path}")
           FileUtils.cp(source_path, tempfile.path)
diff --git a/lib/chef/provider/remote_file/network_file.rb b/lib/chef/provider/remote_file/network_file.rb
new file mode 100644
index 0000000..4404613
--- /dev/null
+++ b/lib/chef/provider/remote_file/network_file.rb
@@ -0,0 +1,48 @@
+#
+# Author:: Jesse Campbell (<hikeit at gmail.com>)
+# Copyright:: Copyright 2013-2016, Jesse Campbell
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "uri"
+require "tempfile"
+require "chef/provider/remote_file"
+
+class Chef
+  class Provider
+    class RemoteFile
+      class NetworkFile
+
+        attr_reader :new_resource
+
+        def initialize(source, new_resource, current_resource)
+          @new_resource = new_resource
+          @source = source
+        end
+
+        # Fetches the file on a network share, returning a Tempfile-like File handle
+        # windows only
+        def fetch
+          tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
+          Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}")
+          FileUtils.cp(@source, tempfile.path)
+          tempfile.close if tempfile
+          tempfile
+        end
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
index 72a5029..3dd0e33 100644
--- a/lib/chef/provider/route.rb
+++ b/lib/chef/provider/route.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org), Jesse Nelson (spheromak at gmail.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,214 +16,214 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/mixin/command'
-require 'chef/provider'
-require 'ipaddr'
+require "chef/log"
+require "chef/mixin/command"
+require "chef/provider"
+require "ipaddr"
 
 class Chef::Provider::Route < Chef::Provider
-    include Chef::Mixin::Command
-
-    provides :route
-
-    attr_accessor :is_running
-
-    MASK = {'0.0.0.0'          => '0',
-            '128.0.0.0'        => '1',
-            '192.0.0.0'        => '2',
-            '224.0.0.0'        => '3',
-            '240.0.0.0'        => '4',
-            '248.0.0.0'        => '5',
-            '252.0.0.0'        => '6',
-            '254.0.0.0'        => '7',
-            '255.0.0.0'        => '8',
-            '255.128.0.0'      => '9',
-            '255.192.0.0'      => '10',
-            '255.224.0.0'      => '11',
-            '255.240.0.0'      => '12',
-            '255.248.0.0'      => '13',
-            '255.252.0.0'      => '14',
-            '255.254.0.0'      => '15',
-            '255.255.0.0'      => '16',
-            '255.255.128.0'    => '17',
-            '255.255.192.0'    => '18',
-            '255.255.224.0'    => '19',
-            '255.255.240.0'    => '20',
-            '255.255.248.0'    => '21',
-            '255.255.252.0'    => '22',
-            '255.255.254.0'    => '23',
-            '255.255.255.0'    => '24',
-            '255.255.255.128'  => '25',
-            '255.255.255.192'  => '26',
-            '255.255.255.224'  => '27',
-            '255.255.255.240'  => '28',
-            '255.255.255.248'  => '29',
-            '255.255.255.252'  => '30',
-            '255.255.255.254'  => '31',
-            '255.255.255.255'  => '32' }
-
-    def hex2ip(hex_data)
-      # Cleanup hex data
-      hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, '')
-
-      # Check hex data format (IP is a 32bit integer, so should be 8 chars long)
-      return nil if hex_ip.length != hex_data.length || hex_ip.length != 8
-
-      # Extract octets from hex data
-      octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack('H2').unpack("C").first }
-
-      # Validate IP
-      ip = octets.join('.')
-      begin
-        IPAddr.new(ip, Socket::AF_INET).to_s
-      rescue ArgumentError
-        Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
-        return nil
-      end
-    end
-
-    def whyrun_supported?
-      true
+  include Chef::Mixin::Command
+
+  provides :route
+
+  attr_accessor :is_running
+
+  MASK = { "0.0.0.0"          => "0",
+           "128.0.0.0"        => "1",
+           "192.0.0.0"        => "2",
+           "224.0.0.0"        => "3",
+           "240.0.0.0"        => "4",
+           "248.0.0.0"        => "5",
+           "252.0.0.0"        => "6",
+           "254.0.0.0"        => "7",
+           "255.0.0.0"        => "8",
+           "255.128.0.0"      => "9",
+           "255.192.0.0"      => "10",
+           "255.224.0.0"      => "11",
+           "255.240.0.0"      => "12",
+           "255.248.0.0"      => "13",
+           "255.252.0.0"      => "14",
+           "255.254.0.0"      => "15",
+           "255.255.0.0"      => "16",
+           "255.255.128.0"    => "17",
+           "255.255.192.0"    => "18",
+           "255.255.224.0"    => "19",
+           "255.255.240.0"    => "20",
+           "255.255.248.0"    => "21",
+           "255.255.252.0"    => "22",
+           "255.255.254.0"    => "23",
+           "255.255.255.0"    => "24",
+           "255.255.255.128"  => "25",
+           "255.255.255.192"  => "26",
+           "255.255.255.224"  => "27",
+           "255.255.255.240"  => "28",
+           "255.255.255.248"  => "29",
+           "255.255.255.252"  => "30",
+           "255.255.255.254"  => "31",
+           "255.255.255.255"  => "32" }
+
+  def hex2ip(hex_data)
+    # Cleanup hex data
+    hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, "")
+
+    # Check hex data format (IP is a 32bit integer, so should be 8 chars long)
+    return nil if hex_ip.length != hex_data.length || hex_ip.length != 8
+
+    # Extract octets from hex data
+    octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack("H2").unpack("C").first }
+
+    # Validate IP
+    ip = octets.join(".")
+    begin
+      IPAddr.new(ip, Socket::AF_INET).to_s
+    rescue ArgumentError
+      Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
+      return nil
     end
+  end
 
-    def load_current_resource
-      self.is_running = false
+  def whyrun_supported?
+    true
+  end
 
-      # cidr or quad dot mask
-      if @new_resource.netmask
-        new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}")
-      else
-        new_ip = IPAddr.new(@new_resource.target)
-      end
-
-      # For linux, we use /proc/net/route file to read proc table info
-      if node[:os] == "linux"
-        route_file = ::File.open("/proc/net/route", "r")
-
-        # Read all routes
-        while (line = route_file.gets)
-          # Get all the fields for a route
-          iface,destination,gateway,flags,refcnt,use,metric,mask,mtu,window,irtt = line.split
-
-          # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0)
-          destination = hex2ip(destination)
-          gateway = hex2ip(gateway)
-          mask = hex2ip(mask)
-
-          # Skip formatting lines (header, etc)
-          next unless destination && gateway && mask
-          Chef::Log.debug("#{@new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}")
-
-          # check if what were trying to configure is already there
-          # use an ipaddr object with ip/mask this way we can have
-          # a new resource be in cidr format (i don't feel like
-          # expanding bitmask by hand.
-          #
-          running_ip = IPAddr.new("#{destination}/#{mask}")
-          Chef::Log.debug("#{@new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}")
-          self.is_running = true if running_ip == new_ip && gateway == @new_resource.gateway
-        end
+  def load_current_resource
+    self.is_running = false
 
-        route_file.close
-      end
+    # cidr or quad dot mask
+    if @new_resource.netmask
+      new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}")
+    else
+      new_ip = IPAddr.new(@new_resource.target)
     end
 
-    def action_add
-      # check to see if load_current_resource found the route
-      if is_running
-        Chef::Log.debug("#{@new_resource} route already active - nothing to do")
-      else
-        command = generate_command(:add)
-        converge_by ("run #{ command } to add route") do
-          run_command( :command => command )
-          Chef::Log.info("#{@new_resource} added")
-        end
+    # For linux, we use /proc/net/route file to read proc table info
+    if node[:os] == "linux"
+      route_file = ::File.open("/proc/net/route", "r")
+
+      # Read all routes
+      while (line = route_file.gets)
+        # Get all the fields for a route
+        iface, destination, gateway, flags, refcnt, use, metric, mask, mtu, window, irtt = line.split
+
+        # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0)
+        destination = hex2ip(destination)
+        gateway = hex2ip(gateway)
+        mask = hex2ip(mask)
+
+        # Skip formatting lines (header, etc)
+        next unless destination && gateway && mask
+        Chef::Log.debug("#{@new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}")
+
+        # check if what were trying to configure is already there
+        # use an ipaddr object with ip/mask this way we can have
+        # a new resource be in cidr format (i don't feel like
+        # expanding bitmask by hand.
+        #
+        running_ip = IPAddr.new("#{destination}/#{mask}")
+        Chef::Log.debug("#{@new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}")
+        self.is_running = true if running_ip == new_ip && gateway == @new_resource.gateway
       end
 
-      #for now we always write the file (ugly but its what it is)
-      generate_config
+      route_file.close
     end
-
-    def action_delete
-      if is_running
-        command = generate_command(:delete)
-        converge_by ("run #{ command } to delete route ") do
-          run_command( :command => command )
-          Chef::Log.info("#{@new_resource} removed")
-        end
-      else
-        Chef::Log.debug("#{@new_resource} route does not exist - nothing to do")
+  end
+
+  def action_add
+    # check to see if load_current_resource found the route
+    if is_running
+      Chef::Log.debug("#{@new_resource} route already active - nothing to do")
+    else
+      command = generate_command(:add)
+      converge_by ("run #{ command } to add route") do
+        run_command( :command => command )
+        Chef::Log.info("#{@new_resource} added")
       end
+    end
+
+    #for now we always write the file (ugly but its what it is)
+    generate_config
+  end
 
-      #for now we always write the file (ugly but its what it is)
-      generate_config
+  def action_delete
+    if is_running
+      command = generate_command(:delete)
+      converge_by ("run #{ command } to delete route ") do
+        run_command( :command => command )
+        Chef::Log.info("#{@new_resource} removed")
+      end
+    else
+      Chef::Log.debug("#{@new_resource} route does not exist - nothing to do")
     end
 
-    def generate_config
-      conf = Hash.new
-      case node[:platform]
-      when "centos", "redhat", "fedora"
-        # walk the collection
-        run_context.resource_collection.each do |resource|
-          if resource.is_a? Chef::Resource::Route
-            # default to eth0
-            if resource.device
-              dev = resource.device
-            else
-              dev = "eth0"
-            end
-
-            conf[dev] = String.new if conf[dev].nil?
-            case @action
-            when :add
-              conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway)
-            when :delete
-              # need to do this for the case when the last route on an int
-              # is removed
-              conf[dev] << config_file_contents(:delete)
-            end
+    #for now we always write the file (ugly but its what it is)
+    generate_config
+  end
+
+  def generate_config
+    conf = Hash.new
+    case node[:platform]
+    when "centos", "redhat", "fedora"
+      # walk the collection
+      run_context.resource_collection.each do |resource|
+        if resource.is_a? Chef::Resource::Route
+          # default to eth0
+          if resource.device
+            dev = resource.device
+          else
+            dev = "eth0"
           end
-        end
-        conf.each do |k, v|
-          network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
-          converge_by ("write route route.#{k}\n#{conf[k]} to #{ network_file_name }") do
-            network_file = ::File.new(network_file_name, "w")
-            network_file.puts(conf[k])
-            Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}")
-            network_file.close
+
+          conf[dev] = String.new if conf[dev].nil?
+          case @action
+          when :add
+            conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway)
+          when :delete
+            # need to do this for the case when the last route on an int
+            # is removed
+            conf[dev] << config_file_contents(:delete)
           end
         end
       end
-    end
-
-    def generate_command(action)
-      common_route_items = ''
-      common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask
-      common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway
-
-      case action
-      when :add
-        command = "ip route replace #{@new_resource.target}"
-        command << common_route_items
-        command << " dev #{@new_resource.device} " if @new_resource.device
-      when :delete
-        command = "ip route delete #{@new_resource.target}"
-        command << common_route_items
+      conf.each do |k, v|
+        network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
+        converge_by ("write route route.#{k}\n#{conf[k]} to #{ network_file_name }") do
+          network_file = ::File.new(network_file_name, "w")
+          network_file.puts(conf[k])
+          Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}")
+          network_file.close
+        end
       end
-
-      return command
+    end
+  end
+
+  def generate_command(action)
+    common_route_items = ""
+    common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask
+    common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway
+
+    case action
+    when :add
+      command = "ip route replace #{@new_resource.target}"
+      command << common_route_items
+      command << " dev #{@new_resource.device} " if @new_resource.device
+    when :delete
+      command = "ip route delete #{@new_resource.target}"
+      command << common_route_items
     end
 
-    def config_file_contents(action, options={})
-      content = ''
-      case action
-      when :add
-        content << "#{options[:target]}"
-        content << "/#{options[:netmask]}" if options[:netmask]
-        content << " via #{options[:gateway]}" if options[:gateway]
-        content << "\n"
-      end
-
-      return content
+    return command
+  end
+
+  def config_file_contents(action, options = {})
+    content = ""
+    case action
+    when :add
+      content << "#{options[:target]}"
+      content << "/#{options[:netmask]}" if options[:netmask]
+      content << " via #{options[:gateway]}" if options[:gateway]
+      content << "\n"
     end
+
+    return content
+  end
 end
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index eb93fd5..0817b14 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2009-2016, Opscode
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb
index e8b5235..6ca4e9f 100644
--- a/lib/chef/provider/script.rb
+++ b/lib/chef/provider/script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'chef/provider/execute'
-require 'forwardable'
+require "tempfile"
+require "chef/provider/execute"
+require "forwardable"
 
 class Chef
   class Provider
@@ -27,6 +27,7 @@ class Chef
 
       provides :bash
       provides :csh
+      provides :ksh
       provides :perl
       provides :python
       provides :ruby
diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb
index 75da2dd..390330a 100644
--- a/lib/chef/provider/service.rb
+++ b/lib/chef/provider/service.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/command'
-require 'chef/provider'
+require "chef/mixin/command"
+require "chef/provider"
 
 class Chef
   class Provider
@@ -25,6 +25,10 @@ class Chef
 
       include Chef::Mixin::Command
 
+      def supports
+        @supports ||= new_resource.supports.dup
+      end
+
       def initialize(new_resource, run_context)
         super
         @enabled = nil
@@ -34,28 +38,37 @@ class Chef
         true
       end
 
-     def load_new_resource_state
-        # If the user didn't specify a change in enabled state,
-        # it will be the same as the old resource
-       if ( @new_resource.enabled.nil? )
-         @new_resource.enabled(@current_resource.enabled)
-       end
-       if ( @new_resource.running.nil? )
-         @new_resource.running(@current_resource.running)
-       end
-     end
+      def load_current_resource
+        supports[:status] = false if supports[:status].nil?
+        supports[:reload] = false if supports[:reload].nil?
+        supports[:restart] = false if supports[:restart].nil?
+      end
+
+      # the new_resource#enabled and #running variables are not user input, but when we
+      # do (e.g.) action_enable we want to set new_resource.enabled so that the comparison
+      # between desired and current state produces the correct change in reporting.
+      # XXX?: the #nil? check below will likely fail if this is a cloned resource or if
+      # we just run multiple actions.
+      def load_new_resource_state
+        if ( @new_resource.enabled.nil? )
+          @new_resource.enabled(@current_resource.enabled)
+        end
+        if ( @new_resource.running.nil? )
+          @new_resource.running(@current_resource.running)
+        end
+      end
 
       def shared_resource_requirements
       end
 
       def define_resource_requirements
-       requirements.assert(:reload) do |a|
-         a.assertion { @new_resource.supports[:reload] || @new_resource.reload_command }
-         a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
-         # if a service is not declared to support reload, that won't
-         # typically change during the course of a run - so no whyrun
-         # alternative here.
-       end
+        requirements.assert(:reload) do |a|
+          a.assertion { supports[:reload] || @new_resource.reload_command }
+          a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
+          # if a service is not declared to support reload, that won't
+          # typically change during the course of a run - so no whyrun
+          # alternative here.
+        end
       end
 
       def action_enable
@@ -130,27 +143,27 @@ class Chef
       end
 
       def enable_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :enable"
       end
 
       def disable_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :disable"
       end
 
       def start_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :start"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :start"
       end
 
       def stop_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :stop"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :stop"
       end
 
       def restart_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :restart"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :restart"
       end
 
       def reload_service
-        raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
+        raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
       end
 
       protected
@@ -168,6 +181,32 @@ class Chef
         @new_resource.respond_to?(method_name) &&
           !!@new_resource.send(method_name)
       end
+
+      module ServicePriorityInit
+
+        #
+        # Platform-specific versions
+        #
+
+        #
+        # Linux
+        #
+
+        require "chef/chef_class"
+        require "chef/provider/service/systemd"
+        require "chef/provider/service/insserv"
+        require "chef/provider/service/redhat"
+        require "chef/provider/service/arch"
+        require "chef/provider/service/gentoo"
+        require "chef/provider/service/upstart"
+        require "chef/provider/service/debian"
+        require "chef/provider/service/invokercd"
+
+        Chef.set_provider_priority_array :service, [ Systemd, Arch ], platform_family: "arch"
+        Chef.set_provider_priority_array :service, [ Systemd, Gentoo ], platform_family: "gentoo"
+        Chef.set_provider_priority_array :service, [ Systemd, Upstart, Insserv, Debian, Invokercd ], platform_family: "debian"
+        Chef.set_provider_priority_array :service, [ Systemd, Insserv, Redhat ], platform_family: %w{rhel fedora suse}
+      end
     end
   end
 end
diff --git a/lib/chef/provider/service/aix.rb b/lib/chef/provider/service/aix.rb
index 0aef62c..201f9ff 100644
--- a/lib/chef/provider/service/aix.rb
+++ b/lib/chef/provider/service/aix.rb
@@ -1,6 +1,6 @@
 #
 # Author:: kaustubh (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service'
+require "chef/provider/service"
 
 class Chef
   class Provider
@@ -90,16 +90,20 @@ class Chef
         end
 
         protected
+
         def determine_current_status!
-          Chef::Log.debug "#{@new_resource} using lssrc to check the status "
+          Chef::Log.debug "#{@new_resource} using lssrc to check the status"
           begin
-            services = shell_out!("lssrc -a | grep -w #{@new_resource.service_name}").stdout.split("\n")
-            is_resource_group?(services)
-
-            if services.length == 1 && services[0].split(' ').last == "active"
-              @current_resource.running true
-            else
+            if is_resource_group?
+              # Groups as a whole have no notion of whether they're running
               @current_resource.running false
+            else
+              service = shell_out!("lssrc -s #{@new_resource.service_name}").stdout
+              if service.split(" ").last == "active"
+                @current_resource.running true
+              else
+                @current_resource.running false
+              end
             end
             Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}"
             # ShellOut sometimes throws different types of Exceptions than ShellCommandFailed.
@@ -112,11 +116,9 @@ class Chef
           end
         end
 
-        def is_resource_group? (services)
-          if services.length > 1
-            Chef::Log.debug("#{@new_resource.service_name} is a group")
-            @is_resource_group = true
-          elsif services[0].split(' ')[1] == @new_resource.service_name
+        def is_resource_group?
+          so = shell_out("lssrc -g #{@new_resource.service_name}")
+          if so.exitstatus == 0
             Chef::Log.debug("#{@new_resource.service_name} is a group")
             @is_resource_group = true
           end
@@ -125,4 +127,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/provider/service/aixinit.rb b/lib/chef/provider/service/aixinit.rb
index 19beac7..6b451d6 100644
--- a/lib/chef/provider/service/aixinit.rb
+++ b/lib/chef/provider/service/aixinit.rb
@@ -1,6 +1,6 @@
 #
 # Author:: kaustubh (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
 
 class Chef
   class Provider
@@ -57,17 +57,17 @@ class Chef
         end
 
         def enable_service
-          Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f)}
+          Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f) }
 
           if @new_resource.priority.is_a? Integer
-            create_symlink(2, 'S', @new_resource.priority)
+            create_symlink(2, "S", @new_resource.priority)
 
           elsif @new_resource.priority.is_a? Hash
-            @new_resource.priority.each do |level,o|
-              create_symlink(level,(o[0] == :start ? 'S' : 'K'),o[1])
+            @new_resource.priority.each do |level, o|
+              create_symlink(level, (o[0] == :start ? "S" : "K"), o[1])
             end
           else
-            create_symlink(2, 'S', '')
+            create_symlink(2, "S", "")
           end
         end
 
@@ -75,13 +75,13 @@ class Chef
           Dir.glob(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).each { |f| ::File.delete(f) }
 
           if @new_resource.priority.is_a? Integer
-            create_symlink(2, 'K',100 - @new_resource.priority)
+            create_symlink(2, "K", 100 - @new_resource.priority)
           elsif @new_resource.priority.is_a? Hash
-            @new_resource.priority.each do |level,o|
-              create_symlink(level, 'K', 100 - o[1]) if o[0] == :stop
+            @new_resource.priority.each do |level, o|
+              create_symlink(level, "K", 100 - o[1]) if o[0] == :stop
             end
           else
-            create_symlink(2, 'K', '')
+            create_symlink(2, "K", "")
           end
         end
 
@@ -98,7 +98,7 @@ class Chef
 
           files.each do |file|
             if (RC_D_SCRIPT_NAME =~ file)
-              priority[2] = [($1 == "S" ? :start : :stop), ($2.empty? ? '' : $2.to_i)]
+              priority[2] = [($1 == "S" ? :start : :stop), ($2.empty? ? "" : $2.to_i)]
               if $1 == "S"
                 is_enabled = true
               end
diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb
index e7fbcc8..9c66fb4 100644
--- a/lib/chef/provider/service/arch.rb
+++ b/lib/chef/provider/service/arch.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
 
 class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
 
@@ -32,8 +32,8 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
   end
 
   def load_current_resource
-    raise Chef::Exceptions::Service, "Could not find /etc/rc.conf"  unless ::File.exists?("/etc/rc.conf")
-    raise Chef::Exceptions::Service, "No DAEMONS found in /etc/rc.conf"  unless ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m)
+    raise Chef::Exceptions::Service, "Could not find /etc/rc.conf" unless ::File.exists?("/etc/rc.conf")
+    raise Chef::Exceptions::Service, "No DAEMONS found in /etc/rc.conf" unless ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m)
     super
 
     @current_resource.enabled(daemons.include?(@current_resource.service_name))
@@ -50,7 +50,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
   def daemons
     entries = []
     if ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m)
-      entries += $1.gsub(/\\?[\r\n]/, ' ').gsub(/# *[^ ]+/,' ').split(' ') if $1.length > 0
+      entries += $1.gsub(/\\?[\r\n]/, " ").gsub(/# *[^ ]+/, " ").split(" ") if $1.length > 0
     end
 
     yield(entries) if block_given?
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 0150592..6550c85 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,19 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
 
 class Chef
   class Provider
     class Service
       class Debian < Chef::Provider::Service::Init
+        provides :service, platform_family: "debian" do |node|
+          Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
+        end
+
         UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i
         UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i
 
-        provides :service, platform_family: "debian"
-
-        def self.provides?(node, resource)
-          super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
-        end
-
         def self.supports?(resource, action)
           Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
         end
@@ -57,18 +55,18 @@ class Chef
 
           requirements.assert(:all_actions) do |a|
             a.assertion { @priority_success }
-            a.failure_message  Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
+            a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{current_resource.service_name} failed - #{@rcd_status.inspect}"
             # This can happen if the service is not yet installed,so we'll fake it.
             a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
                       "Assigning temporary priorities to continue.",
                       "If this service is not properly installed prior to this point, this will fail."] do
-              temp_priorities = {"6"=>[:stop, "20"],
-                "0"=>[:stop, "20"],
-                "1"=>[:stop, "20"],
-                "2"=>[:start, "20"],
-                "3"=>[:start, "20"],
-                "4"=>[:start, "20"],
-                "5"=>[:start, "20"]}
+              temp_priorities = { "6" => [:stop, "20"],
+                                  "0" => [:stop, "20"],
+                                  "1" => [:stop, "20"],
+                                  "2" => [:start, "20"],
+                                  "3" => [:start, "20"],
+                                  "4" => [:start, "20"],
+                                  "5" => [:start, "20"] }
               current_resource.priority(temp_priorities)
             end
           end
@@ -111,7 +109,7 @@ class Chef
           priority.each { |runlevel, arguments|
             Chef::Log.debug("#{new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
             # if we are in a update-rc.d default startup runlevel && we start in this runlevel
-            if %w[ 1 2 3 4 5 S ].include?(runlevel) && arguments[0] == :start
+            if %w{ 1 2 3 4 5 S }.include?(runlevel) && arguments[0] == :start
               enabled = true
             end
           }
@@ -150,7 +148,6 @@ class Chef
             shell_out!("/usr/sbin/update-rc.d -f #{new_resource.service_name} remove")
             shell_out!("/usr/sbin/update-rc.d #{new_resource.service_name} defaults")
           end
-
         end
 
         def disable_service
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index 9204e3e..7e475fc 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/resource/service'
-require 'chef/provider/service/init'
-require 'chef/mixin/command'
+require "chef/resource/service"
+require "chef/provider/service/init"
+require "chef/mixin/command"
 
 class Chef
   class Provider
@@ -51,7 +51,7 @@ class Chef
           Chef::Log.debug("#{current_resource} found at #{init_command}")
 
           @status_load_success = true
-          determine_current_status!  # see Chef::Provider::Service::Simple
+          determine_current_status! # see Chef::Provider::Service::Simple
 
           determine_enabled_status!
           current_resource
@@ -99,7 +99,7 @@ class Chef
         def restart_service
           if new_resource.restart_command
             super
-          elsif new_resource.supports[:restart]
+          elsif supports[:restart]
             shell_out_with_systems_locale!("#{init_command} fastrestart")
           else
             stop_service
@@ -119,11 +119,11 @@ class Chef
         private
 
         def read_rc_conf
-          ::File.open("/etc/rc.conf", 'r') { |file| file.readlines }
+          ::File.open("/etc/rc.conf", "r") { |file| file.readlines }
         end
 
         def write_rc_conf(lines)
-          ::File.open("/etc/rc.conf", 'w') do |file|
+          ::File.open("/etc/rc.conf", "w") do |file|
             lines.each { |line| file.puts(line) }
           end
         end
@@ -147,7 +147,7 @@ class Chef
                 # some scripts support multiple instances through symlinks such as openvpn.
                 # We should get the service name from rcvar.
                 Chef::Log.debug("name=\"service\" not found at #{init_command}. falling back to rcvar")
-                sn = shell_out!("#{init_command} rcvar").stdout[/(\w+_enable)=/, 1]
+                shell_out!("#{init_command} rcvar").stdout[/(\w+_enable)=/, 1]
               else
                 # for why-run mode when the rcd_script is not there yet
                 new_resource.service_name
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index 3dab920..66f2f10 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Lee Jensen (<ljensen at engineyard.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,18 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
-require 'chef/mixin/command'
-require 'chef/util/path_helper'
+require "chef/provider/service/init"
+require "chef/mixin/command"
+require "chef/util/path_helper"
 
 class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
 
   provides :service, platform_family: "gentoo"
 
   def load_current_resource
+    supports[:status] = true if supports[:status].nil?
+    supports[:restart] = true if supports[:restart].nil?
 
-    @new_resource.supports[:status] = true
-    @new_resource.supports[:restart] = true
     @found_script = false
     super
 
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 0a219a6..dff627d 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/simple'
-require 'chef/mixin/command'
+require "chef/provider/service/simple"
+require "chef/mixin/command"
+require "chef/platform/service_helpers"
 
 class Chef
   class Provider
@@ -71,7 +72,7 @@ class Chef
         def restart_service
           if @new_resource.restart_command
             super
-          elsif @new_resource.supports[:restart]
+          elsif supports[:restart]
             shell_out_with_systems_locale!("#{default_init_command} restart")
           else
             stop_service
@@ -83,7 +84,7 @@ class Chef
         def reload_service
           if @new_resource.reload_command
             super
-          elsif @new_resource.supports[:reload]
+          elsif supports[:reload]
             shell_out_with_systems_locale!("#{default_init_command} reload")
           end
         end
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 31965a4..7f92ef1 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
-require 'chef/util/path_helper'
+require "chef/provider/service/init"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
     class Service
       class Insserv < Chef::Provider::Service::Init
 
-        provides :service, os: "linux"
-
-        def self.provides?(node, resource)
-          super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
+        provides :service, platform_family: %w{debian rhel fedora suse} do |node|
+          Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
         end
 
         def self.supports?(resource, action)
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index 5ff24e0..9477afe 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
 
 class Chef
   class Provider
     class Service
       class Invokercd < Chef::Provider::Service::Init
 
-        provides :service, platform_family: "debian"
-
-        def self.provides?(node, resource)
-          super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
+        provides :service, platform_family: "debian", override: true do |node|
+          Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
         end
 
         def self.supports?(resource, action)
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 7cfe57a..6348590 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Igor Afonov <afonov at gmail.com>
-# Copyright:: Copyright (c) 2011 Igor Afonov
+# Copyright:: Copyright 2011-2016, Igor Afonov
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,36 @@
 # limitations under the License.
 #
 
-require 'etc'
-require 'rexml/document'
-require 'chef/resource/service'
-require 'chef/resource/macosx_service'
-require 'chef/provider/service/simple'
-require 'chef/util/path_helper'
+require "etc"
+require "rexml/document"
+require "chef/resource/service"
+require "chef/resource/macosx_service"
+require "chef/provider/service/simple"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
     class Service
       class Macosx < Chef::Provider::Service::Simple
 
-        provides :service, os: "darwin"
         provides :macosx_service, os: "darwin"
+        provides :service, os: "darwin"
 
         def self.gather_plist_dirs
           locations = %w{/Library/LaunchAgents
                          /Library/LaunchDaemons
                          /System/Library/LaunchAgents
                          /System/Library/LaunchDaemons }
-          Chef::Util::PathHelper.home('Library', 'LaunchAgents') { |p| locations << p }
+          Chef::Util::PathHelper.home("Library", "LaunchAgents") { |p| locations << p }
           locations
         end
 
         PLIST_DIRS = gather_plist_dirs
 
+        def this_version_or_newer?(this_version)
+          Gem::Version.new(node["platform_version"]) >= Gem::Version.new(this_version)
+        end
+
         def load_current_resource
           @current_resource = Chef::Resource::MacosxService.new(@new_resource.name)
           @current_resource.service_name(@new_resource.service_name)
@@ -49,17 +53,17 @@ class Chef
           @plist = @new_resource.plist ? @new_resource.plist : find_service_plist
           @service_label = find_service_label
           # LauchAgents should be loaded as the console user.
-          @console_user = @plist ? @plist.include?('LaunchAgents') : false
+          @console_user = @plist ? @plist.include?("LaunchAgents") : false
           @session_type = @new_resource.session_type
 
           if @console_user
             @console_user = Etc.getlogin
             Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
             cmd = "su "
-            param = !node['platform_version'].include?('10.10') ? '-l ' : ''
+            param = this_version_or_newer?("10.10") ? "" : "-l "
             @base_user_cmd = cmd + param + "#{@console_user} -c"
             # Default LauchAgent session should be Aqua
-            @session_type = 'Aqua' if @session_type.nil?
+            @session_type = "Aqua" if @session_type.nil?
           end
 
           Chef::Log.debug("#{new_resource} Plist: '#{@plist}' service_label: '#{@service_label}'")
@@ -70,7 +74,7 @@ class Chef
 
         def define_resource_requirements
           requirements.assert(:reload) do |a|
-            a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
+            a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} does not support :reload"
           end
 
           requirements.assert(:all_actions) do |a|
@@ -79,7 +83,7 @@ class Chef
           end
 
           requirements.assert(:all_actions) do |a|
-            a.assertion {::File.exists?(@plist.to_s) }
+            a.assertion { ::File.exists?(@plist.to_s) }
             a.failure_message Chef::Exceptions::Service,
               "Could not find plist for #{@new_resource}"
           end
@@ -156,14 +160,14 @@ class Chef
           end
         end
 
-       def load_service
-          session = @session_type ? "-S #{@session_type} " : ''
-          cmd = 'launchctl load -w ' + session + @plist
+        def load_service
+          session = @session_type ? "-S #{@session_type} " : ""
+          cmd = "launchctl load -w " + session + @plist
           shell_out_as_user(cmd)
         end
 
         def unload_service
-          cmd = 'launchctl unload -w ' + @plist
+          cmd = "launchctl unload -w " + @plist
           shell_out_as_user(cmd)
         end
 
@@ -202,7 +206,7 @@ class Chef
           end
         end
 
-      private
+        private
 
         def find_service_label
           # CHEF-5223 "you can't glob for a file that hasn't been converged
diff --git a/lib/chef/provider/service/openbsd.rb b/lib/chef/provider/service/openbsd.rb
index d509ee1..c31df25 100644
--- a/lib/chef/provider/service/openbsd.rb
+++ b/lib/chef/provider/service/openbsd.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Scott Bonds (<scott at ggr.com>)
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2014-2016, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,35 +16,36 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/command'
-require 'chef/mixin/shell_out'
-require 'chef/provider/service/init'
-require 'chef/resource/service'
+require "chef/mixin/command"
+require "chef/mixin/shell_out"
+require "chef/provider/service/init"
+require "chef/resource/service"
 
 class Chef
   class Provider
     class Service
       class Openbsd < Chef::Provider::Service::Init
 
-        provides :service, os: [ "openbsd" ]
+        provides :service, os: "openbsd"
 
         include Chef::Mixin::ShellOut
 
         attr_reader :init_command, :rc_conf, :rc_conf_local, :enabled_state_found
 
-        RC_CONF_PATH = '/etc/rc.conf'
-        RC_CONF_LOCAL_PATH = '/etc/rc.conf.local'
+        RC_CONF_PATH = "/etc/rc.conf"
+        RC_CONF_LOCAL_PATH = "/etc/rc.conf.local"
 
         def initialize(new_resource, run_context)
           super
-          @rc_conf = ::File.read(RC_CONF_PATH) rescue ''
-          @rc_conf_local = ::File.read(RC_CONF_LOCAL_PATH) rescue ''
+          @rc_conf = ::File.read(RC_CONF_PATH) rescue ""
+          @rc_conf_local = ::File.read(RC_CONF_LOCAL_PATH) rescue ""
           @init_command = ::File.exist?(rcd_script_path) ? rcd_script_path : nil
-          new_resource.supports[:status] = true
           new_resource.status_command("#{default_init_command} check")
         end
 
         def load_current_resource
+          supports[:status] = true if supports[:status].nil?
+
           @current_resource = Chef::Resource::Service.new(new_resource.name)
           current_resource.service_name(new_resource.service_name)
 
@@ -81,7 +82,7 @@ class Chef
           if !is_enabled?
             if is_builtin?
               if is_enabled_by_default?
-                update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, '')
+                update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, "")
               else
                 # add line with blank string, which means enable
                 update_rcl rc_conf_local + "\n" + "#{builtin_service_enable_variable_name}=\"\"\n"
@@ -89,7 +90,7 @@ class Chef
             else
               # add to pkg_scripts, most recent addition goes last
               old_services_list = rc_conf_local.match(/^pkg_scripts="(.*)"/)
-              old_services_list = old_services_list ? old_services_list[1].split(' ') : []
+              old_services_list = old_services_list ? old_services_list[1].split(" ") : []
               new_services_list = old_services_list + [new_resource.service_name]
               if rc_conf_local.match(/^pkg_scripts="(.*)"/)
                 new_rcl = rc_conf_local.sub(/^pkg_scripts="(.*)"/, "pkg_scripts=\"#{new_services_list.join(' ')}\"")
@@ -109,14 +110,14 @@ class Chef
                 update_rcl rc_conf_local + "\n" + "#{builtin_service_enable_variable_name}=\"NO\"\n"
               else
                 # remove line to disable
-                update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, '')
+                update_rcl rc_conf_local.sub(/^#{Regexp.escape(builtin_service_enable_variable_name)}=.*/, "")
               end
             else
               # remove from pkg_scripts
               old_list = rc_conf_local.match(/^pkg_scripts="(.*)"/)
-              old_list = old_list ? old_list[1].split(' ') : []
+              old_list = old_list ? old_list[1].split(" ") : []
               new_list = old_list - [new_resource.service_name]
-              update_rcl rc_conf_local.sub(/^pkg_scripts="(.*)"/, pkg_scripts="#{new_list.join(' ')}")
+              update_rcl rc_conf_local.sub(/^pkg_scripts="(.*)"/, pkg_scripts = "#{new_list.join(' ')}")
             end
           end
         end
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 8509531..a76622e 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,31 +16,39 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/init'
+require "chef/provider/service/init"
 
 class Chef
   class Provider
     class Service
       class Redhat < Chef::Provider::Service::Init
 
-        CHKCONFIG_ON = /\d:on/
-        CHKCONFIG_MISSING = /No such/
-
-        provides :service, platform_family: [ "rhel", "fedora", "suse" ]
+        # @api private
+        attr_accessor :service_missing
+        # @api private
+        attr_accessor :current_run_levels
 
-        def self.provides?(node, resource)
-          super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
+        provides :service, platform_family: %w{rhel fedora suse} do |node|
+          Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
         end
 
+        CHKCONFIG_ON = /\d:on/
+        CHKCONFIG_MISSING = /No such/
+
         def self.supports?(resource, action)
           Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
         end
 
         def initialize(new_resource, run_context)
           super
-          @init_command = "/sbin/service #{@new_resource.service_name}"
-          @new_resource.supports[:status] = true
+          @init_command = "/sbin/service #{new_resource.service_name}"
           @service_missing = false
+          @current_run_levels = []
+        end
+
+        # @api private
+        def run_levels
+          new_resource.run_levels
         end
 
         def define_resource_requirements
@@ -49,34 +57,62 @@ class Chef
           requirements.assert(:all_actions) do |a|
             chkconfig_file = "/sbin/chkconfig"
             a.assertion { ::File.exists? chkconfig_file  }
-            a.failure_message Chef::Exceptions::Service, "#{chkconfig_file} does not exist!"
+            a.failure_message Chef::Exceptions::Service, "#{chkconfig_file} dbleoes not exist!"
           end
 
           requirements.assert(:start, :enable, :reload, :restart) do |a|
-            a.assertion { !@service_missing }
-            a.failure_message Chef::Exceptions::Service, "#{@new_resource}: unable to locate the init.d script!"
+            a.assertion do
+              custom_command_for_action?(action) || !@service_missing
+            end
+            a.failure_message Chef::Exceptions::Service, "#{new_resource}: No custom command for #{action} specified and unable to locate the init.d script!"
             a.whyrun "Assuming service would be disabled. The init script is not presently installed."
           end
         end
 
         def load_current_resource
+          supports[:status] = true if supports[:status].nil?
+
           super
 
           if ::File.exists?("/sbin/chkconfig")
-            chkconfig = shell_out!("/sbin/chkconfig --list #{@current_resource.service_name}", :returns => [0,1])
-            @current_resource.enabled(!!(chkconfig.stdout =~ CHKCONFIG_ON))
+            chkconfig = shell_out!("/sbin/chkconfig --list #{current_resource.service_name}", :returns => [0, 1])
+            unless run_levels.nil? or run_levels.empty?
+              all_levels_match = true
+              chkconfig.stdout.split(/\s+/)[1..-1].each do |level|
+                index = level.split(":").first
+                status = level.split(":").last
+                if level =~ CHKCONFIG_ON
+                  @current_run_levels << index.to_i
+                  all_levels_match = false unless run_levels.include?(index.to_i)
+                else
+                  all_levels_match = false if run_levels.include?(index.to_i)
+                end
+              end
+              current_resource.enabled(all_levels_match)
+            else
+              current_resource.enabled(!!(chkconfig.stdout =~ CHKCONFIG_ON))
+            end
             @service_missing = !!(chkconfig.stderr =~ CHKCONFIG_MISSING)
           end
 
-          @current_resource
+          current_resource
+        end
+
+        # @api private
+        def levels
+          (run_levels.nil? or run_levels.empty?) ? "" : "--level #{run_levels.join('')} "
         end
 
         def enable_service()
-          shell_out! "/sbin/chkconfig #{@new_resource.service_name} on"
+          unless run_levels.nil? or run_levels.empty?
+            disable_levels = current_run_levels - run_levels
+            shell_out! "/sbin/chkconfig --level #{disable_levels.join('')} #{new_resource.service_name} off" unless disable_levels.empty?
+          end
+          shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} on"
         end
 
         def disable_service()
-          shell_out! "/sbin/chkconfig #{@new_resource.service_name} off"
+          shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} off"
         end
       end
     end
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index ee403ee..d76779a 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mathieu Sauve-Frankel <msf at kisoku.net>
-# Copyright:: Copyright (c) 2009 Mathieu Sauve-Frankel
+# Copyright:: Copyright 2009-2016, Mathieu Sauve-Frankel
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service'
-require 'chef/resource/service'
-require 'chef/mixin/command'
+require "chef/provider/service"
+require "chef/resource/service"
+require "chef/mixin/command"
 
 class Chef
   class Provider
@@ -58,25 +58,25 @@ class Chef
           shared_resource_requirements
           requirements.assert(:start) do |a|
             a.assertion { @new_resource.start_command }
-            a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that start_command be set"
+            a.failure_message Chef::Exceptions::Service, "#{self} requires that start_command be set"
           end
           requirements.assert(:stop) do |a|
             a.assertion { @new_resource.stop_command }
-            a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that stop_command be set"
+            a.failure_message Chef::Exceptions::Service, "#{self} requires that stop_command be set"
           end
 
           requirements.assert(:restart) do |a|
-            a.assertion { @new_resource.restart_command  || ( @new_resource.start_command && @new_resource.stop_command ) }
-            a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires a restart_command or both start_command and stop_command be set in order to perform a restart"
+            a.assertion { @new_resource.restart_command || ( @new_resource.start_command && @new_resource.stop_command ) }
+            a.failure_message Chef::Exceptions::Service, "#{self} requires a restart_command or both start_command and stop_command be set in order to perform a restart"
           end
 
           requirements.assert(:reload) do |a|
             a.assertion { @new_resource.reload_command }
-            a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} requires a reload_command be set in order to perform a reload"
+            a.failure_message Chef::Exceptions::UnsupportedAction, "#{self} requires a reload_command be set in order to perform a reload"
           end
 
           requirements.assert(:all_actions) do |a|
-            a.assertion { @new_resource.status_command or @new_resource.supports[:status] or
+            a.assertion { @new_resource.status_command or supports[:status] or
               (!ps_cmd.nil? and !ps_cmd.empty?) }
             a.failure_message Chef::Exceptions::Service, "#{@new_resource} could not determine how to inspect the process table, please set this node's 'command.ps' attribute"
           end
@@ -109,6 +109,7 @@ class Chef
         end
 
       protected
+
         def determine_current_status!
           if @new_resource.status_command
             Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
@@ -127,7 +128,7 @@ class Chef
               nil
             end
 
-          elsif @new_resource.supports[:status]
+          elsif supports[:status]
             Chef::Log.debug("#{@new_resource} supports status, running")
             begin
               if shell_out("#{default_init_command} status").exitstatus == 0
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index eaea6bb..0787392 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service'
-require 'chef/resource/service'
-require 'chef/mixin/command'
+require "chef/provider/service"
+require "chef/resource/service"
+require "chef/mixin/command"
 
 class Chef
   class Provider
@@ -28,37 +28,41 @@ class Chef
 
         provides :service, os: "solaris2"
 
-        def initialize(new_resource, run_context=nil)
+        def initialize(new_resource, run_context = nil)
           super
-          @init_command = "/usr/sbin/svcadm"
-          @status_command = "/bin/svcs -l"
+          @init_command   = "/usr/sbin/svcadm"
+          @status_command = "/bin/svcs"
           @maintenace     = false
         end
 
         def load_current_resource
           @current_resource = Chef::Resource::Service.new(@new_resource.name)
           @current_resource.service_name(@new_resource.service_name)
-          unless ::File.exists? "/bin/svcs"
-            raise Chef::Exceptions::Service, "/bin/svcs does not exist!"
+
+          [@init_command, @status_command].each do |cmd|
+            unless ::File.executable? cmd then
+              raise Chef::Exceptions::Service, "#{cmd} not executable!"
+            end
           end
           @status = service_status.enabled
+
           @current_resource
         end
 
         def enable_service
-          shell_out!("#{default_init_command} clear #{@new_resource.service_name}") if @maintenance
-          shell_out!("#{default_init_command} enable -s #{@new_resource.service_name}")
+          shell_out!(default_init_command, "clear", @new_resource.service_name) if @maintenance
+          shell_out!(default_init_command, "enable", "-s", @new_resource.service_name)
         end
 
         def disable_service
-          shell_out!("#{default_init_command} disable -s #{@new_resource.service_name}")
+          shell_out!(default_init_command, "disable", "-s", @new_resource.service_name)
         end
 
         alias_method :stop_service, :disable_service
         alias_method :start_service, :enable_service
 
         def reload_service
-          shell_out_with_systems_locale!("#{default_init_command} refresh #{@new_resource.service_name}")
+          shell_out!(default_init_command, "refresh", @new_resource.service_name)
         end
 
         def restart_service
@@ -68,16 +72,38 @@ class Chef
         end
 
         def service_status
-          status = shell_out!("#{@status_command} #{@current_resource.service_name}", :returns => [0, 1])
-          status.stdout.each_line do |line|
-            case line
-            when /state\s+online/
-              @current_resource.enabled(true)
-              @current_resource.running(true)
-            when /state\s+maintenance/
-              @maintenance = true
-            end
+          cmd = shell_out!(@status_command, "-l", @current_resource.service_name, :returns => [0, 1])
+          # Example output
+          # $ svcs -l rsyslog
+          # fmri         svc:/application/rsyslog:default
+          # name         rsyslog logging utility
+          # enabled      true
+          # state        online
+          # next_state   none
+          # state_time   April  2, 2015 04:25:19 PM EDT
+          # logfile      /var/svc/log/application-rsyslog:default.log
+          # restarter    svc:/system/svc/restarter:default
+          # contract_id  1115271
+          # dependency   require_all/error svc:/milestone/multi-user:default (online)
+          # $
+
+          # load output into hash
+          status = {}
+          cmd.stdout.each_line do |line|
+            key, value = line.strip.split(/\s+/, 2)
+            status[key] = value
+          end
+
+          # check service state
+          @maintenance = false
+          case status["state"]
+          when "online"
+            @current_resource.enabled(true)
+            @current_resource.running(true)
+          when "maintenance"
+            @maintenance = true
           end
+
           unless @current_resource.enabled
             @current_resource.enabled(false)
             @current_resource.running(false)
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 9085ffd..e70576f 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,20 @@
 # limitations under the License.
 #
 
-require 'chef/resource/service'
-require 'chef/provider/service/simple'
-require 'chef/mixin/which'
+require "chef/resource/service"
+require "chef/provider/service/simple"
+require "chef/mixin/which"
 
 class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
 
   include Chef::Mixin::Which
 
-  provides :service, os: "linux"
+  provides :service, os: "linux" do |node|
+    Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
+  end
 
   attr_accessor :status_check_success
 
-  def self.provides?(node, resource)
-    super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
-  end
-
   def self.supports?(resource, action)
     Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:systemd)
   end
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 8d4aa41..edd41db 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2010 Bryan McLellan
+# Copyright:: Copyright 2010-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,22 @@
 # limitations under the License.
 #
 
-require 'chef/resource/service'
-require 'chef/provider/service/simple'
-require 'chef/mixin/command'
-require 'chef/util/file_edit'
+require "chef/resource/service"
+require "chef/provider/service/simple"
+require "chef/mixin/command"
+require "chef/util/file_edit"
 
 class Chef
   class Provider
     class Service
       class Upstart < Chef::Provider::Service::Simple
-        UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
 
-        provides :service, os: "linux"
-
-        def self.provides?(node, resource)
-          super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
+        provides :service, platform_family: "debian", override: true do |node|
+          Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
         end
 
+        UPSTART_STATE_FORMAT = /\S+ \(?(start|stop)?\)? ?[\/ ](\w+)/
+
         def self.supports?(resource, action)
           Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
         end
@@ -90,7 +89,7 @@ class Chef
           end
 
           requirements.assert(:all_actions) do |a|
-            a.assertion  { @config_file_found }
+            a.assertion { @config_file_found }
             # no failure here, just document the assumptions made.
             a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled."
           end
@@ -107,7 +106,7 @@ class Chef
             Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
 
             begin
-              if shell_out!(@new_resource.status_command) == 0
+              if shell_out!(@new_resource.status_command).exitstatus == 0
                 @current_resource.running true
               end
             rescue
@@ -131,7 +130,7 @@ class Chef
           # Get enabled/disabled state by reading job configuration file
           if ::File.exists?("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
             Chef::Log.debug("#{@new_resource} found #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
-            ::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}",'r') do |file|
+            ::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}", "r") do |file|
               while line = file.gets
                 case line
                 when /^start on/
@@ -225,10 +224,10 @@ class Chef
           command = "/sbin/status #{@job}"
           status = popen4(command) do |pid, stdin, stdout, stderr|
             stdout.each_line do |line|
-              # rsyslog stop/waiting
               # service goal/state
               # OR
-              # rsyslog (stop) waiting
+              # service (instance) goal/state
+              # OR
               # service (goal) state
               line =~ UPSTART_STATE_FORMAT
               data = Regexp.last_match
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index ba53f0a..2705aa5 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Nuo Yan <nuo at opscode.com>
+# Author:: Nuo Yan <nuo at chef.io>
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Author:: Seth Chisamore <schisamo at opscode.com>
-# Copyright:: Copyright (c) 2010-2011 Opscode, Inc
+# Author:: Seth Chisamore <schisamo at chef.io>
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/service/simple'
+require "chef/provider/service/simple"
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'chef/win32/error'
-  require 'win32/service'
+  require "chef/win32/error"
+  require "win32/service"
 end
 
 class Chef::Provider::Service::Windows < Chef::Provider::Service
-
   provides :service, os: "windows"
   provides :windows_service, os: "windows"
 
@@ -33,20 +32,22 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
   include Chef::ReservedNames::Win32::API::Error rescue LoadError
 
   #Win32::Service.get_start_type
-  AUTO_START = 'auto start'
-  MANUAL = 'demand start'
-  DISABLED = 'disabled'
+  AUTO_START = "auto start"
+  MANUAL = "demand start"
+  DISABLED = "disabled"
 
   #Win32::Service.get_current_state
-  RUNNING = 'running'
-  STOPPED = 'stopped'
-  CONTINUE_PENDING = 'continue pending'
-  PAUSE_PENDING = 'pause pending'
-  PAUSED = 'paused'
-  START_PENDING = 'start pending'
-  STOP_PENDING  = 'stop pending'
+  RUNNING = "running"
+  STOPPED = "stopped"
+  CONTINUE_PENDING = "continue pending"
+  PAUSE_PENDING = "pause pending"
+  PAUSED = "paused"
+  START_PENDING = "start pending"
+  STOP_PENDING  = "stop pending"
+
+  TIMEOUT = 60
 
-  TIMEOUT  = 60
+  SERVICE_RIGHT = "SeServiceLogonRight"
 
   def whyrun_supported?
     false
@@ -74,15 +75,15 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
         service_name: @new_resource.service_name,
         service_start_name: @new_resource.run_as_user,
         password: @new_resource.run_as_password,
-      }.reject { |k,v| v.nil? || v.length == 0 }
+      }.reject { |k, v| v.nil? || v.length == 0 }
 
       Win32::Service.configure(new_config)
       Chef::Log.info "#{@new_resource} configured with #{new_config.inspect}"
 
-      # it would be nice to check if the user already has the logon privilege, but that turns out to be
-      # nontrivial.
       if new_config.has_key?(:service_start_name)
-        grant_service_logon(new_config[:service_start_name])
+        unless Chef::ReservedNames::Win32::Security.get_account_right(canonicalize_username(new_config[:service_start_name])).include?(SERVICE_RIGHT)
+          grant_service_logon(new_config[:service_start_name])
+        end
       end
 
       state = current_state
@@ -237,74 +238,26 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
   end
 
   private
-  def make_policy_text(username)
-    text = <<-EOS
-[Unicode]
-Unicode=yes
-[Privilege Rights]
-SeServiceLogonRight = \\\\#{canonicalize_username(username)},*S-1-5-80-0
-[Version]
-signature="$CHICAGO$"
-Revision=1
-EOS
-  end
-
-  def grant_logfile_name(username)
-    Chef::Util::PathHelper.canonical_path("#{Dir.tmpdir}/logon_grant-#{clean_username_for_path(username)}-#{$$}.log", prefix=false)
-  end
-
-  def grant_policyfile_name(username)
-    Chef::Util::PathHelper.canonical_path("#{Dir.tmpdir}/service_logon_policy-#{clean_username_for_path(username)}-#{$$}.inf", prefix=false)
-  end
-
-  def grant_dbfile_name(username)
-    "#{ENV['TEMP']}\\secedit.sdb"
-  end
 
   def grant_service_logon(username)
-    logfile = grant_logfile_name(username)
-    policy_file = ::File.new(grant_policyfile_name(username), 'w')
-    policy_text = make_policy_text(username)
-    dbfile = grant_dbfile_name(username)        # this is just an audit file.
-
     begin
-      Chef::Log.debug "Policy file text:\n#{policy_text}"
-      policy_file.puts(policy_text)
-      policy_file.close   # need to flush the buffer.
-
-      # it would be nice to do this with APIs instead, but the LSA_* APIs are
-      # particularly onerous and life is short.
-      cmd = %Q{secedit.exe /configure /db "#{dbfile}" /cfg "#{policy_file.path}" /areas USER_RIGHTS SECURITYPOLICY SERVICES /log "#{logfile}"}
-      Chef::Log.debug "Granting logon-as-service privilege with: #{cmd}"
-      runner = shell_out(cmd)
-
-      if runner.exitstatus != 0
-        Chef::Log.fatal "Logon-as-service grant failed with output: #{runner.stdout}"
-        raise Chef::Exceptions::Service, <<-EOS
-Logon-as-service grant failed with policy file #{policy_file.path}.
-You can look at #{logfile} for details, or do `secedit /analyze #{dbfile}`.
-The failed command was `#{cmd}`.
-EOS
-      end
-
-      Chef::Log.info "Grant logon-as-service to user '#{username}' successful."
-
-      ::File.delete(dbfile) rescue nil
-      ::File.delete(policy_file)
-      ::File.delete(logfile) rescue nil     # logfile is not always present at end.
+      Chef::ReservedNames::Win32::Security.add_account_right(canonicalize_username(username), SERVICE_RIGHT)
+    rescue Chef::Exceptions::Win32APIError => err
+      Chef::Log.fatal "Logon-as-service grant failed with output: #{err}"
+      raise Chef::Exceptions::Service, "Logon-as-service grant failed for #{username}: #{err}"
     end
+
+    Chef::Log.info "Grant logon-as-service to user '#{username}' successful."
     true
   end
 
   # remove characters that make for broken or wonky filenames.
   def clean_username_for_path(username)
-    username.gsub(/[\/\\. ]+/, '_')
+    username.gsub(/[\/\\. ]+/, "_")
   end
 
-  # the security policy file only seems to accept \\username, so fix .\username or .\\username.
-  # TODO: this probably has to be fixed to handle various valid Windows names correctly.
   def canonicalize_username(username)
-    username.sub(/^\.?\\+/, '')
+    username.sub(/^\.?\\+/, "")
   end
 
   def current_state
@@ -353,7 +306,7 @@ EOS
     Chef::Log.debug "#{@new_resource.name} setting start_type to #{type}"
     Win32::Service.configure(
       :service_name => @new_resource.service_name,
-      :start_type => allowed_types[type]
+      :start_type => allowed_types[type],
     )
     @new_resource.updated_by_last_action(true)
   end
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index 5f36483..45002de 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
 
 #TODO subversion and git should both extend from a base SCM provider.
 
-require 'chef/log'
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'fileutils'
+require "chef/log"
+require "chef/provider"
+require "chef/mixin/command"
+require "fileutils"
 
 class Chef
   class Provider
@@ -48,7 +48,7 @@ class Chef
       end
 
       def define_resource_requirements
-        requirements.assert(:all_actions)  do |a|
+        requirements.assert(:all_actions) do |a|
           # Make sure the parent dir exists, or else fail.
           # for why run, print a message explaining the potential error.
           parent_directory = ::File.dirname(@new_resource.destination)
@@ -115,7 +115,7 @@ class Chef
       def export_command
         args = ["--force"]
         args << @new_resource.svn_arguments << verbose << authentication <<
-            "-r#{revision_int}" << @new_resource.repository << @new_resource.destination
+          "-r#{revision_int}" << @new_resource.repository << @new_resource.destination
         c = scm :export, *args
         Chef::Log.info "#{@new_resource} exported #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}"
         c
@@ -130,8 +130,8 @@ class Chef
             @new_resource.revision
           else
             command = scm(:info, @new_resource.repository, @new_resource.svn_info_args, authentication, "-r#{@new_resource.revision}")
-            status, svn_info, error_message = output_of_command(command, run_options)
-            handle_command_failures(status, "STDOUT: #{svn_info}\nSTDERR: #{error_message}")
+            svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0, 1])).stdout
+
             extract_revision_info(svn_info)
           end
         end
@@ -142,11 +142,8 @@ class Chef
       def find_current_revision
         return nil unless ::File.exist?(::File.join(@new_resource.destination, ".svn"))
         command = scm(:info)
-        status, svn_info, error_message = output_of_command(command, run_options(:cwd => cwd))
+        svn_info = shell_out!(command, run_options(:cwd => cwd, :returns => [0, 1])).stdout
 
-        unless [0,1].include?(status.exitstatus)
-          handle_command_failures(status, "STDOUT: #{svn_info}\nSTDERR: #{error_message}")
-        end
         extract_revision_info(svn_info)
       end
 
@@ -154,7 +151,7 @@ class Chef
         (!@current_resource.revision.nil?) && (revision_int.strip.to_i == @current_resource.revision.strip.to_i)
       end
 
-      def run_options(run_opts={})
+      def run_options(run_opts = {})
         run_opts[:user] = @new_resource.user if @new_resource.user
         run_opts[:group] = @new_resource.group if @new_resource.group
         run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
@@ -179,7 +176,8 @@ class Chef
           end
           attrs
         end
-        rev = (repo_attrs['Last Changed Rev'] || repo_attrs['Revision'])
+        rev = (repo_attrs["Last Changed Rev"] || repo_attrs["Revision"])
+        rev.strip! if rev
         raise "Could not parse `svn info` data: #{svn_info}" if repo_attrs.empty?
         Chef::Log.debug "#{@new_resource} resolved revision #{@new_resource.revision} to #{rev}"
         rev
@@ -197,12 +195,20 @@ class Chef
       end
 
       def scm(*args)
-        ['svn', *args].compact.join(" ")
+        binary = svn_binary
+        binary = "\"#{binary}\"" if binary =~ /\s/
+        [binary, *args].compact.join(" ")
       end
 
       def target_dir_non_existent_or_empty?
-        !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
+        !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == [".", ".."]
       end
+
+      def svn_binary
+        @new_resource.svn_binary ||
+          (Chef::Platform.windows? ? "svn.exe" : "svn")
+      end
+
       def assert_target_directory_valid!
         target_parent_directory = ::File.dirname(@new_resource.destination)
         unless ::File.directory?(target_parent_directory)
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index 1e75907..e12d465 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 # limitations under the License.
 #
 
-require 'chef/provider/template_finder'
-require 'chef/provider/file'
-require 'chef/deprecation/provider/template'
-require 'chef/deprecation/warnings'
+require "chef/provider/template_finder"
+require "chef/provider/file"
+require "chef/deprecation/provider/template"
+require "chef/deprecation/warnings"
 
 class Chef
   class Provider
diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb
index 7fc680e..acf2006 100644
--- a/lib/chef/provider/template/content.rb
+++ b/lib/chef/provider/template/content.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/template'
-require 'chef/file_content_management/content_base'
+require "chef/mixin/template"
+require "chef/file_content_management/content_base"
 
 class Chef
   class Provider
@@ -29,20 +29,30 @@ class Chef
 
         def template_location
           @template_file_cache_location ||= begin
-            template_finder.find(@new_resource.source, :local => @new_resource.local, :cookbook => @new_resource.cookbook)
+            template_finder.find(new_resource.source, :local => new_resource.local, :cookbook => new_resource.cookbook)
           end
         end
 
         private
 
         def file_for_provider
-          context = TemplateContext.new(@new_resource.variables)
-          context[:node] = @run_context.node
+          context = TemplateContext.new(new_resource.variables)
+          context[:node] = run_context.node
           context[:template_finder] = template_finder
-          context._extend_modules(@new_resource.helper_modules)
+
+          # helper variables
+          context[:cookbook_name] = new_resource.cookbook_name unless context.keys.include?(:coookbook_name)
+          context[:recipe_name] = new_resource.recipe_name unless context.keys.include?(:recipe_name)
+          context[:recipe_line_string] = new_resource.source_line unless context.keys.include?(:recipe_line_string)
+          context[:recipe_path] = new_resource.source_line_file unless context.keys.include?(:recipe_path)
+          context[:recipe_line] = new_resource.source_line_number unless context.keys.include?(:recipe_line)
+          context[:template_name] = new_resource.source unless context.keys.include?(:template_name)
+          context[:template_path] = template_location unless context.keys.include?(:template_path)
+
+          context._extend_modules(new_resource.helper_modules)
           output = context.render_template(template_location)
 
-          tempfile = Tempfile.open("chef-rendered-template")
+          tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
           tempfile.binmode
           tempfile.write(output)
           tempfile.close
@@ -51,7 +61,7 @@ class Chef
 
         def template_finder
           @template_finder ||= begin
-            TemplateFinder.new(run_context, @new_resource.cookbook_name, @run_context.node)
+            TemplateFinder.new(run_context, new_resource.cookbook_name, run_context.node)
           end
         end
       end
diff --git a/lib/chef/provider/template_finder.rb b/lib/chef/provider/template_finder.rb
index 1596a32..67342a8 100644
--- a/lib/chef/provider/template_finder.rb
+++ b/lib/chef/provider/template_finder.rb
@@ -1,6 +1,6 @@
 #--
 # Author:: Andrea Campi (<andrea.campi at zephirworks.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -41,6 +41,7 @@ class Chef
       end
 
     protected
+
       def template_source_name(name, options)
         if options[:source]
           options[:source]
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index f6ac724..85bd674 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider'
-require 'chef/mixin/command'
-require 'etc'
+require "chef/provider"
+require "chef/mixin/command"
+require "etc"
 
 class Chef
   class Provider
     class User < Chef::Provider
-
       include Chef::Mixin::Command
 
       attr_accessor :user_exists, :locked
@@ -72,9 +71,9 @@ class Chef
           end
           @current_resource.comment(user_info.gecos)
 
-          if @new_resource.password && @current_resource.password == 'x'
+          if @new_resource.password && @current_resource.password == "x"
             begin
-              require 'shadow'
+              require "shadow"
             rescue LoadError
               @shadow_lib_ok = false
             else
@@ -90,7 +89,7 @@ class Chef
       end
 
       def define_resource_requirements
-        requirements.assert(:all_actions) do |a|
+        requirements.assert(:create, :modify, :manage, :lock, :unlock) do |a|
           a.assertion { @group_name_resolved }
           a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{@new_resource.gid}"
           a.whyrun "group name #{@new_resource.gid} does not exist.  This will cause group assignment to fail.  Assuming this group will have been created previously."
@@ -99,7 +98,7 @@ class Chef
           a.assertion { @shadow_lib_ok }
           a.failure_message Chef::Exceptions::MissingLibrary, "You must have ruby-shadow installed for password support!"
           a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure.  Assuming that this gem will have been previously installed." +
-                   "Note that user update converge may report false-positive on the basis of mismatched password. "
+            "Note that user update converge may report false-positive on the basis of mismatched password. "
         end
         requirements.assert(:modify, :lock, :unlock) do |a|
           a.assertion { @user_exists }
@@ -126,7 +125,6 @@ class Chef
       end
 
       def action_create
-
         if !@user_exists
           converge_by("create user #{@new_resource.username}") do
             create_user
@@ -181,7 +179,7 @@ class Chef
             lock_user
             Chef::Log.info("#{@new_resource} locked")
           end
-         else
+        else
           Chef::Log.debug("#{@new_resource} already locked - nothing to do")
         end
       end
@@ -208,7 +206,6 @@ class Chef
       def unlock_user
         raise NotImplementedError
       end
-
     end
   end
 end
diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb
index af08ab4..42798a5 100644
--- a/lib/chef/provider/user/aix.rb
+++ b/lib/chef/provider/user/aix.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,10 @@ class Chef
   class Provider
     class User
       class Aix < Chef::Provider::User::Useradd
+        provides :user, platform: %w{aix}
 
         UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
-        
+
         def create_user
           super
           add_password
@@ -47,7 +48,7 @@ class Chef
           end
           raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if lock_info.stdout.empty?
 
-          status  = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)
+          status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)
           if status && status[1] == "true"
             @locked = true
           else
@@ -66,6 +67,7 @@ class Chef
         end
 
       private
+
         def add_password
           if @current_resource.password != @new_resource.password && @new_resource.password
             Chef::Log.debug("#{@new_resource.username} setting password to #{@new_resource.password}")
@@ -88,7 +90,7 @@ class Chef
             end
           end
         end
-          
+
       end
     end
   end
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb
index 0c0c85e..e81a01c 100644
--- a/lib/chef/provider/user/dscl.rb
+++ b/lib/chef/provider/user/dscl.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dreamcat4 (<dreamcat4 at gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'mixlib/shellout'
-require 'chef/provider/user'
-require 'openssl'
-require 'plist'
-require 'chef/util/path_helper'
+require "mixlib/shellout"
+require "chef/provider/user"
+require "openssl"
+require "plist"
+require "chef/util/path_helper"
 
 class Chef
   class Provider
@@ -44,6 +44,10 @@ class Chef
       # This provider only supports Mac OSX versions 10.7 and above
       class Dscl < Chef::Provider::User
 
+        attr_accessor :user_info
+        attr_accessor :authentication_authority
+        attr_accessor :password_shadow_conversion_algorithm
+
         provides :user, os: "darwin"
 
         def define_resource_requirements
@@ -56,19 +60,19 @@ class Chef
 
           requirements.assert(:all_actions) do |a|
             a.assertion { ::File.exists?("/usr/bin/dscl") }
-            a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{@new_resource}!")
+            a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{new_resource}!")
           end
 
           requirements.assert(:all_actions) do |a|
             a.assertion { ::File.exists?("/usr/bin/plutil") }
-            a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{@new_resource}!")
+            a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{new_resource}!")
           end
 
           requirements.assert(:create, :modify, :manage) do |a|
             a.assertion do
-              if @new_resource.password && mac_osx_version_greater_than_10_7?
+              if new_resource.password && mac_osx_version_greater_than_10_7?
                 # SALTED-SHA512 password shadow hashes are not supported on 10.8 and above.
-                !salted_sha512?(@new_resource.password)
+                !salted_sha512?(new_resource.password)
               else
                 true
               end
@@ -80,10 +84,10 @@ in 'password', with the associated 'salt' and 'iterations'.")
 
           requirements.assert(:create, :modify, :manage) do |a|
             a.assertion do
-              if @new_resource.password && mac_osx_version_greater_than_10_7? && salted_sha512_pbkdf2?(@new_resource.password)
+              if new_resource.password && mac_osx_version_greater_than_10_7? && salted_sha512_pbkdf2?(new_resource.password)
                 # salt and iterations should be specified when
                 # SALTED-SHA512-PBKDF2 password shadow hash is given
-                !@new_resource.salt.nil? && !@new_resource.iterations.nil?
+                !new_resource.salt.nil? && !new_resource.iterations.nil?
               else
                 true
               end
@@ -94,9 +98,9 @@ in 'password', with the associated 'salt' and 'iterations'.")
 
           requirements.assert(:create, :modify, :manage) do |a|
             a.assertion do
-              if @new_resource.password && !mac_osx_version_greater_than_10_7?
+              if new_resource.password && !mac_osx_version_greater_than_10_7?
                 # On 10.7 SALTED-SHA512-PBKDF2 is not supported
-                !salted_sha512_pbkdf2?(@new_resource.password)
+                !salted_sha512_pbkdf2?(new_resource.password)
               else
                 true
               end
@@ -105,25 +109,24 @@ in 'password', with the associated 'salt' and 'iterations'.")
 Mac OS X version 10.7. Please specify a SALTED-SHA512 shadow hash in 'password' attribute to set the \
 user password using shadow hash.")
           end
-
         end
 
         def load_current_resource
-          @current_resource = Chef::Resource::User.new(@new_resource.username)
-          @current_resource.username(@new_resource.username)
+          @current_resource = Chef::Resource::User.new(new_resource.username)
+          current_resource.username(new_resource.username)
 
           @user_info = read_user_info
-          if @user_info
-            @current_resource.uid(dscl_get(@user_info, :uid))
-            @current_resource.gid(dscl_get(@user_info, :gid))
-            @current_resource.home(dscl_get(@user_info, :home))
-            @current_resource.shell(dscl_get(@user_info, :shell))
-            @current_resource.comment(dscl_get(@user_info, :comment))
-            @authentication_authority = dscl_get(@user_info, :auth_authority)
-
-            if @new_resource.password && dscl_get(@user_info, :password) == "********"
+          if user_info
+            current_resource.uid(dscl_get(user_info, :uid))
+            current_resource.gid(dscl_get(user_info, :gid))
+            current_resource.home(dscl_get(user_info, :home))
+            current_resource.shell(dscl_get(user_info, :shell))
+            current_resource.comment(dscl_get(user_info, :comment))
+            @authentication_authority = dscl_get(user_info, :auth_authority)
+
+            if new_resource.password && dscl_get(user_info, :password) == "********"
               # A password is set. Let's get the password information from shadow file
-              shadow_hash_binary = dscl_get(@user_info, :shadow_hash)
+              shadow_hash_binary = dscl_get(user_info, :shadow_hash)
 
               # Calling shell_out directly since we want to give an input stream
               shadow_hash_xml = convert_binary_plist_to_xml(shadow_hash_binary.string)
@@ -132,26 +135,26 @@ user password using shadow hash.")
               if shadow_hash["SALTED-SHA512"]
                 # Convert the shadow value from Base64 encoding to hex before consuming them
                 @password_shadow_conversion_algorithm = "SALTED-SHA512"
-                @current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack('H*').first)
+                current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack("H*").first)
               elsif shadow_hash["SALTED-SHA512-PBKDF2"]
                 @password_shadow_conversion_algorithm = "SALTED-SHA512-PBKDF2"
                 # Convert the entropy from Base64 encoding to hex before consuming them
-                @current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first)
-                @current_resource.iterations(shadow_hash["SALTED-SHA512-PBKDF2"]["iterations"])
+                current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first)
+                current_resource.iterations(shadow_hash["SALTED-SHA512-PBKDF2"]["iterations"])
                 # Convert the salt from Base64 encoding to hex before consuming them
-                @current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack('H*').first)
+                current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack("H*").first)
               else
-                raise(Chef::Exceptions::User,"Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}")
+                raise(Chef::Exceptions::User, "Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}")
               end
             end
 
-            convert_group_name if @new_resource.gid
+            convert_group_name if new_resource.gid
           else
             @user_exists = false
-            Chef::Log.debug("#{@new_resource} user does not exist")
+            Chef::Log.debug("#{new_resource} user does not exist")
           end
 
-          @current_resource
+          current_resource
         end
 
         #
@@ -190,15 +193,16 @@ user password using shadow hash.")
         # Create a user using dscl
         #
         def dscl_create_user
-          run_dscl("create /Users/#{@new_resource.username}")
+          run_dscl("create /Users/#{new_resource.username}")
         end
 
         #
         # Saves the specified Chef user `comment` into RealName attribute
-        # of Mac user.
+        # of Mac user. If `comment` is not specified, it takes `username` value.
         #
         def dscl_create_comment
-          run_dscl("create /Users/#{@new_resource.username} RealName '#{@new_resource.comment}'")
+          comment = new_resource.comment || new_resource.username
+          run_dscl("create /Users/#{new_resource.username} RealName '#{comment}'")
         end
 
         #
@@ -207,22 +211,23 @@ user password using shadow hash.")
         # from 200 if `system` is set, 500 otherwise.
         #
         def dscl_set_uid
-          @new_resource.uid(get_free_uid) if (@new_resource.uid.nil? || @new_resource.uid == '')
+          # XXX: mutates the new resource
+          new_resource.uid(get_free_uid) if (new_resource.uid.nil? || new_resource.uid == "")
 
-          if uid_used?(@new_resource.uid)
-            raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{@new_resource.uid} is already in use")
+          if uid_used?(new_resource.uid)
+            raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{new_resource.uid} is already in use")
           end
 
-          run_dscl("create /Users/#{@new_resource.username} UniqueID #{@new_resource.uid}")
+          run_dscl("create /Users/#{new_resource.username} UniqueID #{new_resource.uid}")
         end
 
         #
         # Find the next available uid on the system. starting with 200 if `system` is set,
         # 500 otherwise.
         #
-        def get_free_uid(search_limit=1000)
+        def get_free_uid(search_limit = 1000)
           uid = nil
-          base_uid = @new_resource.system ? 200 : 500
+          base_uid = new_resource.system ? 200 : 500
           next_uid_guess = base_uid
           users_uids = run_dscl("list /Users uid")
           while(next_uid_guess < search_limit + base_uid)
@@ -248,7 +253,7 @@ user password using shadow hash.")
             tmap
           end
           if uid_map[uid.to_s]
-            unless uid_map[uid.to_s] == @new_resource.username.to_s
+            unless uid_map[uid.to_s] == new_resource.username.to_s
               return true
             end
           end
@@ -257,18 +262,23 @@ user password using shadow hash.")
 
         #
         # Sets the group id for the user using dscl. Fails if a group doesn't
-        # exist on the system with given group id.
+        # exist on the system with given group id. If `gid` is not specified, it
+        # sets a default Mac user group "staff", with id 20.
         #
         def dscl_set_gid
-          unless @new_resource.gid && @new_resource.gid.to_s.match(/^\d+$/)
+          if new_resource.gid.nil?
+            # XXX: mutates the new resource
+            new_resource.gid(20)
+          elsif !new_resource.gid.to_s.match(/^\d+$/)
             begin
-              possible_gid = run_dscl("read /Groups/#{@new_resource.gid} PrimaryGroupID").split(" ").last
+              possible_gid = run_dscl("read /Groups/#{new_resource.gid} PrimaryGroupID").split(" ").last
             rescue Chef::Exceptions::DsclCommandFailed => e
-              raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{@new_resource.gid} when creating user #{@new_resource.username}")
+              raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{new_resource.gid} when creating user #{new_resource.username}")
             end
-            @new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/)
+            # XXX: mutates the new resource
+            new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/)
           end
-          run_dscl("create /Users/#{@new_resource.username} PrimaryGroupID '#{@new_resource.gid}'")
+          run_dscl("create /Users/#{new_resource.username} PrimaryGroupID '#{new_resource.gid}'")
         end
 
         #
@@ -276,15 +286,15 @@ user password using shadow hash.")
         # directory is managed (moved / created) for the user.
         #
         def dscl_set_home
-          if @new_resource.home.nil? || @new_resource.home.empty?
-            run_dscl("delete /Users/#{@new_resource.username} NFSHomeDirectory")
+          if new_resource.home.nil? || new_resource.home.empty?
+            run_dscl("delete /Users/#{new_resource.username} NFSHomeDirectory")
             return
           end
 
-          if @new_resource.supports[:manage_home]
+          if new_resource.supports[:manage_home]
             validate_home_dir_specification!
 
-            if (@current_resource.home == @new_resource.home) && !new_home_exists?
+            if (current_resource.home == new_resource.home) && !new_home_exists?
               ditto_home
             elsif !current_home_exists? && !new_home_exists?
               ditto_home
@@ -292,49 +302,49 @@ user password using shadow hash.")
               move_home
             end
           end
-          run_dscl("create /Users/#{@new_resource.username} NFSHomeDirectory '#{@new_resource.home}'")
+          run_dscl("create /Users/#{new_resource.username} NFSHomeDirectory '#{new_resource.home}'")
         end
 
         def validate_home_dir_specification!
-          unless @new_resource.home =~ /^\//
-            raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{@new_resource.username}', home directory: '#{@new_resource.home}'")
+          unless new_resource.home =~ /^\//
+            raise(Chef::Exceptions::InvalidHomeDirectory, "invalid path spec for User: '#{new_resource.username}', home directory: '#{new_resource.home}'")
           end
         end
 
         def current_home_exists?
-          ::File.exist?("#{@current_resource.home}")
+          ::File.exist?("#{current_resource.home}")
         end
 
         def new_home_exists?
-          ::File.exist?("#{@new_resource.home}")
+          ::File.exist?("#{new_resource.home}")
         end
 
         def ditto_home
           skel = "/System/Library/User Template/English.lproj"
-          raise(Chef::Exceptions::User,"can't find skel at: #{skel}") unless ::File.exists?(skel)
-          shell_out! "ditto '#{skel}' '#{@new_resource.home}'"
-          ::FileUtils.chown_R(@new_resource.username, at new_resource.gid.to_s, at new_resource.home)
+          raise(Chef::Exceptions::User, "can't find skel at: #{skel}") unless ::File.exists?(skel)
+          shell_out! "ditto '#{skel}' '#{new_resource.home}'"
+          ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home)
         end
 
         def move_home
-          Chef::Log.debug("#{@new_resource} moving #{self} home from #{@current_resource.home} to #{@new_resource.home}")
+          Chef::Log.debug("#{new_resource} moving #{self} home from #{current_resource.home} to #{new_resource.home}")
 
-          src = @current_resource.home
-          FileUtils.mkdir_p(@new_resource.home)
-          files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.","#{src}/.."]
-          ::FileUtils.mv(files, at new_resource.home, :force => true)
+          src = current_resource.home
+          FileUtils.mkdir_p(new_resource.home)
+          files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.", "#{src}/.."]
+          ::FileUtils.mv(files, new_resource.home, :force => true)
           ::FileUtils.rmdir(src)
-          ::FileUtils.chown_R(@new_resource.username, at new_resource.gid.to_s, at new_resource.home)
+          ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home)
         end
 
         #
         # Sets the shell for the user using dscl.
         #
         def dscl_set_shell
-          if @new_resource.shell || ::File.exists?("#{@new_resource.shell}")
-            run_dscl("create /Users/#{@new_resource.username} UserShell '#{@new_resource.shell}'")
+          if new_resource.shell || ::File.exists?("#{new_resource.shell}")
+            run_dscl("create /Users/#{new_resource.username} UserShell '#{new_resource.shell}'")
           else
-            run_dscl("create /Users/#{@new_resource.username} UserShell '/usr/bin/false'")
+            run_dscl("create /Users/#{new_resource.username} UserShell '/usr/bin/false'")
           end
         end
 
@@ -345,17 +355,17 @@ user password using shadow hash.")
         #
         def set_password
           # Return if there is no password to set
-          return if @new_resource.password.nil?
+          return if new_resource.password.nil?
 
           shadow_info = prepare_password_shadow_info
 
           # Shadow info is saved as binary plist. Convert the info to binary plist.
           shadow_info_binary = StringIO.new
           command = Mixlib::ShellOut.new("plutil -convert binary1 -o - -",
-            :input => shadow_info.to_plist, :live_stream => shadow_info_binary)
+                                         :input => shadow_info.to_plist, :live_stream => shadow_info_binary)
           command.run_command
 
-          if @user_info.nil?
+          if user_info.nil?
             # User is  just created. read_user_info() will read the fresh information
             # for the user with a cache flush. However with experimentation we've seen
             # that dscl cache is not immediately updated after the creation of the user
@@ -365,51 +375,51 @@ user password using shadow hash.")
           end
 
           # Replace the shadow info in user's plist
-          dscl_set(@user_info, :shadow_hash, shadow_info_binary)
-          save_user_info(@user_info)
+          dscl_set(user_info, :shadow_hash, shadow_info_binary)
+          save_user_info(user_info)
         end
 
         #
         # Prepares the password shadow info based on the platform version.
         #
         def prepare_password_shadow_info
-          shadow_info = { }
+          shadow_info = {}
           entropy = nil
           salt = nil
           iterations = nil
 
           if mac_osx_version_10_7?
-            hash_value = if salted_sha512?(@new_resource.password)
-              @new_resource.password
-            else
-              # Create a random 4 byte salt
-              salt = OpenSSL::Random.random_bytes(4)
-              encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + @new_resource.password)
-              hash_value = salt.unpack('H*').first + encoded_password
-            end
+            hash_value = if salted_sha512?(new_resource.password)
+                           new_resource.password
+                         else
+                           # Create a random 4 byte salt
+                           salt = OpenSSL::Random.random_bytes(4)
+                           encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password)
+                           hash_value = salt.unpack("H*").first + encoded_password
+                         end
 
             shadow_info["SALTED-SHA512"] = StringIO.new
             shadow_info["SALTED-SHA512"].string = convert_to_binary(hash_value)
             shadow_info
           else
-            if salted_sha512_pbkdf2?(@new_resource.password)
-              entropy = convert_to_binary(@new_resource.password)
-              salt = convert_to_binary(@new_resource.salt)
-              iterations = @new_resource.iterations
+            if salted_sha512_pbkdf2?(new_resource.password)
+              entropy = convert_to_binary(new_resource.password)
+              salt = convert_to_binary(new_resource.salt)
+              iterations = new_resource.iterations
             else
               salt = OpenSSL::Random.random_bytes(32)
-              iterations = @new_resource.iterations # Use the default if not specified by the user
+              iterations = new_resource.iterations # Use the default if not specified by the user
 
               entropy = OpenSSL::PKCS5::pbkdf2_hmac(
-                @new_resource.password,
+                new_resource.password,
                 salt,
                 iterations,
                 128,
-                OpenSSL::Digest::SHA512.new
+                OpenSSL::Digest::SHA512.new,
               )
             end
 
-            pbkdf_info = { }
+            pbkdf_info = {}
             pbkdf_info["entropy"] = StringIO.new
             pbkdf_info["entropy"].string = entropy
             pbkdf_info["salt"] = StringIO.new
@@ -427,43 +437,43 @@ user password using shadow hash.")
         # and deleting home directory if needed.
         #
         def remove_user
-          if @new_resource.supports[:manage_home]
+          if new_resource.supports[:manage_home]
             # Remove home directory
-            FileUtils.rm_rf(@current_resource.home)
+            FileUtils.rm_rf(current_resource.home)
           end
 
           # Remove the user from its groups
           run_dscl("list /Groups").each_line do |group|
             if member_of_group?(group.chomp)
-              run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{@new_resource.username}'")
+              run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{new_resource.username}'")
             end
           end
 
           # Remove user account
-          run_dscl("delete /Users/#{@new_resource.username}")
+          run_dscl("delete /Users/#{new_resource.username}")
         end
 
         #
         # Locks the user.
         #
         def lock_user
-          run_dscl("append /Users/#{@new_resource.username} AuthenticationAuthority ';DisabledUser;'")
+          run_dscl("append /Users/#{new_resource.username} AuthenticationAuthority ';DisabledUser;'")
         end
 
         #
         # Unlocks the user
         #
         def unlock_user
-          auth_string = @authentication_authority.gsub(/AuthenticationAuthority: /,"").gsub(/;DisabledUser;/,"").strip
-          run_dscl("create /Users/#{@new_resource.username} AuthenticationAuthority '#{auth_string}'")
+          auth_string = authentication_authority.gsub(/AuthenticationAuthority: /, "").gsub(/;DisabledUser;/, "").strip
+          run_dscl("create /Users/#{new_resource.username} AuthenticationAuthority '#{auth_string}'")
         end
 
         #
         # Returns true if the user is locked, false otherwise.
         #
         def locked?
-          if @authentication_authority
-            !!(@authentication_authority =~ /DisabledUser/ )
+          if authentication_authority
+            !!(authentication_authority =~ /DisabledUser/ )
           else
             false
           end
@@ -485,11 +495,11 @@ user password using shadow hash.")
         # given attribute.
         #
         def diverged?(parameter)
-          parameter_updated?(parameter) && (not @new_resource.send(parameter).nil?)
+          parameter_updated?(parameter) && (not new_resource.send(parameter).nil?)
         end
 
         def parameter_updated?(parameter)
-          not (@new_resource.send(parameter) == @current_resource.send(parameter))
+          not (new_resource.send(parameter) == current_resource.send(parameter))
         end
 
         #
@@ -500,11 +510,11 @@ user password using shadow hash.")
         # type of the password specified.
         #
         def diverged_password?
-          return false if @new_resource.password.nil?
+          return false if new_resource.password.nil?
 
           # Dscl provider supports both plain text passwords and shadow hashes.
           if mac_osx_version_10_7?
-            if salted_sha512?(@new_resource.password)
+            if salted_sha512?(new_resource.password)
               diverged?(:password)
             else
               !salted_sha512_password_match?
@@ -514,14 +524,14 @@ user password using shadow hash.")
             # will be updated when the user logs in. So it's possible that we will have
             # SALTED-SHA512 password in the current_resource. In that case we will force
             # password to be updated.
-            return true if salted_sha512?(@current_resource.password)
+            return true if salted_sha512?(current_resource.password)
 
             # Some system users don't have salts; this can happen if the system is
             # upgraded and the user hasn't logged in yet. In this case, we will force
             # the password to be updated.
-            return true if @current_resource.salt.nil?
+            return true if current_resource.salt.nil?
 
-            if salted_sha512_pbkdf2?(@new_resource.password)
+            if salted_sha512_pbkdf2?(new_resource.password)
               diverged?(:password) || diverged?(:salt) || diverged?(:iterations)
             else
               !salted_sha512_pbkdf2_password_match?
@@ -543,7 +553,7 @@ user password using shadow hash.")
           # GroupMembership: root admin etc
           members = membership_info.split(" ")
           members.shift # Get rid of GroupMembership: string
-          members.include?(@new_resource.username)
+          members.include?(new_resource.username)
         end
 
         #
@@ -559,7 +569,7 @@ user password using shadow hash.")
           :comment => "realname",
           :password => "passwd",
           :auth_authority => "authentication_authority",
-          :shadow_hash => "ShadowHashData"
+          :shadow_hash => "ShadowHashData",
         }.freeze
 
         # Directory where the user plist files are stored for versions 10.7 and above
@@ -577,7 +587,7 @@ user password using shadow hash.")
           shell_out("dscacheutil '-flushcache'")
 
           begin
-            user_plist_file = "#{USER_PLIST_DIRECTORY}/#{@new_resource.username}.plist"
+            user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
             user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}")
             user_info = Plist::parse_xml(user_plist_info)
           rescue Chef::Exceptions::PlistUtilCommandFailed
@@ -591,7 +601,7 @@ user password using shadow hash.")
         # in DSCL_PROPERTY_MAP to the disk.
         #
         def save_user_info(user_info)
-          user_plist_file = "#{USER_PLIST_DIRECTORY}/#{@new_resource.username}.plist"
+          user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist"
           Plist::Emit.save_plist(user_info, user_plist_file)
           run_plutil("convert binary1 #{user_plist_file}")
         end
@@ -644,16 +654,16 @@ user password using shadow hash.")
         def run_dscl(*args)
           result = shell_out("dscl . -#{args.join(' ')}")
           return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 )
-          raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") unless result.exitstatus == 0
-          raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") if result.stdout =~ /No such key: /
+          raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") unless result.exitstatus == 0
+          raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout =~ /No such key: /
           result.stdout
         end
 
         def run_plutil(*args)
           result = shell_out("plutil -#{args.join(' ')}")
-          raise(Chef::Exceptions::PlistUtilCommandFailed,"plutil error: #{result.inspect}") unless result.exitstatus == 0
+          raise(Chef::Exceptions::PlistUtilCommandFailed, "plutil error: #{result.inspect}") unless result.exitstatus == 0
           if result.stdout.encoding == Encoding::ASCII_8BIT
-            result.stdout.encode("utf-8", "binary",  :undef => :replace, :invalid => :replace, :replace => '?')
+            result.stdout.encode("utf-8", "binary", :undef => :replace, :invalid => :replace, :replace => "?")
           else
             result.stdout
           end
@@ -664,7 +674,7 @@ user password using shadow hash.")
         end
 
         def convert_to_binary(string)
-          string.unpack('a2'*(string.size/2)).collect { |i| i.hex.chr }.join
+          string.unpack("a2" * (string.size / 2)).collect { |i| i.hex.chr }.join
         end
 
         def salted_sha512?(string)
@@ -673,9 +683,9 @@ user password using shadow hash.")
 
         def salted_sha512_password_match?
           # Salt is included in the first 4 bytes of shadow data
-          salt = @current_resource.password.slice(0,8)
-          shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) + @new_resource.password)
-          @current_resource.password == salt + shadow
+          salt = current_resource.password.slice(0, 8)
+          shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) + new_resource.password)
+          current_resource.password == salt + shadow
         end
 
         def salted_sha512_pbkdf2?(string)
@@ -683,15 +693,15 @@ user password using shadow hash.")
         end
 
         def salted_sha512_pbkdf2_password_match?
-          salt = convert_to_binary(@current_resource.salt)
+          salt = convert_to_binary(current_resource.salt)
 
           OpenSSL::PKCS5::pbkdf2_hmac(
-            @new_resource.password,
+            new_resource.password,
             salt,
-            @current_resource.iterations,
+            current_resource.iterations,
             128,
-            OpenSSL::Digest::SHA512.new
-          ).unpack('H*').first == @current_resource.password
+            OpenSSL::Digest::SHA512.new,
+          ).unpack("H*").first == current_resource.password
         end
 
       end
diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb
index fe71e93..949a217 100644
--- a/lib/chef/provider/user/pw.rb
+++ b/lib/chef/provider/user/pw.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/provider/user'
+require "chef/provider/user"
 
 class Chef
   class Provider
     class User
       class Pw < Chef::Provider::User
+        provides :user, platform: %w{freebsd}
 
         def load_current_resource
           super
@@ -70,13 +71,13 @@ class Chef
           opts = " #{@new_resource.username}"
 
           field_list = {
-            'comment' => "-c",
-            'home' => "-d",
-            'gid' => "-g",
-            'uid' => "-u",
-            'shell' => "-s"
+            "comment" => "-c",
+            "home" => "-d",
+            "gid" => "-g",
+            "uid" => "-u",
+            "shell" => "-s",
           }
-          field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
+          field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
             field_symbol = field.to_sym
             if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
               if @new_resource.send(field_symbol)
diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb
index d480aca..1f0cbb6 100644
--- a/lib/chef/provider/user/solaris.rb
+++ b/lib/chef/provider/user/solaris.rb
@@ -1,7 +1,9 @@
 #
-# Author:: Stephen Nelson-Smith (<sns at opscode.com>)
+# Author:: Stephen Nelson-Smith (<sns at chef.io>)
 # Author:: Jon Ramsey (<jonathon.ramsey at gmail.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Dave Eddy (<dave at daveeddy.com>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# Copyright:: Copyright 2015-2016, Dave Eddy
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +18,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/provider/user/useradd'
+require "chef/provider/user/useradd"
 
 class Chef
   class Provider
     class User
       class Solaris < Chef::Provider::User::Useradd
+        provides :user, platform: %w{omnios solaris2}
         UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]]
 
         attr_writer :password_file
@@ -41,6 +44,32 @@ class Chef
           super
         end
 
+        def check_lock
+          shadow_line = shell_out!("getent", "shadow", new_resource.username).stdout.strip rescue nil
+
+          # if the command fails we return nil, this can happen if the user
+          # in question doesn't exist
+          return nil if shadow_line.nil?
+
+          # convert "dave:NP:16507::::::\n" to "NP"
+          fields = shadow_line.split(":")
+
+          # '*LK*...' and 'LK' are both considered locked,
+          # so look for LK at the beginning of the shadow entry
+          # optionally surrounded by '*'
+          @locked = !!fields[1].match(/^\*?LK\*?/)
+
+          @locked
+        end
+
+        def lock_user
+          shell_out!("passwd", "-l", new_resource.username)
+        end
+
+        def unlock_user
+          shell_out!("passwd", "-u", new_resource.username)
+        end
+
       private
 
         def manage_password
@@ -65,9 +94,10 @@ class Chef
           buffer.close
 
           # FIXME: mostly duplicates code with file provider deploying a file
-          mode = ::File.stat(@password_file).mode & 07777
-          uid  = ::File.stat(@password_file).uid
-          gid  = ::File.stat(@password_file).gid
+          s = ::File.stat(@password_file)
+          mode = s.mode & 07777
+          uid  = s.uid
+          gid  = s.gid
 
           FileUtils.chown uid, gid, buffer.path
           FileUtils.chmod mode, buffer.path
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index cc770c0..aabd4b5 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,14 @@
 # limitations under the License.
 #
 
-require 'pathname'
-require 'chef/provider/user'
+require "pathname"
+require "chef/provider/user"
 
 class Chef
   class Provider
     class User
       class Useradd < Chef::Provider::User
+        provides :user
 
         UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]]
 
@@ -54,7 +55,7 @@ class Chef
         def check_lock
           # we can get an exit code of 1 even when it's successful on
           # rhel/centos (redhat bug 578534). See additional error checks below.
-          passwd_s = shell_out!("passwd", "-S", new_resource.username, :returns => [0,1])
+          passwd_s = shell_out!("passwd", "-S", new_resource.username, :returns => [0, 1])
           if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/)
             # if we're in whyrun mode and the user is not yet created we assume it would be
             return false
@@ -62,7 +63,7 @@ class Chef
 
           raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if passwd_s.stdout.empty?
 
-          status_line = passwd_s.stdout.split(' ')
+          status_line = passwd_s.stdout.split(" ")
           case status_line[1]
           when /^P/
             @locked = false
@@ -74,11 +75,11 @@ class Chef
 
           unless passwd_s.exitstatus == 0
             raise_lock_error = false
-            if ['redhat', 'centos'].include?(node[:platform])
-              passwd_version_check = shell_out!('rpm -q passwd')
+            if ["redhat", "centos"].include?(node[:platform])
+              passwd_version_check = shell_out!("rpm -q passwd")
               passwd_version = passwd_version_check.stdout.chomp
 
-              unless passwd_version == 'passwd-0.73-1'
+              unless passwd_version == "passwd-0.73-1"
                 raise_lock_error = true
               end
             else
diff --git a/lib/chef/provider/user/windows.rb b/lib/chef/provider/user/windows.rb
index e282a11..9545b1f 100644
--- a/lib/chef/provider/user/windows.rb
+++ b/lib/chef/provider/user/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/provider/user'
-require 'chef/exceptions'
+require "chef/provider/user"
+require "chef/exceptions"
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'chef/util/windows/net_user'
+  require "chef/util/windows/net_user"
 end
 
 class Chef
@@ -29,12 +29,16 @@ class Chef
 
         provides :user, os: "windows"
 
-        def initialize(new_resource,run_context)
+        def initialize(new_resource, run_context)
           super
           @net_user = Chef::Util::Windows::NetUser.new(@new_resource.username)
         end
 
         def load_current_resource
+          if @new_resource.gid
+            Chef::Log.warn("The 'gid' attribute is not implemented by the Windows platform. Please use the 'group' resource to assign a user to a group.")
+          end
+
           @current_resource = Chef::Resource::User.new(@new_resource.name)
           @current_resource.username(@new_resource.username)
           user_info = nil
@@ -42,7 +46,6 @@ class Chef
             user_info = @net_user.get_info
 
             @current_resource.uid(user_info[:user_id])
-            @current_resource.gid(user_info[:primary_group_id])
             @current_resource.comment(user_info[:full_name])
             @current_resource.home(user_info[:home_dir])
             @current_resource.shell(user_info[:script_path])
@@ -65,7 +68,7 @@ class Chef
             Chef::Log.debug("#{@new_resource} password has changed")
             return true
           end
-          [ :uid, :gid, :comment, :home, :shell ].any? do |user_attrib|
+          [ :uid, :comment, :home, :shell ].any? do |user_attrib|
             !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib)
           end
         end
@@ -95,18 +98,17 @@ class Chef
         end
 
         def set_options
-          opts = {:name => @new_resource.username}
+          opts = { :name => @new_resource.username }
 
           field_list = {
-            'comment' => 'full_name',
-            'home' => 'home_dir',
-            'gid' => 'primary_group_id',
-            'uid' => 'user_id',
-            'shell' => 'script_path',
-            'password' => 'password'
+            "comment" => "full_name",
+            "home" => "home_dir",
+            "uid" => "user_id",
+            "shell" => "script_path",
+            "password" => "password",
           }
 
-          field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
+          field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option|
             field_symbol = field.to_sym
             if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
               if @new_resource.send(field_symbol)
diff --git a/lib/chef/provider/whyrun_safe_ruby_block.rb b/lib/chef/provider/whyrun_safe_ruby_block.rb
index 3b95752..3ea4801 100644
--- a/lib/chef/provider/whyrun_safe_ruby_block.rb
+++ b/lib/chef/provider/whyrun_safe_ruby_block.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Phil Dibowitz (<phild at fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/provider/windows_script.rb b/lib/chef/provider/windows_script.rb
index e600bb2..2de127a 100644
--- a/lib/chef/provider/windows_script.rb
+++ b/lib/chef/provider/windows_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,20 @@
 # limitations under the License.
 #
 
-require 'chef/provider/script'
-require 'chef/mixin/windows_architecture_helper'
+require "chef/provider/script"
+require "chef/mixin/windows_architecture_helper"
 
 class Chef
   class Provider
     class WindowsScript < Chef::Provider::Script
 
+      attr_reader :is_forced_32bit
+
       protected
 
       include Chef::Mixin::WindowsArchitectureHelper
 
-      def initialize( new_resource, run_context, script_extension='')
+      def initialize( new_resource, run_context, script_extension = "")
         super( new_resource, run_context )
         @script_extension = script_extension
 
@@ -36,11 +38,7 @@ class Chef
 
         @is_wow64 = wow64_architecture_override_required?(run_context.node, target_architecture)
 
-        # if the user wants to run the script 32 bit && we are on a 64bit windows system && we are running a 64bit ruby ==> fail
-        if ( target_architecture == :i386 ) && node_windows_architecture(run_context.node) == :x86_64 && !is_i386_process_on_x86_64_windows?
-          raise Chef::Exceptions::Win32ArchitectureIncorrect,
-          "Support for the i386 architecture from a 64-bit Ruby runtime is not yet implemented"
-        end
+        @is_forced_32bit = forced_32bit_override_required?(run_context.node, target_architecture)
       end
 
       public
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index 5e88722..1df473a 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Richard Manyanza (<liseki at nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,34 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/platform/provider_priority_map'
+require "chef/exceptions"
+require "chef/platform/priority_map"
 
 class Chef
+  #
+  # Provider Resolution
+  # ===================
+  #
+  # Provider resolution is the process of taking a Resource object and an
+  # action, and determining the Provider class that should be instantiated to
+  # handle the action.
+  #
+  # If the resource has its `provider` set, that is used.
+  #
+  # Otherwise, we take the lists of Providers that have registered as
+  # providing the DSL through `provides :dsl_name, <filters>` or
+  # `Chef.set_resource_priority_array :dsl_name, <filters>`.  We filter each
+  # list of Providers through:
+  #
+  # 1. The filters it was registered with (such as `os: 'linux'` or
+  #    `platform_family: 'debian'`)
+  # 2. `provides?(node, resource)`
+  # 3. `supports?(resource, action)`
+  #
+  # Anything that passes the filter and returns `true` to provides and supports,
+  # is considered a match.  The first matching Provider in the *most recently
+  # registered list* is selected and returned.
+  #
   class ProviderResolver
 
     attr_reader :node
@@ -32,37 +56,53 @@ class Chef
       @action = action
     end
 
-    # return a deterministically sorted list of Chef::Provider subclasses
-    def providers
-      @providers ||= Chef::Provider.descendants
-    end
-
     def resolve
       maybe_explicit_provider(resource) ||
         maybe_dynamic_provider_resolution(resource, action) ||
         maybe_chef_platform_lookup(resource)
     end
 
-    # this cut looks at if the provider can handle the resource type on the node
+    # Does NOT call provides? on the resource (it is assumed this is being
+    # called *from* provides?).
+    def provided_by?(provider_class)
+      potential_handlers.include?(provider_class)
+    end
+
     def enabled_handlers
-      @enabled_handlers ||=
-        providers.select do |klass|
-          # NB: this is different from resource_resolver which must pass a resource_name
-          # FIXME: deprecate this and normalize on passing resource_name here
-          klass.provides?(node, resource)
-        end.sort {|a,b| a.to_s <=> b.to_s }
+      @enabled_handlers ||= potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource) }
     end
 
-    # this cut looks at if the provider can handle the specific resource and action
+    # TODO deprecate this and allow actions to be passed as a filter to
+    # `provides` so we don't have to have two separate things.
+    # @api private
     def supported_handlers
-      @supported_handlers ||=
-        enabled_handlers.select do |klass|
-          klass.supports?(resource, action)
-        end
+      enabled_handlers.select { |handler| handler.supports?(resource, action) }
     end
 
     private
 
+    def potential_handlers
+      handler_map.list(node, resource.resource_name).uniq
+    end
+
+    # The list of handlers, with any in the priority_map moved to the front
+    def prioritized_handlers
+      @prioritized_handlers ||= begin
+        supported_handlers = self.supported_handlers
+        if supported_handlers.empty?
+          # if none of the providers specifically support the resource, we still need to pick one of the providers that are
+          # enabled on the node to handle the why-run use case. FIXME we should only do this in why-run mode then.
+          Chef::Log.debug "No providers responded true to `supports?` for action #{action} on resource #{resource}, falling back to enabled handlers so we can return something anyway."
+          supported_handlers = enabled_handlers
+        end
+
+        prioritized = priority_map.list(node, resource.resource_name).flatten(1)
+        prioritized &= supported_handlers # Filter the priority map by the actual enabled handlers
+        prioritized |= supported_handlers # Bring back any handlers that aren't in the priority map, at the *end* (ordered set)
+        prioritized
+      end
+    end
+
     # if resource.provider is set, just return one of those objects
     def maybe_explicit_provider(resource)
       return nil unless resource.provider
@@ -71,40 +111,17 @@ class Chef
 
     # try dynamically finding a provider based on querying the providers to see what they support
     def maybe_dynamic_provider_resolution(resource, action)
-      # log this so we know what providers will work for the generic resource on the node (early cut)
-      Chef::Log.debug "providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
-
-      # what providers were excluded by machine state (late cut)
-      Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}"
-      Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}"
-
-      # if none of the providers specifically support the resource, we still need to pick one of the providers that are
-      # enabled on the node to handle the why-run use case.
-      handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers
-      Chef::Log.debug "no providers supported the resource, falling back to enabled handlers" if supported_handlers.empty?
-
-      if handlers.count >= 2
-        # this magic stack ranks the providers by where they appear in the provider_priority_map, it is mostly used
-        # to pick amongst N different ways to start init scripts on different debian/ubuntu systems.
-        priority_list = [ get_priority_array(node, resource.resource_name) ].flatten.compact
-        handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
-        if priority_list.index(handlers.first).nil?
-          # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
-          # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
-          Chef::Log.warn "Ambiguous provider precedence: #{handlers}, please use Chef.set_provider_priority_array to provide determinism"
-        end
-        handlers = [ handlers.first ]
-      end
-
-      Chef::Log.debug "providers that survived replacement include: #{handlers}"
-
-      raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2
+      Chef::Log.debug "Providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
 
-      Chef::Log.debug "dynamic provider resolver FAILED to resolve a provider" if handlers.empty?
+      handler = prioritized_handlers.first
 
-      return nil if handlers.empty?
+      if handler
+        Chef::Log.debug "Provider for action #{action} on resource #{resource} is #{handler}"
+      else
+        Chef::Log.debug "Dynamic provider resolver FAILED to resolve a provider for action #{action} on resource #{resource}"
+      end
 
-      handlers[0]
+      handler
     end
 
     # try the old static lookup of providers by platform
@@ -112,13 +129,42 @@ class Chef
       Chef::Platform.find_provider_for_node(node, resource)
     end
 
-    # dep injection hooks
-    def get_priority_array(node, resource_name)
-      provider_priority_map.get_priority_array(node, resource_name)
+    def priority_map
+      Chef.provider_priority_map
+    end
+
+    def handler_map
+      Chef.provider_handler_map
     end
 
-    def provider_priority_map
-      Chef::Platform::ProviderPriorityMap.instance
+    def overrode_provides?(handler)
+      handler.method(:provides?).owner != Chef::Provider.method(:provides?).owner
+    end
+
+    module Deprecated
+      # return a deterministically sorted list of Chef::Provider subclasses
+      def providers
+        @providers ||= Chef::Provider.descendants
+      end
+
+      def enabled_handlers
+        @enabled_handlers ||= begin
+          handlers = super
+          if handlers.empty?
+            # Look through all providers, and find ones that return true to provides.
+            # Don't bother with ones that don't override provides?, since they
+            # would have been in enabled_handlers already if that were so. (It's a
+            # perf concern otherwise.)
+            handlers = providers.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource) }
+            handlers.each do |handler|
+              Chef.log_deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource.resource_name}, but provides #{resource.resource_name.inspect} was never called!")
+              Chef.log_deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+            end
+          end
+          handlers
+        end
+      end
     end
+    prepend Deprecated
   end
 end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index a5f5386..8af25b4 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,122 +16,126 @@
 # limitations under the License.
 #
 
-require 'chef/provider/batch'
-require 'chef/provider/breakpoint'
-require 'chef/provider/cookbook_file'
-require 'chef/provider/cron'
-require 'chef/provider/cron/solaris'
-require 'chef/provider/cron/aix'
-require 'chef/provider/deploy'
-require 'chef/provider/directory'
-require 'chef/provider/dsc_script'
-require 'chef/provider/dsc_resource'
-require 'chef/provider/env'
-require 'chef/provider/erl_call'
-require 'chef/provider/execute'
-require 'chef/provider/file'
-require 'chef/provider/git'
-require 'chef/provider/group'
-require 'chef/provider/http_request'
-require 'chef/provider/ifconfig'
-require 'chef/provider/link'
-require 'chef/provider/log'
-require 'chef/provider/ohai'
-require 'chef/provider/mdadm'
-require 'chef/provider/mount'
-require 'chef/provider/package'
-require 'chef/provider/powershell_script'
-require 'chef/provider/reboot'
-require 'chef/provider/remote_directory'
-require 'chef/provider/remote_file'
-require 'chef/provider/route'
-require 'chef/provider/ruby_block'
-require 'chef/provider/script'
-require 'chef/provider/service'
-require 'chef/provider/subversion'
-require 'chef/provider/template'
-require 'chef/provider/user'
-require 'chef/provider/whyrun_safe_ruby_block'
+require "chef/provider/apt_update"
+require "chef/provider/batch"
+require "chef/provider/breakpoint"
+require "chef/provider/cookbook_file"
+require "chef/provider/cron"
+require "chef/provider/cron/solaris"
+require "chef/provider/cron/aix"
+require "chef/provider/deploy"
+require "chef/provider/directory"
+require "chef/provider/dsc_script"
+require "chef/provider/dsc_resource"
+require "chef/provider/env"
+require "chef/provider/erl_call"
+require "chef/provider/execute"
+require "chef/provider/file"
+require "chef/provider/git"
+require "chef/provider/group"
+require "chef/provider/http_request"
+require "chef/provider/ifconfig"
+require "chef/provider/link"
+require "chef/provider/log"
+require "chef/provider/ohai"
+require "chef/provider/mdadm"
+require "chef/provider/mount"
+require "chef/provider/package"
+require "chef/provider/powershell_script"
+require "chef/provider/osx_profile"
+require "chef/provider/reboot"
+require "chef/provider/remote_directory"
+require "chef/provider/remote_file"
+require "chef/provider/route"
+require "chef/provider/ruby_block"
+require "chef/provider/script"
+require "chef/provider/service"
+require "chef/provider/subversion"
+require "chef/provider/template"
+require "chef/provider/user"
+require "chef/provider/whyrun_safe_ruby_block"
 
-require 'chef/provider/env/windows'
+require "chef/provider/env/windows"
 
-require 'chef/provider/package/apt'
-require 'chef/provider/package/dpkg'
-require 'chef/provider/package/easy_install'
-require 'chef/provider/package/freebsd/port'
-require 'chef/provider/package/freebsd/pkg'
-require 'chef/provider/package/freebsd/pkgng'
-require 'chef/provider/package/homebrew'
-require 'chef/provider/package/ips'
-require 'chef/provider/package/macports'
-require 'chef/provider/package/openbsd'
-require 'chef/provider/package/pacman'
-require 'chef/provider/package/portage'
-require 'chef/provider/package/paludis'
-require 'chef/provider/package/rpm'
-require 'chef/provider/package/rubygems'
-require 'chef/provider/package/yum'
-require 'chef/provider/package/zypper'
-require 'chef/provider/package/solaris'
-require 'chef/provider/package/smartos'
-require 'chef/provider/package/aix'
+require "chef/provider/package/apt"
+require "chef/provider/package/chocolatey"
+require "chef/provider/package/dpkg"
+require "chef/provider/package/easy_install"
+require "chef/provider/package/freebsd/port"
+require "chef/provider/package/freebsd/pkg"
+require "chef/provider/package/freebsd/pkgng"
+require "chef/provider/package/homebrew"
+require "chef/provider/package/ips"
+require "chef/provider/package/macports"
+require "chef/provider/package/openbsd"
+require "chef/provider/package/pacman"
+require "chef/provider/package/portage"
+require "chef/provider/package/paludis"
+require "chef/provider/package/rpm"
+require "chef/provider/package/rubygems"
+require "chef/provider/package/yum"
+require "chef/provider/package/zypper"
+require "chef/provider/package/solaris"
+require "chef/provider/package/smartos"
+require "chef/provider/package/aix"
 
-require 'chef/provider/service/arch'
-require 'chef/provider/service/freebsd'
-require 'chef/provider/service/gentoo'
-require 'chef/provider/service/init'
-require 'chef/provider/service/invokercd'
-require 'chef/provider/service/debian'
-require 'chef/provider/service/openbsd'
-require 'chef/provider/service/redhat'
-require 'chef/provider/service/insserv'
-require 'chef/provider/service/simple'
-require 'chef/provider/service/systemd'
-require 'chef/provider/service/upstart'
-require 'chef/provider/service/windows'
-require 'chef/provider/service/solaris'
-require 'chef/provider/service/macosx'
-require 'chef/provider/service/aixinit'
-require 'chef/provider/service/aix'
+require "chef/provider/service/arch"
+require "chef/provider/service/freebsd"
+require "chef/provider/service/gentoo"
+require "chef/provider/service/init"
+require "chef/provider/service/invokercd"
+require "chef/provider/service/debian"
+require "chef/provider/service/openbsd"
+require "chef/provider/service/redhat"
+require "chef/provider/service/insserv"
+require "chef/provider/service/simple"
+require "chef/provider/service/systemd"
+require "chef/provider/service/upstart"
+require "chef/provider/service/windows"
+require "chef/provider/service/solaris"
+require "chef/provider/service/macosx"
+require "chef/provider/service/aixinit"
+require "chef/provider/service/aix"
 
-require 'chef/provider/user/dscl'
-require 'chef/provider/user/pw'
-require 'chef/provider/user/useradd'
-require 'chef/provider/user/windows'
-require 'chef/provider/user/solaris'
-require 'chef/provider/user/aix'
+require "chef/provider/user/dscl"
+require "chef/provider/user/pw"
+require "chef/provider/user/useradd"
+require "chef/provider/user/windows"
+require "chef/provider/user/solaris"
+require "chef/provider/user/aix"
 
-require 'chef/provider/group/aix'
-require 'chef/provider/group/dscl'
-require 'chef/provider/group/gpasswd'
-require 'chef/provider/group/groupadd'
-require 'chef/provider/group/groupmod'
-require 'chef/provider/group/pw'
-require 'chef/provider/group/suse'
-require 'chef/provider/group/usermod'
-require 'chef/provider/group/windows'
+require "chef/provider/group/aix"
+require "chef/provider/group/dscl"
+require "chef/provider/group/gpasswd"
+require "chef/provider/group/groupadd"
+require "chef/provider/group/groupmod"
+require "chef/provider/group/pw"
+require "chef/provider/group/suse"
+require "chef/provider/group/usermod"
+require "chef/provider/group/windows"
 
-require 'chef/provider/mount/mount'
-require 'chef/provider/mount/aix'
-require 'chef/provider/mount/solaris'
-require 'chef/provider/mount/windows'
+require "chef/provider/mount/mount"
+require "chef/provider/mount/aix"
+require "chef/provider/mount/solaris"
+require "chef/provider/mount/windows"
 
-require 'chef/provider/deploy/revision'
-require 'chef/provider/deploy/timestamped'
+require "chef/provider/deploy/revision"
+require "chef/provider/deploy/timestamped"
 
-require 'chef/provider/remote_file/ftp'
-require 'chef/provider/remote_file/http'
-require 'chef/provider/remote_file/local_file'
-require 'chef/provider/remote_file/fetcher'
+require "chef/provider/remote_file/ftp"
+require "chef/provider/remote_file/http"
+require "chef/provider/remote_file/local_file"
+require "chef/provider/remote_file/network_file"
+require "chef/provider/remote_file/fetcher"
 
 require "chef/provider/lwrp_base"
-require 'chef/provider/registry_key'
+require "chef/provider/registry_key"
 
-require 'chef/provider/file/content'
-require 'chef/provider/remote_file/content'
-require 'chef/provider/cookbook_file/content'
-require 'chef/provider/template/content'
+require "chef/provider/file/content"
+require "chef/provider/remote_file/content"
+require "chef/provider/cookbook_file/content"
+require "chef/provider/template/content"
 
-require 'chef/provider/ifconfig/redhat'
-require 'chef/provider/ifconfig/debian'
-require 'chef/provider/ifconfig/aix'
+require "chef/provider/ifconfig/redhat"
+require "chef/provider/ifconfig/debian"
+require "chef/provider/ifconfig/aix"
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index b4d37c2..3a91781 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -1,7 +1,7 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,33 +17,25 @@
 # limitations under the License.
 #
 
+require "chef/dsl/recipe"
+require "chef/dsl/data_query"
+require "chef/dsl/platform_introspection"
+require "chef/dsl/include_recipe"
+require "chef/dsl/registry_helper"
+require "chef/dsl/reboot_pending"
+require "chef/dsl/audit"
+require "chef/dsl/powershell"
 
-require 'chef/dsl/recipe'
-require 'chef/dsl/data_query'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/include_recipe'
-require 'chef/dsl/registry_helper'
-require 'chef/dsl/reboot_pending'
-require 'chef/dsl/audit'
-require 'chef/dsl/powershell'
+require "chef/mixin/from_file"
 
-require 'chef/mixin/from_file'
-
-require 'chef/mixin/deprecation'
+require "chef/mixin/deprecation"
 
 class Chef
   # == Chef::Recipe
   # A Recipe object is the context in which Chef recipes are evaluated.
   class Recipe
 
-    include Chef::DSL::DataQuery
-    include Chef::DSL::PlatformIntrospection
-    include Chef::DSL::IncludeRecipe
-    include Chef::DSL::Recipe
-    include Chef::DSL::RegistryHelper
-    include Chef::DSL::RebootPending
-    include Chef::DSL::Audit
-    include Chef::DSL::Powershell
+    include Chef::DSL::Recipe::FullDSL
 
     include Chef::Mixin::FromFile
     include Chef::Mixin::Deprecation
@@ -104,10 +96,8 @@ class Chef
     # true<TrueClass>:: If all the parameters are present
     # false<FalseClass>:: If any of the parameters are missing
     def tagged?(*tags)
-      return false if run_context.node[:tags].nil?
-
       tags.each do |tag|
-        return false unless run_context.node[:tags].include?(tag)
+        return false unless run_context.node.tags.include?(tag)
       end
       true
     end
@@ -118,10 +108,10 @@ class Chef
     # tags<Array>:: A list of tags
     #
     # === Returns
-    # tags<Array>:: The current list of run_context.node[:tags]
+    # tags<Array>:: The current list of run_context.node.tags
     def untag(*tags)
       tags.each do |tag|
-        run_context.node.normal[:tags].delete(tag)
+        run_context.node.tags.delete(tag)
       end
     end
 
diff --git a/lib/chef/request_id.rb b/lib/chef/request_id.rb
index 2c7af01..33e54d9 100644
--- a/lib/chef/request_id.rb
+++ b/lib/chef/request_id.rb
@@ -1,5 +1,5 @@
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013, 2014 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # limitations under the License.
 #
 
-require 'securerandom'
-require 'singleton'
+require "securerandom"
+require "singleton"
 
 class Chef
   class RequestID
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index d934ec8..032effe 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -1,7 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io)
+# Copyright:: Copyright 2008-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,23 +18,32 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/params_validate'
-require 'chef/dsl/platform_introspection'
-require 'chef/dsl/data_query'
-require 'chef/dsl/registry_helper'
-require 'chef/dsl/reboot_pending'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/guard_interpreter/resource_guard_interpreter'
-require 'chef/resource/conditional'
-require 'chef/resource/conditional_action_not_nothing'
-require 'chef/resource_collection'
-require 'chef/node_map'
-require 'chef/node'
-require 'chef/platform'
-require 'chef/resource/resource_notification'
-
-require 'chef/mixin/deprecation'
-require 'chef/mixin/provides'
+require "chef/exceptions"
+require "chef/dsl/platform_introspection"
+require "chef/dsl/data_query"
+require "chef/dsl/registry_helper"
+require "chef/dsl/reboot_pending"
+require "chef/dsl/resources"
+require "chef/mixin/convert_to_class_name"
+require "chef/guard_interpreter/resource_guard_interpreter"
+require "chef/resource/conditional"
+require "chef/resource/conditional_action_not_nothing"
+require "chef/resource/action_class"
+require "chef/resource_collection"
+require "chef/node_map"
+require "chef/node"
+require "chef/platform"
+require "chef/resource/resource_notification"
+require "chef/provider_resolver"
+require "chef/resource_resolver"
+require "chef/provider"
+require "set"
+
+require "chef/mixin/deprecation"
+require "chef/mixin/properties"
+require "chef/mixin/provides"
+require "chef/mixin/shell_out"
+require "chef/mixin/powershell_out"
 
 class Chef
   class Resource
@@ -48,6 +58,38 @@ class Chef
     include Chef::DSL::RebootPending
     extend Chef::Mixin::Provides
 
+    # This lets user code do things like `not_if { shell_out!("command") }`
+    include Chef::Mixin::ShellOut
+    include Chef::Mixin::PowershellOut
+
+    # Bring in `property` and `property_type`
+    include Chef::Mixin::Properties
+
+    #
+    # The name of this particular resource.
+    #
+    # This special resource attribute is set automatically from the declaration
+    # of the resource, e.g.
+    #
+    #   execute 'Vitruvius' do
+    #     command 'ls'
+    #   end
+    #
+    # Will set the name to "Vitruvius".
+    #
+    # This is also used in to_s to show the resource name, e.g. `execute[Vitruvius]`.
+    #
+    # This is also used for resource notifications and subscribes in the same manner.
+    #
+    # This will coerce any object into a string via #to_s.  Arrays are a special case
+    # so that `package ["foo", "bar"]` becomes package[foo, bar] instead of the more
+    # awkward `package[["foo", "bar"]]` that #to_s would produce.
+    #
+    # @param name [Object] The name to set, typically a String or Array
+    # @return [String] The name of this Resource.
+    #
+    property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(", ") : v.to_s }, desired_state: false
+
     #
     # The node the current Chef run is using.
     #
@@ -79,7 +121,6 @@ class Chef
       run_context.resource_collection.find(*args)
     end
 
-
     #
     # Resource User Interface (for users)
     #
@@ -91,15 +132,15 @@ class Chef
     #   used for notifications to this resource).
     # @param run_context The context of the Chef run. Corresponds to #run_context.
     #
-    def initialize(name, run_context=nil)
-      name(name)
+    def initialize(name, run_context = nil)
+      name(name) unless name.nil?
       @run_context = run_context
       @noop = nil
       @before = nil
       @params = Hash.new
       @provider = nil
-      @allowed_actions = [ :nothing ]
-      @action = :nothing
+      @allowed_actions = self.class.allowed_actions.to_a
+      @action = self.class.default_action
       @updated = false
       @updated_by_last_action = false
       @supports = {}
@@ -121,67 +162,34 @@ class Chef
     end
 
     #
-    # The name of this particular resource.
-    #
-    # This special resource attribute is set automatically from the declaration
-    # of the resource, e.g.
-    #
-    #   execute 'Vitruvius' do
-    #     command 'ls'
-    #   end
-    #
-    # Will set the name to "Vitruvius".
-    #
-    # This is also used in to_s to show the resource name, e.g. `execute[Vitruvius]`.
-    #
-    # This is also used for resource notifications and subscribes in the same manner.
-    #
-    # This will coerce any object into a string via #to_s.  Arrays are a special case
-    # so that `package ["foo", "bar"]` becomes package[foo, bar] instead of the more
-    # awkward `package[["foo", "bar"]]` that #to_s would produce.
-    #
-    # @param name [Object] The name to set, typically a String or Array
-    # @return [String] The name of this Resource.
-    #
-    def name(name=nil)
-      if !name.nil?
-        if name.is_a?(Array)
-          @name = name.join(', ')
-        else
-          @name = name.to_s
-        end
-      end
-      @name
-    end
-
-    #
     # The action or actions that will be taken when this resource is run.
     #
     # @param arg [Array[Symbol], Symbol] A list of actions (e.g. `:create`)
     # @return [Array[Symbol]] the list of actions.
     #
-    def action(arg=nil)
+    def action(arg = nil)
       if arg
-        action_list = arg.kind_of?(Array) ? arg : [ arg ]
-        action_list = action_list.collect { |a| a.to_sym }
-        action_list.each do |action|
+        arg = Array(arg).map(&:to_sym)
+        arg.each do |action|
           validate(
             { action: action },
-            { action: { kind_of: Symbol, equal_to: @allowed_actions } }
+            { action: { kind_of: Symbol, equal_to: allowed_actions } },
           )
         end
-        @action = action_list
+        @action = arg
       else
         @action
       end
     end
 
+    # Alias for normal assigment syntax.
+    alias_method :action=, :action
+
     #
     # Sets up a notification that will run a particular action on another resource
     # if and when *this* resource is updated by an action.
     #
-    # If the action does nothing--does not update this resource, the
-    # notification never triggers.)
+    # If the action does not update this resource, the notification never triggers.
     #
     # Only one resource may be specified per notification.
     #
@@ -201,6 +209,8 @@ class Chef
     #     actions have been run.  This is the default.
     #   - `immediate`, `immediately`: Will run the action on the other resource
     #     immediately (before any other action is run).
+    #   - `before`: Will run the action on the other resource
+    #     immediately *before* the action is actually run.
     #
     # @example Resource by string
     #   file '/foo.txt' do
@@ -230,7 +240,7 @@ class Chef
     #     notifies :create, bar
     #   end
     #
-    def notifies(action, resource_spec, timing=:delayed)
+    def notifies(action, resource_spec, timing = :delayed)
       # when using old-style resources(:template => "/foo.txt") style, you
       # could end up with multiple resources.
       validate_resource_spec!(resource_spec)
@@ -239,13 +249,15 @@ class Chef
       resources.each do |resource|
 
         case timing.to_s
-        when 'delayed'
+        when "delayed"
           notifies_delayed(action, resource)
-        when 'immediate', 'immediately'
+        when "immediate", "immediately"
           notifies_immediately(action, resource)
+        when "before"
+          notifies_before(action, resource)
         else
           raise ArgumentError,  "invalid timing: #{timing} for notifies(#{action}, #{resources.inspect}, #{timing}) resource #{self} "\
-          "Valid timings are: :delayed, :immediate, :immediately"
+            "Valid timings are: :delayed, :immediate, :immediately, :before"
         end
       end
 
@@ -269,6 +281,8 @@ class Chef
     #     actions have been run.  This is the default.
     #   - `immediate`, `immediately`: The action will run immediately following
     #     the other resource being updated.
+    #   - `before`: The action will run immediately before the
+    #     other resource is updated.
     #
     # @example Resources by string
     #   file '/foo.txt' do
@@ -313,7 +327,7 @@ class Chef
     #     subscribes :create, [ bar, baz ]
     #   end
     #
-    def subscribes(action, resources, timing=:delayed)
+    def subscribes(action, resources, timing = :delayed)
       resources = [resources].flatten
       resources.each do |resource|
         if resource.is_a?(String)
@@ -350,7 +364,7 @@ class Chef
     # @param opts [Hash] Options control the execution of the command
     # @param block [Proc] A ruby block to run. Ignored if a command is given.
     #
-    def only_if(command=nil, opts={}, &block)
+    def only_if(command = nil, opts = {}, &block)
       if command || block_given?
         @only_if << Conditional.only_if(self, command, opts, &block)
       end
@@ -380,7 +394,7 @@ class Chef
     # @param opts [Hash] Options control the execution of the command
     # @param block [Proc] A ruby block to run. Ignored if a command is given.
     #
-    def not_if(command=nil, opts={}, &block)
+    def not_if(command = nil, opts = {}, &block)
       if command || block_given?
         @not_if << Conditional.not_if(self, command, opts, &block)
       end
@@ -397,7 +411,7 @@ class Chef
     # @param arg [Integer] The number of retries.
     # @return [Integer] The number of retries.
     #
-    def retries(arg=nil)
+    def retries(arg = nil)
       set_or_return(:retries, arg, kind_of: Integer)
     end
     attr_writer :retries
@@ -408,7 +422,7 @@ class Chef
     # @param arg [Integer] The number of seconds to wait between retries.
     # @return [Integer] The number of seconds to wait between retries.
     #
-    def retry_delay(arg=nil)
+    def retry_delay(arg = nil)
       set_or_return(:retry_delay, arg, kind_of: Integer)
     end
     attr_writer :retry_delay
@@ -420,7 +434,7 @@ class Chef
     # @param arg [Boolean] Whether this resource is sensitive or not.
     # @return [Boolean] Whether this resource is sensitive or not.
     #
-    def sensitive(arg=nil)
+    def sensitive(arg = nil)
       set_or_return(:sensitive, arg, :kind_of => [ TrueClass, FalseClass ])
     end
     attr_writer :sensitive
@@ -454,7 +468,7 @@ class Chef
     #   symbol/name.
     # @return [Class, Symbol, String] The Guard interpreter resource.
     #
-    def guard_interpreter(arg=nil)
+    def guard_interpreter(arg = nil)
       if arg.nil?
         @guard_interpreter || @default_guard_interpreter
       else
@@ -465,27 +479,49 @@ class Chef
     #
     # Get the value of the state attributes in this resource as a hash.
     #
+    # Does not include properties that are not set (unless they are identity
+    # properties).
+    #
     # @return [Hash{Symbol => Object}] A Hash of attribute => value for the
     #   Resource class's `state_attrs`.
-    def state
-      self.class.state_attrs.inject({}) do |state_attrs, attr_name|
-        state_attrs[attr_name] = send(attr_name)
-        state_attrs
+    #
+    def state_for_resource_reporter
+      state = {}
+      state_properties = self.class.state_properties
+      state_properties.each do |property|
+        if property.identity? || property.is_set?(self)
+          state[property.name] = send(property.name)
+        end
       end
+      state
     end
 
     #
-    # The value of the identity attribute, if declared. Falls back to #name if
-    # no identity attribute is declared.
+    # Since there are collisions with LWRP parameters named 'state' this
+    # method is not used by the resource_reporter and is most likely unused.
+    # It certainly cannot be relied upon and cannot be fixed.
     #
-    # @return The value of the identity attribute.
+    # @deprecated
+    #
+    alias_method :state, :state_for_resource_reporter
+
+    #
+    # The value of the identity of this resource.
+    #
+    # - If there are no identity properties on the resource, `name` is returned.
+    # - If there is exactly one identity property on the resource, it is returned.
+    # - If there are more than one, they are returned in a hash.
+    #
+    # @return [Object,Hash<Symbol,Object>] The identity of this resource.
     #
     def identity
-      if identity_attr = self.class.identity_attr
-        send(identity_attr)
-      else
-        name
+      result = {}
+      identity_properties = self.class.identity_properties
+      identity_properties.each do |property|
+        result[property.name] = send(property.name)
       end
+      return result.values.first if identity_properties.size == 1
+      result
     end
 
     #
@@ -499,7 +535,7 @@ class Chef
     # @param arg [Boolean] Whether to ignore failures.
     # @return Whether this resource will ignore failures.
     #
-    def ignore_failure(arg=nil)
+    def ignore_failure(arg = nil)
       set_or_return(:ignore_failure, arg, kind_of: [ TrueClass, FalseClass ])
     end
     attr_writer :ignore_failure
@@ -507,9 +543,7 @@ class Chef
     #
     # Equivalent to #ignore_failure.
     #
-    def epic_fail(arg=nil)
-      ignore_failure(arg)
-    end
+    alias :epic_fail :ignore_failure
 
     #
     # Make this resource into an exact (shallow) copy of the other resource.
@@ -533,7 +567,7 @@ class Chef
     #
     # @raise Any error that occurs during the actual action.
     #
-    def run_action(action, notification_type=nil, notifying_resource=nil)
+    def run_action(action, notification_type = nil, notifying_resource = nil)
       # reset state in case of multiple actions on the same resource.
       @elapsed_time = 0
       start_time = Time.now
@@ -574,12 +608,26 @@ class Chef
           events.resource_failed(self, action, e)
           raise customize_exception(e)
         end
-      ensure
-        @elapsed_time = Time.now - start_time
-        # Reporting endpoint doesn't accept a negative resource duration so set it to 0.
-        # A negative value can occur when a resource changes the system time backwards
-        @elapsed_time = 0 if @elapsed_time < 0
-        events.resource_completed(self)
+      end
+    ensure
+      @elapsed_time = Time.now - start_time
+      # Reporting endpoint doesn't accept a negative resource duration so set it to 0.
+      # A negative value can occur when a resource changes the system time backwards
+      @elapsed_time = 0 if @elapsed_time < 0
+      events.resource_completed(self)
+    end
+
+    #
+    # If we are currently initializing the resource, this will be true.
+    #
+    # Do NOT use this. It may be removed. It is for internal purposes only.
+    # @api private
+    attr_reader :resource_initializing
+    def resource_initializing=(value)
+      if value
+        @resource_initializing = true
+      else
+        remove_instance_variable(:@resource_initializing)
       end
     end
 
@@ -588,18 +636,18 @@ class Chef
     #
 
     def to_s
-      "#{@resource_name}[#{@name}]"
+      "#{resource_name}[#{name}]"
     end
 
     def to_text
       return "suppressed sensitive resource output" if sensitive
       ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS
       text = "# Declared in #{@source_line}\n\n"
-      text << self.class.dsl_name + "(\"#{name}\") do\n"
+      text << "#{resource_name}(\"#{name}\") do\n"
       ivars.each do |ivar|
         if (value = instance_variable_get(ivar)) && !(value.respond_to?(:empty?) && value.empty?)
           value_string = value.respond_to?(:to_text) ? value.to_text : value.inspect
-          text << "  #{ivar.to_s.sub(/^@/,'')} #{value_string}\n"
+          text << "  #{ivar.to_s.sub(/^@/, '')} #{value_string}\n"
         end
       end
       [@not_if, @only_if].flatten.each do |conditional|
@@ -610,7 +658,7 @@ class Chef
 
     def inspect
       ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
-      ivars.inject("<#{to_s}") do |str, ivar|
+      ivars.inject("<#{self}") do |str, ivar|
         str << " #{ivar}: #{instance_variable_get(ivar).inspect}"
       end << ">"
     end
@@ -622,11 +670,11 @@ class Chef
       safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
       instance_vars = Hash.new
       safe_ivars.each do |iv|
-        instance_vars[iv.to_s.sub(/^@/, '')] = instance_variable_get(iv)
+        instance_vars[iv.to_s.sub(/^@/, "")] = instance_variable_get(iv)
       end
       {
-        'json_class' => self.class.name,
-        'instance_vars' => instance_vars
+        "json_class" => self.class.name,
+        "instance_vars" => instance_vars,
       }
     end
 
@@ -637,18 +685,23 @@ class Chef
     end
 
     def to_hash
+      # Grab all current state, then any other ivars (backcompat)
+      result = {}
+      self.class.state_properties.each do |p|
+        result[p.name] = p.get(self)
+      end
       safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS
-      instance_vars = Hash.new
       safe_ivars.each do |iv|
-        key = iv.to_s.sub(/^@/,'').to_sym
-        instance_vars[key] = instance_variable_get(iv)
+        key = iv.to_s.sub(/^@/, "").to_sym
+        next if result.has_key?(key)
+        result[key] = instance_variable_get(iv)
       end
-      instance_vars
+      result
     end
 
     def self.json_create(o)
       resource = self.new(o["instance_vars"]["@name"])
-      o["instance_vars"].each do |k,v|
+      o["instance_vars"].each do |k, v|
         resource.instance_variable_set("@#{k}".to_sym, v)
       end
       resource
@@ -658,72 +711,113 @@ class Chef
     # Resource Definition Interface (for resource developers)
     #
 
-    include Chef::Mixin::ParamsValidate
     include Chef::Mixin::Deprecation
 
     #
     # The provider class for this resource.
     #
+    # If `action :x do ... end` has been declared on this resource or its
+    # superclasses, this will return the `action_class`.
+    #
     # If this is not set, `provider_for_action` will dynamically determine the
     # provider.
     #
     # @param arg [String, Symbol, Class] Sets the provider class for this resource.
     #   If passed a String or Symbol, e.g. `:file` or `"file"`, looks up the
     #   provider based on the name.
+    #
     # @return The provider class for this resource.
     #
-    def provider(arg=nil)
+    # @see Chef::Resource.action_class
+    #
+    def provider(arg = nil)
       klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
-        lookup_provider_constant(arg)
-      else
-        arg
-      end
-      set_or_return(:provider, klass, kind_of: [ Class ])
+                lookup_provider_constant(arg)
+              else
+                arg
+              end
+      set_or_return(:provider, klass, kind_of: [ Class ]) ||
+        self.class.action_class
     end
+
     def provider=(arg)
       provider(arg)
     end
 
-    # Set or return the list of "state attributes" implemented by the Resource
-    # subclass. State attributes are attributes that describe the desired state
-    # of the system, such as file permissions or ownership. In general, state
-    # attributes are attributes that could be populated by examining the state
-    # of the system (e.g., File.stat can tell you the permissions on an
-    # existing file). Contrarily, attributes that are not "state attributes"
-    # usually modify the way Chef itself behaves, for example by providing
-    # additional options for a package manager to use when installing a
-    # package.
-    #
-    # This list is used by the Chef client auditing system to extract
-    # information from resources to describe changes made to the system.
-    def self.state_attrs(*attr_names)
-      @state_attrs ||= []
-      @state_attrs = attr_names unless attr_names.empty?
-
-      # Return *all* state_attrs that this class has, including inherited ones
-      if superclass.respond_to?(:state_attrs)
-        superclass.state_attrs + @state_attrs
-      else
-        @state_attrs
-      end
+    #
+    # Set or return the list of "state properties" implemented by the Resource
+    # subclass.
+    #
+    # Equivalent to calling #state_properties and getting `state_properties.keys`.
+    #
+    # @deprecated Use state_properties.keys instead. Note that when you declare
+    #   properties with `property`: properties are added to state_properties by
+    #   default, and can be turned off with `desired_state: false`
+    #
+    #   ```ruby
+    #   property :x # part of desired state
+    #   property :y, desired_state: false # not part of desired state
+    #   ```
+    #
+    # @param names [Array<Symbol>] A list of property names to set as desired
+    #   state.
+    #
+    # @return [Array<Symbol>] All property names with desired state.
+    #
+    def self.state_attrs(*names)
+      state_properties(*names).map { |property| property.name }
     end
 
-    # Set or return the "identity attribute" for this resource class. This is
-    # generally going to be the "name attribute" for this resource. In other
-    # words, the resource type plus this attribute uniquely identify a given
-    # bit of state that chef manages. For a File resource, this would be the
-    # path, for a package resource, it will be the package name. This will show
-    # up in chef-client's audit records as a searchable field.
-    def self.identity_attr(attr_name=nil)
-      @identity_attr ||= nil
-      @identity_attr = attr_name if attr_name
-
-      # If this class doesn't have an identity attr, we'll defer to the superclass:
-      if @identity_attr || !superclass.respond_to?(:identity_attr)
-        @identity_attr
-      else
-        superclass.identity_attr
+    #
+    # Set the identity of this resource to a particular property.
+    #
+    # This drives #identity, which returns data that uniquely refers to a given
+    # resource on the given node (in such a way that it can be correlated
+    # across Chef runs).
+    #
+    # This method is unnecessary when declaring properties with `property`;
+    # properties can be added to identity during declaration with
+    # `identity: true`.
+    #
+    # ```ruby
+    # property :x, identity: true # part of identity
+    # property :y # not part of identity
+    # ```
+    #
+    # @param name [Symbol] A list of property names to set as the identity.
+    #
+    # @return [Symbol] The identity property if there is only one; or `nil` if
+    #   there are more than one.
+    #
+    # @raise [ArgumentError] If no arguments are passed and the resource has
+    #   more than one identity property.
+    #
+    def self.identity_property(name = nil)
+      result = identity_properties(*Array(name))
+      if result.size > 1
+        raise Chef::Exceptions::MultipleIdentityError, "identity_property cannot be called on an object with more than one identity property (#{result.map { |r| r.name }.join(", ")})."
       end
+      result.first
+    end
+
+    #
+    # Set a property as the "identity attribute" for this resource.
+    #
+    # Identical to calling #identity_property.first.key.
+    #
+    # @param name [Symbol] The name of the property to set.
+    #
+    # @return [Symbol]
+    #
+    # @deprecated `identity_property` should be used instead.
+    #
+    # @raise [ArgumentError] If no arguments are passed and the resource has
+    #   more than one identity property.
+    #
+    def self.identity_attr(name = nil)
+      property = identity_property(name)
+      return nil if !property
+      property.name
     end
 
     #
@@ -749,6 +843,12 @@ class Chef
     #   have.
     #
     attr_accessor :allowed_actions
+    def allowed_actions(value = NOT_PASSED)
+      if value != NOT_PASSED
+        self.allowed_actions = value
+      end
+      @allowed_actions
+    end
 
     #
     # Whether or not this resource was updated during an action.  If multiple
@@ -801,25 +901,21 @@ class Chef
     def updated=(true_or_false)
       Chef::Log.warn("Chef::Resource#updated=(true|false) is deprecated. Please call #updated_by_last_action(true|false) instead.")
       Chef::Log.warn("Called from:")
-      caller[0..3].each {|line| Chef::Log.warn(line)}
+      caller[0..3].each { |line| Chef::Log.warn(line) }
       updated_by_last_action(true_or_false)
       @updated = true_or_false
     end
 
     #
-    # The DSL name of this resource (e.g. `package` or `yum_package`)
+    # The display name of this resource type, for printing purposes.
     #
-    # @return [String] The DSL name of this resource.
-    def self.dsl_name
-      convert_to_snake_case(name, 'Chef::Resource')
-    end
-
+    # Will be used to print out the resource in messages, e.g. resource_name[name]
     #
-    # The name of this resource (e.g. `file`)
+    # @return [Symbol] The name of this resource type (e.g. `:execute`).
     #
-    # @return [String] The name of this resource.
-    #
-    attr_reader :resource_name
+    def resource_name
+      @resource_name || self.class.resource_name
+    end
 
     #
     # Sets a list of capabilities of the real resource.  For example, `:remount`
@@ -832,13 +928,14 @@ class Chef
     #   this resource. Default: {}
     # @return Hash{Symbol=>Boolean} An array of things this resource supports.
     #
-    def supports(args={})
+    def supports(args = {})
       if args.any?
         @supports = args
       else
         @supports
       end
     end
+
     def supports=(args)
       supports(args)
     end
@@ -852,6 +949,74 @@ class Chef
     end
 
     #
+    # The DSL name of this resource (e.g. `package` or `yum_package`)
+    #
+    # @return [String] The DSL name of this resource.
+    #
+    # @deprecated Use resource_name instead.
+    #
+    def self.dsl_name
+      Chef.log_deprecation "Resource.dsl_name is deprecated and will be removed in Chef 13.  Use resource_name instead."
+      if name
+        name = self.name.split("::")[-1]
+        convert_to_snake_case(name)
+      end
+    end
+
+    #
+    # The display name of this resource type, for printing purposes.
+    #
+    # This also automatically calls "provides" to provide DSL with the given
+    # name.
+    #
+    # resource_name defaults to your class name.
+    #
+    # Call `resource_name nil` to remove the resource name (and any
+    # corresponding DSL).
+    #
+    # @param value [Symbol] The desired name of this resource type (e.g.
+    #   `execute`), or `nil` if this class is abstract and has no resource_name.
+    #
+    # @return [Symbol] The name of this resource type (e.g. `:execute`).
+    #
+    def self.resource_name(name = NOT_PASSED)
+      # Setter
+      if name != NOT_PASSED
+        remove_canonical_dsl
+
+        # Set the resource_name and call provides
+        if name
+          name = name.to_sym
+          # If our class is not already providing this name, provide it.
+          if !Chef::ResourceResolver.includes_handler?(name, self)
+            provides name, canonical: true
+          end
+          @resource_name = name
+        else
+          @resource_name = nil
+        end
+      end
+      @resource_name
+    end
+
+    def self.resource_name=(name)
+      resource_name(name)
+    end
+
+    #
+    # Use the class name as the resource name.
+    #
+    # Munges the last part of the class name from camel case to snake case,
+    # and sets the resource_name to that:
+    #
+    # A::B::BlahDBlah -> blah_d_blah
+    #
+    def self.use_automatic_resource_name
+      automatic_name = convert_to_snake_case(self.name.split("::")[-1])
+      resource_name automatic_name
+    end
+
+    #
     # The module where Chef should look for providers for this resource.
     # The provider for `MyResource` will be looked up using
     # `provider_base::MyResource`.  Defaults to `Chef::Provider`.
@@ -865,11 +1030,193 @@ class Chef
     #     # ...other stuff
     #   end
     #
-    def self.provider_base(arg=nil)
-      @provider_base ||= arg
-      @provider_base ||= Chef::Provider
+    # @deprecated Use `provides` on the provider, or `provider` on the resource, instead.
+    #
+    def self.provider_base(arg = nil)
+      if arg
+        Chef.log_deprecation("Resource.provider_base is deprecated and will be removed in Chef 13. Use provides on the provider, or provider on the resource, instead.")
+      end
+      @provider_base ||= arg || Chef::Provider
+    end
+
+    #
+    # The list of allowed actions for the resource.
+    #
+    # @param actions [Array<Symbol>] The list of actions to add to allowed_actions.
+    #
+    # @return [Array<Symbol>] The list of actions, as symbols.
+    #
+    def self.allowed_actions(*actions)
+      @allowed_actions ||=
+        if superclass.respond_to?(:allowed_actions)
+          superclass.allowed_actions.dup
+        else
+          [ :nothing ]
+        end
+      @allowed_actions |= actions.flatten
+    end
+
+    def self.allowed_actions=(value)
+      @allowed_actions = value.uniq
+    end
+
+    #
+    # The action that will be run if no other action is specified.
+    #
+    # Setting default_action will automatially add the action to
+    # allowed_actions, if it isn't already there.
+    #
+    # Defaults to [:nothing].
+    #
+    # @param action_name [Symbol,Array<Symbol>] The default action (or series
+    #   of actions) to use.
+    #
+    # @return [Array<Symbol>] The default actions for the resource.
+    #
+    def self.default_action(action_name = NOT_PASSED)
+      unless action_name.equal?(NOT_PASSED)
+        @default_action = Array(action_name).map(&:to_sym)
+        self.allowed_actions |= @default_action
+      end
+
+      if @default_action
+        @default_action
+      elsif superclass.respond_to?(:default_action)
+        superclass.default_action
+      else
+        [:nothing]
+      end
+    end
+
+    def self.default_action=(action_name)
+      default_action action_name
+    end
+
+    #
+    # Define an action on this resource.
+    #
+    # The action is defined as a *recipe* block that will be compiled and then
+    # converged when the action is taken (when Resource is converged).  The recipe
+    # has access to the resource's attributes and methods, as well as the Chef
+    # recipe DSL.
+    #
+    # Resources in the action recipe may notify and subscribe to other resources
+    # within the action recipe, but cannot notify or subscribe to resources
+    # in the main Chef run.
+    #
+    # Resource actions are *inheritable*: if resource A defines `action :create`
+    # and B is a subclass of A, B gets all of A's actions.  Additionally,
+    # resource B can define `action :create` and call `super()` to invoke A's
+    # action code.
+    #
+    # The first action defined (besides `:nothing`) will become the default
+    # action for the resource.
+    #
+    # @param name [Symbol] The action name to define.
+    # @param recipe_block The recipe to run when the action is taken. This block
+    #   takes no parameters, and will be evaluated in a new context containing:
+    #
+    #   - The resource's public and protected methods (including attributes)
+    #   - The Chef Recipe DSL (file, etc.)
+    #   - super() referring to the parent version of the action (if any)
+    #
+    # @return The Action class implementing the action
+    #
+    def self.action(action, &recipe_block)
+      action = action.to_sym
+      declare_action_class
+      action_class.action(action, &recipe_block)
+      self.allowed_actions += [ action ]
+      default_action action if Array(default_action) == [:nothing]
+    end
+
+    #
+    # Define a method to load up this resource's properties with the current
+    # actual values.
+    #
+    # @param load_block The block to load.  Will be run in the context of a newly
+    #   created resource with its identity values filled in.
+    #
+    def self.load_current_value(&load_block)
+      define_method(:load_current_value!, &load_block)
+    end
+
+    #
+    # Call this in `load_current_value` to indicate that the value does not
+    # exist and that `current_resource` should therefore be `nil`.
+    #
+    # @raise Chef::Exceptions::CurrentValueDoesNotExist
+    #
+    def current_value_does_not_exist!
+      raise Chef::Exceptions::CurrentValueDoesNotExist
+    end
+
+    #
+    # Get the current actual value of this resource.
+    #
+    # This does not cache--a new value will be returned each time.
+    #
+    # @return A new copy of the resource, with values filled in from the actual
+    #   current value.
+    #
+    def current_value
+      provider = provider_for_action(Array(action).first)
+      if provider.whyrun_mode? && !provider.whyrun_supported?
+        raise "Cannot retrieve #{self.class.current_resource} in why-run mode: #{provider} does not support why-run"
+      end
+      provider.load_current_resource
+      provider.current_resource
     end
 
+    #
+    # The action class is an automatic `Provider` created to handle
+    # actions declared by `action :x do ... end`.
+    #
+    # This class will be returned by `resource.provider` if `resource.provider`
+    # is not set. `provider_for_action` will also use this instead of calling
+    # out to `Chef::ProviderResolver`.
+    #
+    # If the user has not declared actions on this class or its superclasses
+    # using `action :x do ... end`, then there is no need for this class and
+    # `action_class` will be `nil`.
+    #
+    # If a block is passed, the action_class is always created and the block is
+    # run inside it.
+    #
+    # @api private
+    #
+    def self.action_class(&block)
+      return @action_class if @action_class && !block
+      # If the superclass needed one, then we need one as well.
+      if block || (superclass.respond_to?(:action_class) && superclass.action_class)
+        @action_class = declare_action_class(&block)
+      end
+      @action_class
+    end
+
+    #
+    # Ensure the action class actually gets created. This is called
+    # when the user does `action :x do ... end`.
+    #
+    # If a block is passed, it is run inside the action_class.
+    #
+    # @api private
+    def self.declare_action_class(&block)
+      @action_class ||= begin
+                          if superclass.respond_to?(:action_class)
+                            base_provider = superclass.action_class
+                          end
+                          base_provider ||= Chef::Provider
+
+                          resource_class = self
+                          Class.new(base_provider) do
+                            include ActionClass
+                            self.resource_class = resource_class
+                          end
+                        end
+      @action_class.class_eval(&block) if block
+      @action_class
+    end
 
     #
     # Internal Resource Interface (for Chef)
@@ -922,6 +1269,9 @@ class Chef
     # resolve_resource_reference on each in turn, causing them to
     # resolve lazy/forward references.
     def resolve_notification_references
+      run_context.before_notifications(self).each { |n|
+        n.resolve_resource_reference(run_context.resource_collection)
+      }
       run_context.immediate_notifications(self).each { |n|
         n.resolve_resource_reference(run_context.resource_collection)
       }
@@ -931,6 +1281,11 @@ class Chef
     end
 
     # Helper for #notifies
+    def notifies_before(action, resource_spec)
+      run_context.notifies_before(Notification.new(resource_spec, action, self))
+    end
+
+    # Helper for #notifies
     def notifies_immediately(action, resource_spec)
       run_context.notifies_immediately(Notification.new(resource_spec, action, self))
     end
@@ -942,13 +1297,39 @@ class Chef
 
     class << self
       # back-compat
-      # NOTE: that we do not support unregistering classes as descendents like
+      # NOTE: that we do not support unregistering classes as descendants like
       # we used to for LWRP unloading because that was horrible and removed in
       # Chef-12.
+      # @deprecated
+      # @api private
       alias :resource_classes :descendants
+      # @deprecated
+      # @api private
       alias :find_subclass_by_name :find_descendants_by_name
     end
 
+    # @deprecated
+    # @api private
+    # We memoize a sorted version of descendants so that resource lookups don't
+    # have to sort all the things, all the time.
+    # This was causing performance issues in test runs, and probably in real
+    # life as well.
+    @@sorted_descendants = nil
+    def self.sorted_descendants
+      @@sorted_descendants ||= descendants.sort_by { |x| x.to_s }
+    end
+
+    def self.inherited(child)
+      super
+      @@sorted_descendants = nil
+      # set resource_name automatically if it's not set
+      if child.name && !child.resource_name
+        if child.name =~ /^Chef::Resource::(\w+)$/
+          child.resource_name(convert_to_snake_case($1))
+        end
+      end
+    end
+
     # If an unknown method is invoked, determine whether the enclosing Provider's
     # lexical scope can fulfill the request. E.g. This happens when the Resource's
     # block invokes new_resource.
@@ -956,10 +1337,36 @@ class Chef
       if enclosing_provider && enclosing_provider.respond_to?(method_symbol)
         enclosing_provider.send(method_symbol, *args, &block)
       else
-        raise NoMethodError, "undefined method `#{method_symbol.to_s}' for #{self.class.to_s}"
+        raise NoMethodError, "undefined method `#{method_symbol}' for #{self.class}"
       end
     end
 
+    #
+    # Mark this resource as providing particular DSL.
+    #
+    # Resources have an automatic DSL based on their resource_name, equivalent to
+    # `provides :resource_name` (providing the resource on all OS's).  If you
+    # declare a `provides` with the given resource_name, it *replaces* that
+    # provides (so that you can provide your resource DSL only on certain OS's).
+    #
+    def self.provides(name, **options, &block)
+      name = name.to_sym
+
+      # `provides :resource_name, os: 'linux'`) needs to remove the old
+      # canonical DSL before adding the new one.
+      if @resource_name && name == @resource_name
+        remove_canonical_dsl
+      end
+
+      result = Chef.resource_handler_map.set(name, self, options, &block)
+      Chef::DSL::Resources.add_resource_dsl(name)
+      result
+    end
+
+    def self.provides?(node, resource_name)
+      Chef::ResourceResolver.new(node, resource_name).provided_by?(self)
+    end
+
     # Helper for #notifies
     def validate_resource_spec!(resource_spec)
       run_context.resource_collection.validate_lookup_spec!(resource_spec)
@@ -973,6 +1380,10 @@ class Chef
       "#{declared_type}[#{@name}]"
     end
 
+    def before_notifications
+      run_context.before_notifications(self)
+    end
+
     def immediate_notifications
       run_context.immediate_notifications(self)
     end
@@ -981,16 +1392,31 @@ class Chef
       run_context.delayed_notifications(self)
     end
 
+    def source_line_file
+      if source_line
+        source_line.match(/(.*):(\d+):?.*$/).to_a[1]
+      else
+        nil
+      end
+    end
+
+    def source_line_number
+      if source_line
+        source_line.match(/(.*):(\d+):?.*$/).to_a[2]
+      else
+        nil
+      end
+    end
+
     def defined_at
       # The following regexp should match these two sourceline formats:
       #   /some/path/to/file.rb:80:in `wombat_tears'
       #   C:/some/path/to/file.rb:80 in 1`wombat_tears'
       # extracting the path to the source file and the line number.
-      (file, line_no) = source_line.match(/(.*):(\d+):?.*$/).to_a[1,2] if source_line
       if cookbook_name && recipe_name && source_line
-        "#{cookbook_name}::#{recipe_name} line #{line_no}"
+        "#{cookbook_name}::#{recipe_name} line #{source_line_number}"
       elsif source_line
-        "#{file} line #{line_no}"
+        "#{source_line_file} line #{source_line_number}"
       else
         "dynamically defined"
       end
@@ -1016,14 +1442,14 @@ class Chef
     end
 
     def provider_for_action(action)
-      require 'chef/provider_resolver'
-      provider = Chef::ProviderResolver.new(node, self, action).resolve.new(self, run_context)
+      provider_class = Chef::ProviderResolver.new(node, self, action).resolve
+      provider = provider_class.new(self, run_context)
       provider.action = action
       provider
     end
 
     # ??? TODO Seems unused.  Delete?
-    def noop(tf=nil)
+    def noop(tf = nil)
       if !tf.nil?
         raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false
         @noop = tf
@@ -1090,30 +1516,43 @@ class Chef
     # === Returns
     # <Chef::Resource>:: returns the proper Chef::Resource class
     def self.resource_for_node(short_name, node)
-      require 'chef/resource_resolver'
-      klass = Chef::ResourceResolver.new(node, short_name).resolve
+      klass = Chef::ResourceResolver.resolve(short_name, node: node)
       raise Chef::Exceptions::NoSuchResourceType.new(short_name, node) if klass.nil?
       klass
     end
 
-    # Returns the class of a Chef::Resource based on the short name
+    #
+    # Returns the class with the given resource_name.
+    #
     # ==== Parameters
     # short_name<Symbol>:: short_name of the resource (ie :directory)
     #
     # === Returns
     # <Chef::Resource>:: returns the proper Chef::Resource class
+    #
     def self.resource_matching_short_name(short_name)
-      begin
-        rname = convert_to_class_name(short_name.to_s)
-        Chef::Resource.const_get(rname)
-      rescue NameError
-        nil
+      Chef::ResourceResolver.resolve(short_name, canonical: true)
+    end
+
+    # @api private
+    def self.register_deprecated_lwrp_class(resource_class, class_name)
+      if Chef::Resource.const_defined?(class_name, false)
+        Chef::Log.warn "#{class_name} already exists!  Deprecation class overwrites #{resource_class}"
+        Chef::Resource.send(:remove_const, class_name)
+      end
+
+      if !Chef::Config[:treat_deprecation_warnings_as_errors]
+        Chef::Resource.const_set(class_name, resource_class)
+        deprecated_constants[class_name.to_sym] = resource_class
       end
     end
 
-    private
+    def self.deprecated_constants
+      @deprecated_constants ||= {}
+    end
 
-    def lookup_provider_constant(name)
+    # @api private
+    def lookup_provider_constant(name, action = :nothing)
       begin
         self.class.provider_base.const_get(convert_to_class_name(name.to_s))
       rescue NameError => e
@@ -1124,5 +1563,19 @@ class Chef
         end
       end
     end
+
+    private
+
+    def self.remove_canonical_dsl
+      if @resource_name
+        remaining = Chef.resource_handler_map.delete_canonical(@resource_name, self)
+        if !remaining
+          Chef::DSL::Resources.remove_resource_dsl(@resource_name)
+        end
+      end
+    end
   end
 end
+
+# Requiring things at the bottom breaks cycles
+require "chef/chef_class"
diff --git a/lib/chef/resource/action_class.rb b/lib/chef/resource/action_class.rb
new file mode 100644
index 0000000..3d9f2f3
--- /dev/null
+++ b/lib/chef/resource/action_class.rb
@@ -0,0 +1,87 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/exceptions"
+
+class Chef
+  class Resource
+    module ActionClass
+      def to_s
+        "#{new_resource || "<no resource>"} action #{action ? action.inspect : "<no action>"}"
+      end
+
+      #
+      # If load_current_value! is defined on the resource, use that.
+      #
+      def load_current_resource
+        if new_resource.respond_to?(:load_current_value!)
+          # dup the resource and then reset desired-state properties.
+          current_resource = new_resource.dup
+
+          # We clear desired state in the copy, because it is supposed to be actual state.
+          # We keep identity properties and non-desired-state, which are assumed to be
+          # "control" values like `recurse: true`
+          current_resource.class.properties.each do |name, property|
+            if property.desired_state? && !property.identity? && !property.name_property?
+              property.reset(current_resource)
+            end
+          end
+
+          # Call the actual load_current_value! method. If it raises
+          # CurrentValueDoesNotExist, set current_resource to `nil`.
+          begin
+            # If the user specifies load_current_value do |desired_resource|, we
+            # pass in the desired resource as well as the current one.
+            if current_resource.method(:load_current_value!).arity > 0
+              current_resource.load_current_value!(new_resource)
+            else
+              current_resource.load_current_value!
+            end
+          rescue Chef::Exceptions::CurrentValueDoesNotExist
+            current_resource = nil
+          end
+        end
+
+        @current_resource = current_resource
+      end
+
+      def self.included(other)
+        other.extend(ClassMethods)
+        other.use_inline_resources
+        other.include_resource_dsl true
+      end
+
+      module ClassMethods
+        #
+        # The Chef::Resource class this ActionClass was declared against.
+        #
+        # @return [Class] The Chef::Resource class this ActionClass was declared against.
+        #
+        attr_accessor :resource_class
+
+        def to_s
+          "#{resource_class} action provider"
+        end
+
+        def inspect
+          to_s
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index f944825..069fefc 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,29 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/apt'
+require "chef/resource/package"
+require "chef/provider/package/apt"
 
 class Chef
   class Resource
     class AptPackage < Chef::Resource::Package
-
-      provides :apt_package
+      resource_name :apt_package
       provides :package, os: "linux", platform_family: [ "debian" ]
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :apt_package
-        @default_release = nil
-      end
-
-      def default_release(arg=nil)
-        set_or_return(
-          :default_release,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
+      property :default_release, String, desired_state: false
 
     end
   end
diff --git a/lib/chef/resource/apt_update.rb b/lib/chef/resource/apt_update.rb
new file mode 100644
index 0000000..df2033b
--- /dev/null
+++ b/lib/chef/resource/apt_update.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Thom May (<thom at chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+
+class Chef
+  class Resource
+    class AptUpdate < Chef::Resource
+      resource_name :apt_update
+      provides :apt_update, os: "linux"
+
+      property :frequency, Integer, default: 86_400
+
+      default_action :periodic
+      allowed_actions :update, :periodic
+    end
+  end
+end
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index 0add0ce..1238eed 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Bash < Chef::Resource::Script
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :bash
         @interpreter = "bash"
       end
 
diff --git a/lib/chef/resource/batch.rb b/lib/chef/resource/batch.rb
index c091ec5..10e9683 100644
--- a/lib/chef/resource/batch.rb
+++ b/lib/chef/resource/batch.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource/windows_script'
+require "chef/resource/windows_script"
 
 class Chef
   class Resource
@@ -24,8 +24,8 @@ class Chef
 
       provides :batch, os: "windows"
 
-      def initialize(name, run_context=nil)
-        super(name, run_context, :batch, "cmd.exe")
+      def initialize(name, run_context = nil)
+        super(name, run_context, nil, "cmd.exe")
       end
 
     end
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
index 917f0d1..b145918 100644
--- a/lib/chef/resource/bff_package.rb
+++ b/lib/chef/resource/bff_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Deepali Jagtap (<deepali.jagtap at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/aix'
+require "chef/resource/package"
+require "chef/provider/package/aix"
 
 class Chef
   class Resource
     class BffPackage < Chef::Resource::Package
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :bff_package
-      end
-
     end
   end
 end
-
-
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index b221026..a5eed0d 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,17 @@
 # limitations under the License.
 #
 
-
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class Breakpoint < Chef::Resource
+      default_action :break
 
-      def initialize(action="break", *args)
-        @name = caller.first
-        super(@name, *args)
-        @action = "break"
-        @allowed_actions << :break
-        @resource_name = :breakpoint
+      def initialize(action = "break", *args)
+        super(caller.first, *args)
       end
+
     end
   end
 end
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index 59f575a..e08bacc 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,46 +16,27 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/resource/gem_package'
+require "chef/resource/package"
+require "chef/resource/gem_package"
 
 class Chef
   class Resource
     class ChefGem < Chef::Resource::Package::GemPackage
+      resource_name :chef_gem
 
-      provides :chef_gem
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :chef_gem
-        @compile_time = Chef::Config[:chef_gem_compile_time]
-        @gem_binary = RbConfig::CONFIG['bindir'] + "/gem"
-      end
-
-      # The chef_gem resources is for installing gems to the current gem environment only for use by Chef cookbooks.
-      def gem_binary(arg=nil)
-        if arg
-          raise ArgumentError, "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments."
-        end
-
-        @gem_binary
-      end
-
-      def compile_time(arg=nil)
-        set_or_return(
-          :compile_time,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
+      property :gem_binary, default: "#{RbConfig::CONFIG['bindir']}/gem",
+                            callbacks: {
+                 "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments." => proc { |v| v == "#{RbConfig::CONFIG['bindir']}/gem" }
+               }
+      property :compile_time, [ true, false, nil ], default: lazy { Chef::Config[:chef_gem_compile_time] }, desired_state: false
 
       def after_created
         # Chef::Resource.run_action: Caveat: this skips Chef::Runner.run_action, where notifications are handled
         # Action could be an array of symbols, but probably won't (think install + enable for a package)
         if compile_time.nil?
-          Chef::Log.deprecation "#{self} chef_gem compile_time installation is deprecated"
-          Chef::Log.deprecation "#{self} Please set `compile_time false` on the resource to use the new behavior."
-          Chef::Log.deprecation "#{self} or set `compile_time true` on the resource if compile_time behavior is required."
+          Chef.log_deprecation "#{self} chef_gem compile_time installation is deprecated"
+          Chef.log_deprecation "#{self} Please set `compile_time false` on the resource to use the new behavior."
+          Chef.log_deprecation "#{self} or set `compile_time true` on the resource if compile_time behavior is required."
         end
 
         if compile_time || compile_time.nil?
diff --git a/lib/chef/resource/chocolatey_package.rb b/lib/chef/resource/chocolatey_package.rb
new file mode 100644
index 0000000..805d3a3
--- /dev/null
+++ b/lib/chef/resource/chocolatey_package.rb
@@ -0,0 +1,39 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+
+class Chef
+  class Resource
+    class ChocolateyPackage < Chef::Resource::Package
+
+      provides :chocolatey_package, os: "windows"
+
+      allowed_actions :install, :upgrade, :remove, :uninstall, :purge, :reconfig
+
+      def initialize(name, run_context = nil)
+        super
+        @resource_name = :chocolatey_package
+      end
+
+      property :package_name, [String, Array], coerce: proc { |x| [x].flatten }
+
+      property :version, [String, Array], coerce: proc { |x| [x].flatten }
+    end
+  end
+end
diff --git a/lib/chef/resource/conditional.rb b/lib/chef/resource/conditional.rb
index 35bdae8..cdb9f13 100644
--- a/lib/chef/resource/conditional.rb
+++ b/lib/chef/resource/conditional.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/shell_out'
-require 'chef/guard_interpreter'
+require "chef/mixin/shell_out"
+require "chef/guard_interpreter"
 
 class Chef
   class Resource
@@ -30,11 +30,11 @@ class Chef
         private :new
       end
 
-      def self.not_if(parent_resource, command=nil, command_opts={}, &block)
+      def self.not_if(parent_resource, command = nil, command_opts = {}, &block)
         new(:not_if, parent_resource, command, command_opts, &block)
       end
 
-      def self.only_if(parent_resource, command=nil, command_opts={}, &block)
+      def self.only_if(parent_resource, command = nil, command_opts = {}, &block)
         new(:only_if, parent_resource, command, command_opts, &block)
       end
 
@@ -43,7 +43,7 @@ class Chef
       attr_reader :command_opts
       attr_reader :block
 
-      def initialize(positivity, parent_resource, command=nil, command_opts={}, &block)
+      def initialize(positivity, parent_resource, command = nil, command_opts = {}, &block)
         @positivity = positivity
         @command, @command_opts = command, command_opts
         @block = block
@@ -55,7 +55,7 @@ class Chef
 
       def configure
         case @command
-        when String,Array
+        when String, Array
           @guard_interpreter = Chef::GuardInterpreter.for_resource(@parent_resource, @command, @command_opts)
           @block = nil
         when nil
diff --git a/lib/chef/resource/conditional_action_not_nothing.rb b/lib/chef/resource/conditional_action_not_nothing.rb
index f6c34b2..94b542e 100644
--- a/lib/chef/resource/conditional_action_not_nothing.rb
+++ b/lib/chef/resource/conditional_action_not_nothing.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index 7be353b..785cf69 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,31 +18,29 @@
 # limitations under the License.
 #
 
-require 'chef/resource/file'
-require 'chef/provider/cookbook_file'
-require 'chef/mixin/securable'
+require "chef/resource/file"
+require "chef/provider/cookbook_file"
+require "chef/mixin/securable"
 
 class Chef
   class Resource
     class CookbookFile < Chef::Resource::File
       include Chef::Mixin::Securable
 
-      provides :cookbook_file
+      default_action :create
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
         @provider = Chef::Provider::CookbookFile
-        @resource_name = :cookbook_file
-        @action = "create"
         @source = ::File.basename(name)
         @cookbook = nil
       end
 
-      def source(source_filename=nil)
+      def source(source_filename = nil)
         set_or_return(:source, source_filename, :kind_of => [ String, Array ])
       end
 
-      def cookbook(cookbook_name=nil)
+      def cookbook(cookbook_name = nil)
         set_or_return(:cookbook, cookbook_name, :kind_of => String)
       end
 
diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb
index cb16506..26711fd 100644
--- a/lib/chef/resource/cron.rb
+++ b/lib/chef/resource/cron.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
@@ -27,13 +27,11 @@ class Chef
 
       state_attrs :minute, :hour, :day, :month, :weekday, :user
 
-      provides :cron
+      default_action :create
+      allowed_actions :create, :delete
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :cron
-        @action = :create
-        @allowed_actions.push(:create, :delete)
         @minute = "*"
         @hour = "*"
         @day = "*"
@@ -49,7 +47,7 @@ class Chef
         @environment = {}
       end
 
-      def minute(arg=nil)
+      def minute(arg = nil)
         if arg.is_a?(Integer)
           converted_arg = arg.to_s
         else
@@ -62,11 +60,11 @@ class Chef
         set_or_return(
           :minute,
           converted_arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def hour(arg=nil)
+      def hour(arg = nil)
         if arg.is_a?(Integer)
           converted_arg = arg.to_s
         else
@@ -79,11 +77,11 @@ class Chef
         set_or_return(
           :hour,
           converted_arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def day(arg=nil)
+      def day(arg = nil)
         if arg.is_a?(Integer)
           converted_arg = arg.to_s
         else
@@ -96,11 +94,11 @@ class Chef
         set_or_return(
           :day,
           converted_arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def month(arg=nil)
+      def month(arg = nil)
         if arg.is_a?(Integer)
           converted_arg = arg.to_s
         else
@@ -113,11 +111,11 @@ class Chef
         set_or_return(
           :month,
           converted_arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def weekday(arg=nil)
+      def weekday(arg = nil)
         if arg.is_a?(Integer)
           converted_arg = arg.to_s
         else
@@ -125,11 +123,11 @@ class Chef
         end
         begin
           error_message = "You provided '#{arg}' as a weekday, acceptable values are "
-          error_message << Provider::Cron::WEEKDAY_SYMBOLS.map {|sym| ":#{sym.to_s}"}.join(', ')
+          error_message << Provider::Cron::WEEKDAY_SYMBOLS.map { |sym| ":#{sym}" }.join(", ")
           error_message << " and a string in crontab format"
           if (arg.is_a?(Symbol) && !Provider::Cron::WEEKDAY_SYMBOLS.include?(arg)) ||
-            (!arg.is_a?(Symbol) && integerize(arg) > 7) ||
-            (!arg.is_a?(Symbol) && integerize(arg) < 0)
+             (!arg.is_a?(Symbol) && integerize(arg) > 7) ||
+             (!arg.is_a?(Symbol) && integerize(arg) < 0)
             raise RangeError, error_message
           end
         rescue ArgumentError
@@ -137,71 +135,71 @@ class Chef
         set_or_return(
           :weekday,
           converted_arg,
-          :kind_of => [String, Symbol]
+          :kind_of => [String, Symbol],
         )
       end
 
-      def time(arg=nil)
+      def time(arg = nil)
         set_or_return(
           :time,
           arg,
-          :equal_to => Chef::Provider::Cron::SPECIAL_TIME_VALUES
+          :equal_to => Chef::Provider::Cron::SPECIAL_TIME_VALUES,
         )
       end
 
-      def mailto(arg=nil)
+      def mailto(arg = nil)
         set_or_return(
           :mailto,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def path(arg=nil)
+      def path(arg = nil)
         set_or_return(
           :path,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def home(arg=nil)
+      def home(arg = nil)
         set_or_return(
           :home,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def shell(arg=nil)
+      def shell(arg = nil)
         set_or_return(
           :shell,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def command(arg=nil)
+      def command(arg = nil)
         set_or_return(
           :command,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def user(arg=nil)
+      def user(arg = nil)
         set_or_return(
           :user,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def environment(arg=nil)
+      def environment(arg = nil)
         set_or_return(
           :environment,
           arg,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index 36659c3..4e7c22b 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Csh < Chef::Resource::Script
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :csh
         @interpreter = "csh"
       end
 
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index 4252aa2..df301dd 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,6 +27,7 @@
 #   migration_command "rake db:migrate"
 #   environment "RAILS_ENV" => "production", "OTHER_ENV" => "foo"
 #   shallow_clone true
+#   depth 1
 #   action :deploy # or :rollback
 #   restart_command "touch tmp/restart.txt"
 #   git_ssh_wrapper "wrap-ssh4git.sh"
@@ -51,33 +52,32 @@ class Chef
     #
     class Deploy < Chef::Resource
 
-      provider_base Chef::Provider::Deploy
-
       identity_attr :repository
 
       state_attrs :deploy_to, :revision
 
-      def initialize(name, run_context=nil)
+      default_action :deploy
+      allowed_actions :force_deploy, :deploy, :rollback
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :deploy
         @deploy_to = name
         @environment = nil
-        @repository_cache = 'cached-copy'
+        @repository_cache = "cached-copy"
         @copy_exclude = []
         @purge_before_symlink = %w{log tmp/pids public/system}
         @create_dirs_before_symlink = %w{tmp public config}
-        @symlink_before_migrate = {"config/database.yml" => "config/database.yml"}
-        @symlinks = {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
-        @revision = 'HEAD'
-        @action = :deploy
+        @symlink_before_migrate = { "config/database.yml" => "config/database.yml" }
+        @symlinks = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log" }
+        @revision = "HEAD"
         @migrate = false
         @rollback_on_error = false
         @remote = "origin"
         @enable_submodules = false
         @shallow_clone = false
+        @depth = nil
         @scm_provider = Chef::Provider::Git
         @svn_force_export = false
-        @allowed_actions.push(:force_deploy, :deploy, :rollback)
         @additional_remotes = Hash[]
         @keep_releases = 5
         @enable_checkout = true
@@ -99,176 +99,180 @@ class Chef
         @current_path ||= @deploy_to + "/current"
       end
 
-      def depth
-        @shallow_clone ? "5" : nil
+      def depth(arg = @shallow_clone ? 5 : nil)
+        set_or_return(
+          :depth,
+          arg,
+          :kind_of => [ Integer ],
+        )
       end
 
       # note: deploy_to is your application "meta-root."
-      def deploy_to(arg=nil)
+      def deploy_to(arg = nil)
         set_or_return(
           :deploy_to,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def repo(arg=nil)
+      def repo(arg = nil)
         set_or_return(
           :repo,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
       alias :repository :repo
 
-      def remote(arg=nil)
+      def remote(arg = nil)
         set_or_return(
           :remote,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def role(arg=nil)
+      def role(arg = nil)
         set_or_return(
           :role,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def restart_command(arg=nil, &block)
+      def restart_command(arg = nil, &block)
         arg ||= block
         set_or_return(
           :restart_command,
           arg,
-          :kind_of => [ String, Proc ]
+          :kind_of => [ String, Proc ],
         )
       end
       alias :restart :restart_command
 
-      def migrate(arg=nil)
+      def migrate(arg = nil)
         set_or_return(
           :migrate,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def migration_command(arg=nil)
+      def migration_command(arg = nil)
         set_or_return(
           :migration_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def rollback_on_error(arg=nil)
+      def rollback_on_error(arg = nil)
         set_or_return(
           :rollback_on_error,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def user(arg=nil)
+      def user(arg = nil)
         set_or_return(
           :user,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def group(arg=nil)
+      def group(arg = nil)
         set_or_return(
           :group,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def enable_submodules(arg=nil)
+      def enable_submodules(arg = nil)
         set_or_return(
           :enable_submodules,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def shallow_clone(arg=nil)
+      def shallow_clone(arg = nil)
         set_or_return(
           :shallow_clone,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def repository_cache(arg=nil)
+      def repository_cache(arg = nil)
         set_or_return(
           :repository_cache,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def copy_exclude(arg=nil)
+      def copy_exclude(arg = nil)
         set_or_return(
           :copy_exclude,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def revision(arg=nil)
+      def revision(arg = nil)
         set_or_return(
           :revision,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
       alias :branch :revision
 
-      def git_ssh_wrapper(arg=nil)
+      def git_ssh_wrapper(arg = nil)
         set_or_return(
           :git_ssh_wrapper,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
       alias :ssh_wrapper :git_ssh_wrapper
 
-      def svn_username(arg=nil)
+      def svn_username(arg = nil)
         set_or_return(
           :svn_username,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def svn_password(arg=nil)
+      def svn_password(arg = nil)
         set_or_return(
           :svn_password,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def svn_arguments(arg=nil)
+      def svn_arguments(arg = nil)
         set_or_return(
           :svn_arguments,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def svn_info_args(arg=nil)
+      def svn_info_args(arg = nil)
         set_or_return(
           :svn_arguments,
           arg,
           :kind_of => [ String ])
       end
 
-      def scm_provider(arg=nil)
+      def scm_provider(arg = nil)
         klass = if arg.kind_of?(String) || arg.kind_of?(Symbol)
                   lookup_provider_constant(arg)
                 else
@@ -277,33 +281,39 @@ class Chef
         set_or_return(
           :scm_provider,
           klass,
-          :kind_of => [ Class ]
+          :kind_of => [ Class ],
         )
       end
 
-      def svn_force_export(arg=nil)
+      # This is to support "provider :revision" without deprecation warnings.
+      # Do NOT copy this.
+      def self.provider_base
+        Chef::Provider::Deploy
+      end
+
+      def svn_force_export(arg = nil)
         set_or_return(
           :svn_force_export,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def environment(arg=nil)
+      def environment(arg = nil)
         if arg.is_a?(String)
           Chef::Log.debug "Setting RAILS_ENV, RACK_ENV, and MERB_ENV to `#{arg}'"
           Chef::Log.warn "[DEPRECATED] please modify your deploy recipe or attributes to set the environment using a hash"
-          arg = {"RAILS_ENV"=>arg,"MERB_ENV"=>arg,"RACK_ENV"=>arg}
+          arg = { "RAILS_ENV" => arg, "MERB_ENV" => arg, "RACK_ENV" => arg }
         end
         set_or_return(
           :environment,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
        # The number of old release directories to keep around after cleanup
-      def keep_releases(arg=nil)
+      def keep_releases(arg = nil)
         [set_or_return(
           :keep_releases,
           arg,
@@ -314,11 +324,11 @@ class Chef
       # SCM clone/checkout before symlinking. Use this to get rid of files and
       # directories you want to be shared between releases.
       # Default: ["log", "tmp/pids", "public/system"]
-      def purge_before_symlink(arg=nil)
+      def purge_before_symlink(arg = nil)
         set_or_return(
           :purge_before_symlink,
           arg,
-          :kind_of => Array
+          :kind_of => Array,
         )
       end
 
@@ -330,11 +340,11 @@ class Chef
       # then specify tmp here so that the tmp directory will exist when you
       # symlink the pids directory in to the current release.
       # Default: ["tmp", "public", "config"]
-      def create_dirs_before_symlink(arg=nil)
+      def create_dirs_before_symlink(arg = nil)
         set_or_return(
           :create_dirs_before_symlink,
           arg,
-          :kind_of => Array
+          :kind_of => Array,
         )
       end
 
@@ -344,11 +354,11 @@ class Chef
       # $shared/pids that you would like to symlink as $current_release/tmp/pids
       # you specify it as "pids" => "tmp/pids"
       # Default {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
-      def symlinks(arg=nil)
+      def symlinks(arg = nil)
         set_or_return(
           :symlinks,
           arg,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
@@ -359,59 +369,59 @@ class Chef
       # For a rails/merb app, this is used to link in a known good database.yml
       # (with the production db password) before running migrate.
       # Default {"config/database.yml" => "config/database.yml"}
-      def symlink_before_migrate(arg=nil)
+      def symlink_before_migrate(arg = nil)
         set_or_return(
           :symlink_before_migrate,
           arg,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
       # Callback fires before migration is run.
-      def before_migrate(arg=nil, &block)
+      def before_migrate(arg = nil, &block)
         arg ||= block
         set_or_return(:before_migrate, arg, :kind_of => [Proc, String])
       end
 
       # Callback fires before symlinking
-      def before_symlink(arg=nil, &block)
+      def before_symlink(arg = nil, &block)
         arg ||= block
         set_or_return(:before_symlink, arg, :kind_of => [Proc, String])
       end
 
       # Callback fires before restart
-      def before_restart(arg=nil, &block)
+      def before_restart(arg = nil, &block)
         arg ||= block
         set_or_return(:before_restart, arg, :kind_of => [Proc, String])
       end
 
       # Callback fires after restart
-      def after_restart(arg=nil, &block)
+      def after_restart(arg = nil, &block)
         arg ||= block
         set_or_return(:after_restart, arg, :kind_of => [Proc, String])
       end
 
-      def additional_remotes(arg=nil)
+      def additional_remotes(arg = nil)
         set_or_return(
           :additional_remotes,
           arg,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
-      def enable_checkout(arg=nil)
+      def enable_checkout(arg = nil)
         set_or_return(
           :enable_checkout,
           arg,
-          :kind_of => [TrueClass, FalseClass]
+          :kind_of => [TrueClass, FalseClass],
         )
       end
 
-      def checkout_branch(arg=nil)
+      def checkout_branch(arg = nil)
         set_or_return(
           :checkout_branch,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
@@ -420,11 +430,11 @@ class Chef
       # timeout for SCM operations. The deploy resource must therefore support
       # a timeout method, but the timeout it describes is for SCM operations,
       # not the overall deployment. This is potentially confusing.
-      def timeout(arg=nil)
+      def timeout(arg = nil)
         set_or_return(
           :timeout,
           arg,
-          :kind_of => Integer
+          :kind_of => Integer,
         )
       end
 
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index e144ce2..41046ec 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,23 +22,9 @@ class Chef
     # Convenience class for using the deploy resource with the revision
     # deployment strategy (provider)
     class DeployRevision < Chef::Resource::Deploy
-
-      provides :deploy_revision
-
-      def initialize(*args, &block)
-        super
-        @resource_name = :deploy_revision
-      end
     end
 
     class DeployBranch < Chef::Resource::DeployRevision
-
-      provides :deploy_branch
-
-      def initialize(*args, &block)
-        super
-        @resource_name = :deploy_branch
-      end
     end
 
   end
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index 1ab7f0d..07c29b4 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,9 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/directory'
-require 'chef/mixin/securable'
+require "chef/resource"
+require "chef/provider/directory"
+require "chef/mixin/securable"
 
 class Chef
   class Resource
@@ -32,30 +32,28 @@ class Chef
 
       include Chef::Mixin::Securable
 
-      provides :directory
+      default_action :create
+      allowed_actions :create, :delete
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :directory
         @path = name
-        @action = :create
         @recursive = false
-        @allowed_actions.push(:create, :delete)
       end
 
-      def recursive(arg=nil)
+      def recursive(arg = nil)
         set_or_return(
           :recursive,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def path(arg=nil)
+      def path(arg = nil)
         set_or_return(
           :path,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 35a47e8..9ff3239 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,15 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/dpkg'
+require "chef/resource/package"
 
 class Chef
   class Resource
     class DpkgPackage < Chef::Resource::Package
-
+      resource_name :dpkg_package
       provides :dpkg_package, os: "linux"
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :dpkg_package
-      end
-
+      property :source, [ String, Array, nil ]
     end
   end
 end
diff --git a/lib/chef/resource/dsc_resource.rb b/lib/chef/resource/dsc_resource.rb
index 912b683..4a55ce1 100644
--- a/lib/chef/resource/dsc_resource.rb
+++ b/lib/chef/resource/dsc_resource.rb
@@ -1,83 +1,121 @@
-#
-# Author:: Adam Edwards (<adamed at getchef.com>)
-#
-# Copyright:: 2014, Opscode, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-require 'chef/dsl/powershell'
-
-class Chef
-  class Resource
-    class DscResource < Chef::Resource
-
-      provides :dsc_resource, os: "windows"
-
-      include Chef::DSL::Powershell
-
-      def initialize(name, run_context)
-        super
-        @properties = {}
-        @resource_name = :dsc_resource
-        @resource = nil
-        @allowed_actions.push(:run)
-        @action = :run
-      end
-
-      def resource(value=nil)
-        if value
-          @resource = value
-        else
-          @resource
-        end
-      end
-
-      def module_name(value=nil)
-        if value
-          @module_name = value
-        else
-          @module_name
-        end
-      end
-
-      def property(property_name, value=nil)
-        if not property_name.is_a?(Symbol)
-          raise TypeError, "A property name of type Symbol must be specified, '#{property_name.to_s}' of type #{property_name.class.to_s} was given"
-        end
-
-        if value.nil?
-          value_of(@properties[property_name])
-        else
-          @properties[property_name] = value
-        end
-      end
-
-      def properties
-        @properties.reduce({}) do |memo, (k, v)|
-          memo[k] = value_of(v)
-          memo
-        end
-      end
-
-      private
-
-      def value_of(value)
-        if value.is_a?(DelayedEvaluator)
-          value.call
-        else
-          value
-        end
-      end
-    end
-  end
-end
+#
+# Author:: Adam Edwards (<adamed at chef.io>)
+#
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "chef/dsl/powershell"
+
+class Chef
+  class Resource
+    class DscResource < Chef::Resource
+      provides :dsc_resource, os: "windows"
+
+      # This class will check if the object responds to
+      # to_text. If it does, it will call that as opposed
+      # to inspect. This is useful for properties that hold
+      # objects such as PsCredential, where we do not want
+      # to dump the actual ivars
+      class ToTextHash < Hash
+        def to_text
+          descriptions = self.map do |(property, obj)|
+            obj_text = if obj.respond_to?(:to_text)
+                         obj.to_text
+                       else
+                         obj.inspect
+                       end
+            "#{property}=>#{obj_text}"
+          end
+          "{#{descriptions.join(', ')}}"
+        end
+      end
+
+      include Chef::DSL::Powershell
+
+      default_action :run
+
+      def initialize(name, run_context)
+        super
+        @properties = ToTextHash.new
+        @resource = nil
+        @reboot_action = :nothing
+      end
+
+      def resource(value = nil)
+        if value
+          @resource = value
+        else
+          @resource
+        end
+      end
+
+      def module_name(value = nil)
+        if value
+          @module_name = value
+        else
+          @module_name
+        end
+      end
+
+      def property(property_name, value = nil)
+        if not property_name.is_a?(Symbol)
+          raise TypeError, "A property name of type Symbol must be specified, '#{property_name}' of type #{property_name.class} was given"
+        end
+
+        if value.nil?
+          value_of(@properties[property_name])
+        else
+          @properties[property_name] = value
+        end
+      end
+
+      def properties
+        @properties.reduce({}) do |memo, (k, v)|
+          memo[k] = value_of(v)
+          memo
+        end
+      end
+
+      # This property takes the action message for the reboot resource
+      # If the set method of the DSC resource indicate that a reboot
+      # is necessary, reboot_action provides the mechanism for a reboot to
+      # be requested.
+      def reboot_action(value = nil)
+        if value
+          @reboot_action = value
+        else
+          @reboot_action
+        end
+      end
+
+      def timeout(arg = nil)
+        set_or_return(
+          :timeout,
+          arg,
+          :kind_of => [ Integer ],
+        )
+      end
+
+      private
+
+      def value_of(value)
+        if value.is_a?(DelayedEvaluator)
+          value.call
+        else
+          value
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/resource/dsc_script.rb b/lib/chef/resource/dsc_script.rb
index cf96ef6..a8eeeb1 100644
--- a/lib/chef/resource/dsc_script.rb
+++ b/lib/chef/resource/dsc_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,24 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
+require "chef/exceptions"
+require "chef/dsl/powershell"
 
 class Chef
   class Resource
     class DscScript < Chef::Resource
+      include Chef::DSL::Powershell
 
-      provides :dsc_script, platform: "windows"
+      provides :dsc_script, os: "windows"
 
-      def initialize(name, run_context=nil)
+      default_action :run
+
+      def initialize(name, run_context = nil)
         super
-        @allowed_actions.push(:run)
-        @action = :run
-        @resource_name = :dsc_script
         @imports = {}
       end
 
-      def code(arg=nil)
+      def code(arg = nil)
         if arg && command
           raise ArgumentError, "Only one of 'code' and 'command' attributes may be specified"
         end
@@ -42,59 +43,59 @@ class Chef
         set_or_return(
           :code,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def configuration_name(arg=nil)
+      def configuration_name(arg = nil)
         if arg && code
           raise ArgumentError, "Attribute `configuration_name` may not be set if `code` is set"
         end
         set_or_return(
           :configuration_name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def command(arg=nil)
+      def command(arg = nil)
         if arg && code
           raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
         end
         set_or_return(
           :command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def configuration_data(arg=nil)
+      def configuration_data(arg = nil)
         if arg && configuration_data_script
           raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
         end
         set_or_return(
           :configuration_data,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def configuration_data_script(arg=nil)
+      def configuration_data_script(arg = nil)
         if arg && configuration_data
           raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
         end
         set_or_return(
           :configuration_data_script,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def imports(module_name=nil, *args)
+      def imports(module_name = nil, *args)
         if module_name
           @imports[module_name] ||= []
           if args.length == 0
-            @imports[module_name] << '*'
+            @imports[module_name] << "*"
           else
             @imports[module_name].push(*args)
           end
@@ -103,35 +104,35 @@ class Chef
         end
       end
 
-      def flags(arg=nil)
+      def flags(arg = nil)
         set_or_return(
           :flags,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
-      def cwd(arg=nil)
+      def cwd(arg = nil)
         set_or_return(
           :cwd,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def environment(arg=nil)
+      def environment(arg = nil)
         set_or_return(
           :environment,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
-      def timeout(arg=nil)
+      def timeout(arg = nil)
         set_or_return(
           :timeout,
           arg,
-          :kind_of => [ Integer ]
+          :kind_of => [ Integer ],
         )
       end
     end
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index 5286e9a..dc5073a 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,42 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
+require "chef/resource/package"
 
 class Chef
   class Resource
     class EasyInstallPackage < Chef::Resource::Package
+      resource_name :easy_install_package
 
-      provides :easy_install_package
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :easy_install_package
-      end
-
-      def easy_install_binary(arg=nil)
-        set_or_return(
-          :easy_install_binary,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
-
-      def python_binary(arg=nil)
-        set_or_return(
-          :python_install_binary,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
-
-      def module_name(arg=nil)
-        set_or_return(
-          :module_name,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
+      property :easy_install_binary, String, desired_state: false
+      property :python_binary, String, desired_state: false
+      property :module_name, String, desired_state: false
 
     end
   end
diff --git a/lib/chef/resource/env.rb b/lib/chef/resource/env.rb
index 2072ae5..a483b69 100644
--- a/lib/chef/resource/env.rb
+++ b/lib/chef/resource/env.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,37 +27,37 @@ class Chef
 
       provides :env, os: "windows"
 
-      def initialize(name, run_context=nil)
+      default_action :create
+      allowed_actions :create, :delete, :modify
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :env
         @key_name = name
         @value = nil
-        @action = :create
         @delim = nil
-        @allowed_actions.push(:create, :delete, :modify)
       end
 
-      def key_name(arg=nil)
+      def key_name(arg = nil)
         set_or_return(
           :key_name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def value(arg=nil)
+      def value(arg = nil)
         set_or_return(
           :value,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def delim(arg=nil)
+      def delim(arg = nil)
         set_or_return(
           :delim,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
     end
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index 24009d5..5b5273d 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/erl_call'
+require "chef/resource"
+require "chef/provider/erl_call"
 
 class Chef
   class Resource
@@ -28,57 +28,55 @@ class Chef
 
       identity_attr :code
 
-      def initialize(name, run_context=nil)
+      default_action :run
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :erl_call
 
         @code = "q()." # your erlang code goes here
         @cookie = nil # cookie of the erlang node
         @distributed = false # if you want to have a distributed erlang node
         @name_type = "sname" # type of erlang hostname name or sname
         @node_name = "chef at localhost" # the erlang node hostname
-
-        @action = "run"
-        @allowed_actions.push(:run)
       end
 
-      def code(arg=nil)
+      def code(arg = nil)
         set_or_return(
           :code,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def cookie(arg=nil)
+      def cookie(arg = nil)
         set_or_return(
           :cookie,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def distributed(arg=nil)
+      def distributed(arg = nil)
         set_or_return(
           :distributed,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def name_type(arg=nil)
+      def name_type(arg = nil)
         set_or_return(
           :name_type,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def node_name(arg=nil)
+      def node_name(arg = nil)
         set_or_return(
           :node_name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index 9f8b629..b30cc24 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/execute'
+require "chef/resource"
+require "chef/provider/execute"
 
 class Chef
   class Resource
@@ -32,12 +32,12 @@ class Chef
       # Only execute resources (and subclasses) can be guard interpreters.
       attr_accessor :is_guard_interpreter
 
-      def initialize(name, run_context=nil)
+      default_action :run
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :execute
         @command = name
         @backup = 5
-        @action = "run"
         @creates = nil
         @cwd = nil
         @environment = nil
@@ -46,93 +46,100 @@ class Chef
         @returns = 0
         @timeout = nil
         @user = nil
-        @allowed_actions.push(:run)
         @umask = nil
         @default_guard_interpreter = :execute
         @is_guard_interpreter = false
+        @live_stream = false
       end
 
-      def umask(arg=nil)
+      def umask(arg = nil)
         set_or_return(
           :umask,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
-      def command(arg=nil)
+      def command(arg = nil)
         set_or_return(
           :command,
           arg,
-          :kind_of => [ String, Array ]
+          :kind_of => [ String, Array ],
         )
       end
 
-      def creates(arg=nil)
+      def creates(arg = nil)
         set_or_return(
           :creates,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def cwd(arg=nil)
+      def cwd(arg = nil)
         set_or_return(
           :cwd,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def environment(arg=nil)
+      def environment(arg = nil)
         set_or_return(
           :environment,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
       alias :env :environment
 
-      def group(arg=nil)
+      def group(arg = nil)
         set_or_return(
           :group,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
-      def path(arg=nil)
-        Chef::Log.warn "'path' attribute of 'execute' is not used by any provider in Chef 11 and Chef 12. Use 'environment' attribute to configure 'PATH'. This attribute will be removed in Chef 13."
+      def live_stream(arg = nil)
+        set_or_return(
+          :live_stream,
+          arg,
+          :kind_of => [ TrueClass, FalseClass ])
+      end
+
+      def path(arg = nil)
+        Chef::Log.warn "The 'path' attribute of 'execute' is not used by any provider in Chef 11 or Chef 12. Use 'environment' attribute to configure 'PATH'. This attribute will be removed in Chef 13."
 
         set_or_return(
           :path,
           arg,
-          :kind_of => [ Array ]
+          :kind_of => [ Array ],
         )
       end
 
-      def returns(arg=nil)
+      def returns(arg = nil)
         set_or_return(
           :returns,
           arg,
-          :kind_of => [ Integer, Array ]
+          :kind_of => [ Integer, Array ],
         )
       end
 
-      def timeout(arg=nil)
+      def timeout(arg = nil)
         set_or_return(
           :timeout,
           arg,
-          :kind_of => [ Integer, Float ]
+          :kind_of => [ Integer, Float ],
         )
       end
 
-      def user(arg=nil)
+      def user(arg = nil)
         set_or_return(
           :user,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
@@ -157,7 +164,7 @@ class Chef
         :environment,
         :group,
         :user,
-        :umask
+        :umask,
       )
 
     end
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 53a6a16..ac6dc5f 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2008-2016, 2011-2015 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,16 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/platform/query_helpers'
-require 'chef/mixin/securable'
-require 'chef/resource/file/verification'
+require "chef/resource"
+require "chef/platform/query_helpers"
+require "chef/mixin/securable"
+require "chef/resource/file/verification"
 
 class Chef
   class Resource
     class File < Chef::Resource
       include Chef::Mixin::Securable
 
-      identity_attr :path
-
       if Platform.windows?
         # Use Windows rights instead of standard *nix permissions
         state_attrs :checksum, :rights, :deny_rights
@@ -38,96 +36,47 @@ class Chef
 
       attr_writer :checksum
 
-      provides :file
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :file
-        @path = name
-        @backup = 5
-        @action = "create"
-        @allowed_actions.push(:create, :delete, :touch, :create_if_missing)
-        @atomic_update = Chef::Config[:file_atomic_update]
-        @force_unlink = false
-        @manage_symlink_source = nil
-        @diff = nil
-        @verifications = []
-      end
-
-      def content(arg=nil)
-        set_or_return(
-          :content,
-          arg,
-          :kind_of => String
-        )
-      end
-
-      def backup(arg=nil)
-        set_or_return(
-          :backup,
-          arg,
-          :kind_of => [ Integer, FalseClass ]
-        )
-      end
-
-      def checksum(arg=nil)
-        set_or_return(
-          :checksum,
-          arg,
-          :regex => /^[a-zA-Z0-9]{64}$/
-        )
-      end
-
-      def path(arg=nil)
-        set_or_return(
-          :path,
-          arg,
-          :kind_of => String
-        )
-      end
-
-      def diff(arg=nil)
-        set_or_return(
-          :diff,
-          arg,
-          :kind_of => String
-        )
-      end
-
-      def atomic_update(arg=nil)
-        set_or_return(
-          :atomic_update,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
-
-      def force_unlink(arg=nil)
-        set_or_return(
-          :force_unlink,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
-
-      def manage_symlink_source(arg=nil)
-        set_or_return(
-          :manage_symlink_source,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
-
-      def verify(command=nil, opts={}, &block)
+      #
+      # The checksum of the rendered file.  This has to be saved on the
+      # new_resource for the 'after' state for reporting but we cannot
+      # mutate the new_resource.checksum which would change the
+      # user intent in the new_resource if the resource is reused.
+      #
+      # @returns [String] Checksum of the file we actually rendered
+      attr_accessor :final_checksum
+
+      default_action :create
+      allowed_actions :create, :delete, :touch, :create_if_missing
+
+      property :path, String, name_property: true, identity: true
+      property :atomic_update, [ true, false ], desired_state: false, default: lazy { Chef::Config[:file_atomic_update] }
+      property :backup, [ Integer, false ], desired_state: false, default: 5
+      property :checksum, [ /^[a-zA-Z0-9]{64}$/, nil ]
+      property :content, [ String, nil ], desired_state: false
+      property :diff, [ String, nil ], desired_state: false
+      property :force_unlink, [ true, false ], desired_state: false, default: false
+      property :manage_symlink_source, [ true, false ], desired_state: false
+      property :verifications, Array, default: lazy { [] }
+
+      def verify(command = nil, opts = {}, &block)
         if ! (command.nil? || [String, Symbol].include?(command.class))
           raise ArgumentError, "verify requires either a string, symbol, or a block"
         end
 
         if command || block_given?
-          @verifications << Verification.new(self, command, opts, &block)
+          verifications << Verification.new(self, command, opts, &block)
         else
-          @verifications
+          verifications
+        end
+      end
+
+      def state_for_resource_reporter
+        state_attrs = super()
+        # fix up checksum state with final_checksum saved by the provider
+        if checksum.nil? && final_checksum
+          state_attrs[:checksum] = final_checksum
         end
+        state_attrs
       end
     end
   end
diff --git a/lib/chef/resource/file/verification.rb b/lib/chef/resource/file/verification.rb
index f1ca0f1..e11035d 100644
--- a/lib/chef/resource/file/verification.rb
+++ b/lib/chef/resource/file/verification.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Steven Danna (<steve at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/guard_interpreter'
-require 'chef/mixin/descendants_tracker'
+require "chef/exceptions"
+require "chef/guard_interpreter"
+require "chef/mixin/descendants_tracker"
 
 class Chef
   class Resource
@@ -28,7 +28,7 @@ class Chef
       # See RFC 027 for a full specification
       #
       # File verifications allow user-supplied commands a means of
-      # preventing file reosurce content deploys.  Their intended use
+      # preventing file resource content deploys.  Their intended use
       # is to verify the contents of a temporary file before it is
       # deployed onto the system.
       #
@@ -73,7 +73,7 @@ class Chef
         end
 
         def self.lookup(name)
-          c = descendants.find {|d| d.provides?(name) }
+          c = descendants.find { |d| d.provides?(name) }
           if c.nil?
             raise Chef::Exceptions::VerificationNotFound.new "No file verification for #{name} found."
           end
@@ -86,7 +86,7 @@ class Chef
           @parent_resource = parent_resource
         end
 
-        def verify(path, opts={})
+        def verify(path, opts = {})
           Chef::Log.debug("Running verification[#{self}] on #{path}")
           if @block
             verify_block(path, opts)
@@ -106,7 +106,13 @@ class Chef
         # We reuse Chef::GuardInterpreter in order to support
         # the same set of options that the not_if/only_if blocks do
         def verify_command(path, opts)
-          command = @command % {:file => path}
+          # First implementation interpolated `file`; docs & RFC claim `path`
+          # is interpolated. Until `file` can be deprecated, interpolate both.
+          Chef.log_deprecation(
+            "%{file} is deprecated in verify command and will not be "\
+            "supported in Chef 13. Please use %{path} instead."
+          ) if @command.include?("%{file}")
+          command = @command % { :file => path, :path => path }
           interpreter = Chef::GuardInterpreter.for_resource(@parent_resource, command, @command_opts)
           interpreter.evaluate
         end
diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb
index 9c8db50..540774e 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -1,8 +1,8 @@
 #
-# Authors:: AJ Christensen (<aj at opscode.com>)
+# Authors:: AJ Christensen (<aj at chef.io>)
 #           Richard Manyanza (<liseki at nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,24 +18,20 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/freebsd/port'
-require 'chef/provider/package/freebsd/pkg'
-require 'chef/provider/package/freebsd/pkgng'
-require 'chef/mixin/shell_out'
+require "chef/resource/package"
+require "chef/provider/package/freebsd/port"
+require "chef/provider/package/freebsd/pkg"
+require "chef/provider/package/freebsd/pkgng"
+require "chef/mixin/shell_out"
 
 class Chef
   class Resource
     class FreebsdPackage < Chef::Resource::Package
       include Chef::Mixin::ShellOut
 
+      resource_name :freebsd_package
       provides :package, platform: "freebsd"
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :freebsd_package
-      end
-
       def after_created
         assign_provider
       end
@@ -53,7 +49,7 @@ class Chef
       end
 
       def assign_provider
-        @provider = if @source.to_s =~ /^ports$/i
+        @provider = if source.to_s =~ /^ports$/i
                       Chef::Provider::Package::Freebsd::Port
                     elsif supports_pkgng?
                       Chef::Provider::Package::Freebsd::Pkgng
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index 0e838ca..e095115 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,17 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
+require "chef/resource/package"
 
 class Chef
   class Resource
     class GemPackage < Chef::Resource::Package
+      resource_name :gem_package
 
-      provides :gem_package
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :gem_package
-        @clear_sources = false
-      end
-
-      def source(arg=nil)
-        set_or_return(:source, arg, :kind_of => [ String, Array ])
-      end
-
-      def clear_sources(arg=nil)
-        set_or_return(:clear_sources, arg, :kind_of => [ TrueClass, FalseClass ])
-      end
-
+      property :source, [ String, Array ]
+      property :clear_sources, [ true, false ], default: false, desired_state: false
       # Sets a custom gem_binary to run for gem commands.
-      def gem_binary(gem_cmd=nil)
-        set_or_return(:gem_binary,gem_cmd,:kind_of => [ String ])
-      end
+      property :gem_binary, String, desired_state: false
 
       ##
       # Options for the gem install, either a Hash or a String. When a hash is
@@ -49,10 +34,7 @@ class Chef
       # gem will be installed via the gems API. When a String is given, the gem
       # will be installed by shelling out to the gem command. Using a Hash of
       # options with an explicit gem_binary will result in undefined behavior.
-      def options(opts=nil)
-        set_or_return(:options,opts,:kind_of => [String,Hash])
-      end
-
+      property :options, [ String, Hash, nil ], desired_state: false
 
     end
   end
diff --git a/lib/chef/resource/git.rb b/lib/chef/resource/git.rb
index 7156873..0d3b143 100644
--- a/lib/chef/resource/git.rb
+++ b/lib/chef/resource/git.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,19 +22,16 @@ class Chef
   class Resource
     class Git < Chef::Resource::Scm
 
-      provides :git
-
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :git
         @additional_remotes = Hash[]
       end
 
-      def additional_remotes(arg=nil)
+      def additional_remotes(arg = nil)
         set_or_return(
           :additional_remotes,
           arg,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
diff --git a/lib/chef/resource/group.rb b/lib/chef/resource/group.rb
index 9e8f130..50a70b9 100644
--- a/lib/chef/resource/group.rb
+++ b/lib/chef/resource/group.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,79 +25,76 @@ class Chef
 
       state_attrs :members
 
-      provides :group
+      allowed_actions :create, :remove, :modify, :manage
+      default_action :create
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :group
         @group_name = name
         @gid = nil
         @members = []
         @excluded_members = []
-        @action = :create
         @append = false
         @non_unique = false
-        @allowed_actions.push(:create, :remove, :modify, :manage)
       end
 
-      def group_name(arg=nil)
+      def group_name(arg = nil)
         set_or_return(
           :group_name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def gid(arg=nil)
+      def gid(arg = nil)
         set_or_return(
           :gid,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
-      def members(arg=nil)
+      def members(arg = nil)
         converted_members = arg.is_a?(String) ? [].push(arg) : arg
         set_or_return(
           :members,
           converted_members,
-          :kind_of => [ Array ]
+          :kind_of => [ Array ],
         )
       end
 
       alias_method :users, :members
 
-      def excluded_members(arg=nil)
+      def excluded_members(arg = nil)
         converted_members = arg.is_a?(String) ? [].push(arg) : arg
         set_or_return(
           :excluded_members,
           converted_members,
-          :kind_of => [ Array ]
+          :kind_of => [ Array ],
         )
       end
 
-
-      def append(arg=nil)
+      def append(arg = nil)
         set_or_return(
           :append,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def system(arg=nil)
+      def system(arg = nil)
         set_or_return(
           :system,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def non_unique(arg=nil)
+      def non_unique(arg = nil)
         set_or_return(
           :non_unique,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
     end
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index 73409b1..c2d0a65 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
+# Author:: Joshua Timberman (<joshua at chef.io>)
 # Author:: Graeme Mathieson (<mathie at woss.name>)
 #
-# Copyright 2011-2013, Opscode, Inc.
-# Copyright 2014, Chef Software, Inc <legal at getchef.com>
+# Copyright 2011-2016, Chef Software Inc.
+# Copyright 2014-2016, Chef Software, Inc <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,29 +18,16 @@
 # limitations under the License.
 #
 
-require 'chef/provider/package'
-require 'chef/resource/package'
+require "chef/provider/package"
+require "chef/resource/package"
 
 class Chef
   class Resource
     class HomebrewPackage < Chef::Resource::Package
-
-      provides :homebrew_package
+      resource_name :homebrew_package
       provides :package, os: "darwin"
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :homebrew_package
-        @homebrew_user = nil
-      end
-
-      def homebrew_user(arg=nil)
-        set_or_return(
-            :homebrew_user,
-            arg,
-            :kind_of => [ String, Integer ]
-        )
-      end
+      property :homebrew_user, [ String, Integer ]
 
     end
   end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index ccb0a26..be69e2f 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/http_request'
+require "chef/resource"
+require "chef/provider/http_request"
 
 class Chef
   class Resource
@@ -26,38 +26,38 @@ class Chef
 
       identity_attr :url
 
-      def initialize(name, run_context=nil)
+      default_action :get
+      allowed_actions :get, :put, :post, :delete, :head, :options
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :http_request
         @message = name
         @url = nil
-        @action = :get
         @headers = {}
-        @allowed_actions.push(:get, :put, :post, :delete, :head, :options)
       end
 
-      def url(args=nil)
+      def url(args = nil)
         set_or_return(
           :url,
           args,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def message(args=nil, &block)
+      def message(args = nil, &block)
         args = block if block_given?
         set_or_return(
           :message,
           args,
-          :kind_of => Object
+          :kind_of => Object,
         )
       end
 
-      def headers(args=nil)
+      def headers(args = nil)
         set_or_return(
           :headers,
           args,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb
index c289dda..94362b1 100644
--- a/lib/chef/resource/ifconfig.rb
+++ b/lib/chef/resource/ifconfig.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jason K. Jackson (jasonjackson at gmail.com)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Jason K. Jackson
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Jason K. Jackson
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
@@ -27,12 +27,12 @@ class Chef
 
       state_attrs :inet_addr, :mask
 
-      def initialize(name, run_context=nil)
+      default_action :add
+      allowed_actions :add, :delete, :enable, :disable
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :ifconfig
         @target = name
-        @action = :add
-        @allowed_actions.push(:add, :delete, :enable, :disable)
         @hwaddr = nil
         @mask = nil
         @inet_addr = nil
@@ -46,104 +46,102 @@ class Chef
         @onparent = nil
       end
 
-      def target(arg=nil)
+      def target(arg = nil)
         set_or_return(
           :target,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def device(arg=nil)
+      def device(arg = nil)
         set_or_return(
           :device,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def hwaddr(arg=nil)
+      def hwaddr(arg = nil)
         set_or_return(
           :hwaddr,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def inet_addr(arg=nil)
+      def inet_addr(arg = nil)
         set_or_return(
           :inet_addr,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def bcast(arg=nil)
+      def bcast(arg = nil)
         set_or_return(
           :bcast,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def mask(arg=nil)
+      def mask(arg = nil)
         set_or_return(
           :mask,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def mtu(arg=nil)
+      def mtu(arg = nil)
         set_or_return(
           :mtu,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def metric(arg=nil)
+      def metric(arg = nil)
         set_or_return(
           :metric,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def onboot(arg=nil)
+      def onboot(arg = nil)
         set_or_return(
           :onboot,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def network(arg=nil)
+      def network(arg = nil)
         set_or_return(
           :network,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def bootproto(arg=nil)
+      def bootproto(arg = nil)
         set_or_return(
           :bootproto,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def onparent(arg=nil)
+      def onparent(arg = nil)
         set_or_return(
           :onparent,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
     end
 
   end
 end
-
-
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index c0e699e..4d2c957 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jason Williams (<williamsjj at digitar.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,29 +16,19 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/ips'
+require "chef/resource/package"
+require "chef/provider/package/ips"
 
 class Chef
   class Resource
     class IpsPackage < ::Chef::Resource::Package
-
+      resource_name :ips_package
+      provides :package, os: "solaris2"
       provides :ips_package, os: "solaris2"
 
-      def initialize(name, run_context = nil)
-        super(name, run_context)
-        @resource_name = :ips_package
-        @allowed_actions.push(:install, :remove, :upgrade)
-        @accept_license = false
-      end
+      allowed_actions :install, :remove, :upgrade
 
-      def accept_license(arg=nil)
-        set_or_return(
-          :purge,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
+      property :accept_license, [ true, false ], default: false, desired_state: false
     end
   end
 end
diff --git a/lib/chef/resource/ksh.rb b/lib/chef/resource/ksh.rb
new file mode 100644
index 0000000..3097156
--- /dev/null
+++ b/lib/chef/resource/ksh.rb
@@ -0,0 +1,32 @@
+#
+# Author:: Nolan Davidson (<nolan.davidson at gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/script"
+
+class Chef
+  class Resource
+    class Ksh < Chef::Resource::Script
+
+      def initialize(name, run_context = nil)
+        super
+        @interpreter = "ksh"
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/resource/link.rb b/lib/chef/resource/link.rb
index 30f8ec8..a85e9eb 100644
--- a/lib/chef/resource/link.rb
+++ b/lib/chef/resource/link.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,69 +17,67 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/mixin/securable'
+require "chef/resource"
+require "chef/mixin/securable"
 
 class Chef
   class Resource
     class Link < Chef::Resource
       include Chef::Mixin::Securable
 
-      provides :link
-
       identity_attr :target_file
 
       state_attrs :to, :owner, :group
 
-      def initialize(name, run_context=nil)
+      default_action :create
+      allowed_actions :create, :delete
+
+      def initialize(name, run_context = nil)
         verify_links_supported!
         super
-        @resource_name = :link
         @to = nil
-        @action = :create
         @link_type = :symbolic
         @target_file = name
-        @allowed_actions.push(:create, :delete)
       end
 
-      def to(arg=nil)
+      def to(arg = nil)
         set_or_return(
           :to,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def target_file(arg=nil)
+      def target_file(arg = nil)
         set_or_return(
           :target_file,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def link_type(arg=nil)
+      def link_type(arg = nil)
         real_arg = arg.kind_of?(String) ? arg.to_sym : arg
         set_or_return(
           :link_type,
           real_arg,
-          :equal_to => [ :symbolic, :hard ]
+          :equal_to => [ :symbolic, :hard ],
         )
       end
 
-      def group(arg=nil)
+      def group(arg = nil)
         set_or_return(
           :group,
           arg,
-          :regex => Chef::Config[:group_valid_regex]
+          :regex => Chef::Config[:group_valid_regex],
         )
       end
 
-      def owner(arg=nil)
+      def owner(arg = nil)
         set_or_return(
           :owner,
           arg,
-          :regex => Chef::Config[:user_valid_regex]
+          :regex => Chef::Config[:user_valid_regex],
         )
       end
 
@@ -89,12 +87,13 @@ class Chef
       end
 
       private
+
       def verify_links_supported!
         # On certain versions of windows links are not supported. Make
         # sure we are not on such a platform.
 
         if Chef::Platform.windows?
-          require 'chef/win32/file'
+          require "chef/win32/file"
           begin
             Chef::ReservedNames::Win32::File.verify_links_supported!
           rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 7f970a8..a9b288a 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Cary Penniman (<cary at rightscale.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/log'
+require "chef/resource"
+require "chef/provider/log"
 
 class Chef
   class Resource
@@ -26,6 +26,8 @@ class Chef
 
       identity_attr :message
 
+      default_action :write
+
       # Sends a string from a recipe to a log provider
       #
       # log "some string to log" do
@@ -46,34 +48,29 @@ class Chef
       # name<String>:: Message to log
       # collection<Array>:: Collection of included recipes
       # node<Chef::Node>:: Node where resource will be used
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :log
         @level = :info
-        @action = :write
-        @allowed_actions.push(:write)
         @message = name
       end
 
-      def message(arg=nil)
+      def message(arg = nil)
         set_or_return(
           :message,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
       # <Symbol> Log level, one of :debug, :info, :warn, :error or :fatal
-      def level(arg=nil)
+      def level(arg = nil)
         set_or_return(
           :level,
           arg,
-          :equal_to => [ :debug, :info, :warn, :error, :fatal ]
+          :equal_to => [ :debug, :info, :warn, :error, :fatal ],
         )
       end
 
     end
   end
 end
-
-
diff --git a/lib/chef/resource/lwrp_base.rb b/lib/chef/resource/lwrp_base.rb
index ce72e98..7dfe147 100644
--- a/lib/chef/resource/lwrp_base.rb
+++ b/lib/chef/resource/lwrp_base.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008-2012 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
+require "chef/resource_resolver"
+require "chef/node"
+require "chef/log"
+require "chef/exceptions"
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate" # for DelayedEvaluator
 
 class Chef
   class Resource
@@ -28,138 +35,90 @@ class Chef
     # so attributes, default action, etc. can be defined with pleasing syntax.
     class LWRPBase < Resource
 
-      NULL_ARG = Object.new
+      # Class methods
+      class <<self
 
-      extend Chef::Mixin::ConvertToClassName
-      extend Chef::Mixin::FromFile
+        include Chef::Mixin::ConvertToClassName
+        include Chef::Mixin::FromFile
 
-      # Evaluates the LWRP resource file and instantiates a new Resource class.
-      def self.build_from_file(cookbook_name, filename, run_context)
-        resource_class = nil
-        rname = filename_to_qualified_string(cookbook_name, filename)
+        attr_accessor :loaded_lwrps
 
-        class_name = convert_to_class_name(rname)
-        if Resource.const_defined?(class_name, false)
-          Chef::Log.info("#{class_name} light-weight resource is already initialized -- Skipping loading #{filename}!")
-          Chef::Log.debug("Overriding already defined LWRPs is not supported anymore starting with Chef 12.")
-          resource_class = Resource.const_get(class_name)
-        else
-          resource_class = Class.new(self)
+        def build_from_file(cookbook_name, filename, run_context)
+          if LWRPBase.loaded_lwrps[filename]
+            Chef::Log.debug("Custom resource #{filename} from cookbook #{cookbook_name} has already been loaded!  Skipping the reload.")
+            return loaded_lwrps[filename]
+          end
 
-          Chef::Resource.const_set(class_name, resource_class)
-          resource_class.resource_name = rname
+          resource_name = filename_to_qualified_string(cookbook_name, filename)
+
+          # We load the class first to give it a chance to set its own name
+          resource_class = Class.new(self)
+          resource_class.resource_name resource_name.to_sym
           resource_class.run_context = run_context
           resource_class.class_from_file(filename)
 
-          Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}")
-        end
-
-        resource_class
-      end
+          # Make a useful string for the class (rather than <Class:312894723894>)
+          resource_class.instance_eval do
+            define_singleton_method(:to_s) do
+              "Custom resource #{resource_name} from cookbook #{cookbook_name}"
+            end
+            define_singleton_method(:inspect) { to_s }
+          end
 
-      # Set the resource name for this LWRP
-      def self.resource_name(arg = NULL_ARG)
-        if arg.equal?(NULL_ARG)
-          @resource_name
-        else
-          @resource_name = arg
-        end
-      end
+          Chef::Log.debug("Loaded contents of #{filename} into resource #{resource_name} (#{resource_class})")
 
-      class << self
-        alias_method :resource_name=, :resource_name
-      end
+          LWRPBase.loaded_lwrps[filename] = true
 
-      # Define an attribute on this resource, including optional validation
-      # parameters.
-      def self.attribute(attr_name, validation_opts={})
-        define_method(attr_name) do |arg=nil|
-          set_or_return(attr_name.to_sym, arg, validation_opts)
+          # Create the deprecated Chef::Resource::LwrpFoo class
+          Chef::Resource.register_deprecated_lwrp_class(resource_class, convert_to_class_name(resource_name))
+          resource_class
         end
-      end
 
-      # Sets the default action
-      def self.default_action(action_name=NULL_ARG)
-        unless action_name.equal?(NULL_ARG)
-          @actions ||= []
-          if action_name.is_a?(Array)
-            action = action_name.map { |arg| arg.to_sym }
-            @actions = actions | action
-            @default_action = action
-          else
-            action = action_name.to_sym
-            @actions.push(action) unless @actions.include?(action)
-            @default_action = action
-          end
-        end
+        alias :attribute :property
 
-        @default_action ||= from_superclass(:default_action)
-      end
-
-      # Adds +action_names+ to the list of valid actions for this resource.
-      def self.actions(*action_names)
-        if action_names.empty?
-          defined?(@actions) ? @actions : from_superclass(:actions, []).dup
-        else
-          # BC-compat way for checking if actions have already been defined
-          if defined?(@actions)
-            @actions.push(*action_names)
+        # Adds +action_names+ to the list of valid actions for this resource.
+        # Does not include superclass's action list when appending.
+        def actions(*action_names)
+          action_names = action_names.flatten
+          if !action_names.empty? && !@allowed_actions
+            self.allowed_actions = ([ :nothing ] + action_names).uniq
           else
-            @actions = action_names
+            allowed_actions(*action_names)
           end
         end
-      end
-
-      # @deprecated
-      def self.valid_actions(*args)
-        Chef::Log.warn("`valid_actions' is deprecated, please use actions `instead'!")
-        actions(*args)
-      end
+        alias :actions= :allowed_actions=
 
-      # Set the run context on the class. Used to provide access to the node
-      # during class definition.
-      def self.run_context=(run_context)
-        @run_context = run_context
-      end
+        # @deprecated
+        def valid_actions(*args)
+          Chef::Log.warn("`valid_actions' is deprecated, please use allowed_actions `instead'!")
+          allowed_actions(*args)
+        end
 
-      def self.run_context
-        @run_context
-      end
+        # Set the run context on the class. Used to provide access to the node
+        # during class definition.
+        attr_accessor :run_context
 
-      def self.node
-        run_context.node
-      end
-
-      def self.lazy(&block)
-        DelayedEvaluator.new(&block)
-      end
+        def node
+          run_context ? run_context.node : nil
+        end
 
-      private
+        protected
 
-      # Get the value from the superclass, if it responds, otherwise return
-      # +nil+. Since class instance variables are **not** inherited upon
-      # subclassing, this is a required check to ensure Chef pulls the
-      # +default_action+ and other DSL-y methods when extending LWRP::Base.
-      def self.from_superclass(m, default = nil)
-        return default if superclass == Chef::Resource::LWRPBase
-        superclass.respond_to?(m) ? superclass.send(m) : default
-      end
+        def loaded_lwrps
+          @loaded_lwrps ||= {}
+        end
 
-      # Default initializer. Sets the default action and allowed actions.
-      def initialize(name, run_context=nil)
-        super(name, run_context)
+        private
 
-        # Raise an exception if the resource_name was not defined
-        if self.class.resource_name.nil?
-          raise Chef::Exceptions::InvalidResourceSpecification,
-            "You must specify `resource_name'!"
+        # Get the value from the superclass, if it responds, otherwise return
+        # +nil+. Since class instance variables are **not** inherited upon
+        # subclassing, this is a required check to ensure Chef pulls the
+        # +default_action+ and other DSL-y methods when extending LWRP::Base.
+        def from_superclass(m, default = nil)
+          return default if superclass == Chef::Resource::LWRPBase
+          superclass.respond_to?(m) ? superclass.send(m) : default
         end
-
-        @resource_name = self.class.resource_name.to_sym
-        @action = self.class.default_action
-        allowed_actions.push(self.class.actions).flatten!
       end
-
     end
   end
 end
diff --git a/lib/chef/resource/macosx_service.rb b/lib/chef/resource/macosx_service.rb
index 879ea99..c2d05e5 100644
--- a/lib/chef/resource/macosx_service.rb
+++ b/lib/chef/resource/macosx_service.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mike Dodge (<mikedodge04 at gmail.com>)
-# Copyright:: Copyright (c) 2015 Facebook, Inc.
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,41 +16,40 @@
 # limitations under the License.
 #
 
-require 'chef/resource/service'
+require "chef/resource/service"
 
 class Chef
   class Resource
     class MacosxService < Chef::Resource::Service
 
-      provides :service, os: "darwin"
       provides :macosx_service, os: "darwin"
+      provides :service, os: "darwin"
 
       identity_attr :service_name
 
       state_attrs :enabled, :running
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :macosx_service
         @plist = nil
         @session_type = nil
       end
 
       # This will enable user to pass a plist in the case
       # that the filename and label for the service dont match
-      def plist(arg=nil)
+      def plist(arg = nil)
         set_or_return(
           :plist,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def session_type(arg=nil)
+      def session_type(arg = nil)
         set_or_return(
           :session_type,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index 0d4e5de..3685334 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: David Balatero (<dbalatero at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,12 @@
 # limitations under the License.
 #
 
+require "chef/resource/package"
+
 class Chef
   class Resource
     class MacportsPackage < Chef::Resource::Package
-
-      provides :macports_package
-      provides :package, os: "darwin"
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :macports_package
-      end
+      resource_name :macports_package
     end
   end
 end
diff --git a/lib/chef/resource/mdadm.rb b/lib/chef/resource/mdadm.rb
index 971b6c5..efdd448 100644
--- a/lib/chef/resource/mdadm.rb
+++ b/lib/chef/resource/mdadm.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
@@ -27,11 +27,11 @@ class Chef
 
       state_attrs :devices, :level, :chunk
 
-      provides :mdadm
+      default_action :create
+      allowed_actions :create, :assemble, :stop
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :mdadm
 
         @chunk = 16
         @devices = []
@@ -40,68 +40,64 @@ class Chef
         @metadata = "0.90"
         @bitmap = nil
         @raid_device = name
-
-        @action = :create
-        @allowed_actions.push(:create, :assemble, :stop)
       end
 
-      def chunk(arg=nil)
+      def chunk(arg = nil)
         set_or_return(
           :chunk,
           arg,
-          :kind_of => [ Integer ]
+          :kind_of => [ Integer ],
         )
       end
 
-      def devices(arg=nil)
+      def devices(arg = nil)
         set_or_return(
           :devices,
           arg,
-          :kind_of => [ Array ]
+          :kind_of => [ Array ],
         )
       end
 
-      def exists(arg=nil)
+      def exists(arg = nil)
         set_or_return(
           :exists,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def level(arg=nil)
+      def level(arg = nil)
         set_or_return(
           :level,
           arg,
-          :kind_of => [ Integer ]
+          :kind_of => [ Integer ],
         )
       end
 
-      def metadata(arg=nil)
+      def metadata(arg = nil)
         set_or_return(
           :metadata,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def bitmap(arg=nil)
+      def bitmap(arg = nil)
         set_or_return(
           :bitmap,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def raid_device(arg=nil)
+      def raid_device(arg = nil)
         set_or_return(
           :raid_device,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-
     end
   end
 end
diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb
index 142dec8..7bbff57 100644
--- a/lib/chef/resource/mount.rb
+++ b/lib/chef/resource/mount.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
@@ -27,46 +27,44 @@ class Chef
 
       state_attrs :mount_point, :device_type, :fstype, :username, :password, :domain
 
-      provides :mount
+      default_action :mount
+      allowed_actions :mount, :umount, :remount, :enable, :disable
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :mount
         @mount_point = name
         @device = nil
         @device_type = :device
-        @fsck_device = '-'
+        @fsck_device = "-"
         @fstype = "auto"
         @options = ["defaults"]
         @dump = 0
         @pass = 2
         @mounted = false
         @enabled = false
-        @action = :mount
         @supports = { :remount => false }
-        @allowed_actions.push(:mount, :umount, :remount, :enable, :disable)
         @username = nil
         @password = nil
         @domain = nil
       end
 
-      def mount_point(arg=nil)
+      def mount_point(arg = nil)
         set_or_return(
           :mount_point,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def device(arg=nil)
+      def device(arg = nil)
         set_or_return(
           :device,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def device_type(arg=nil)
+      def device_type(arg = nil)
         real_arg = arg.kind_of?(String) ? arg.to_sym : arg
         valid_devices = if RUBY_PLATFORM =~ /solaris/i
                           [ :device ]
@@ -76,73 +74,73 @@ class Chef
         set_or_return(
           :device_type,
           real_arg,
-          :equal_to => valid_devices
+          :equal_to => valid_devices,
         )
       end
 
-      def fsck_device(arg=nil)
+      def fsck_device(arg = nil)
         set_or_return(
           :fsck_device,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def fstype(arg=nil)
+      def fstype(arg = nil)
         set_or_return(
           :fstype,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def options(arg=nil)
+      def options(arg = nil)
         ret = set_or_return(
                             :options,
                             arg,
-                            :kind_of => [ Array, String ]
+                            :kind_of => [ Array, String ],
                             )
 
         if ret.is_a? String
-          ret.gsub(/,/, ' ').split(/ /)
+          ret.gsub(/,/, " ").split(/ /)
         else
           ret
         end
       end
 
-      def dump(arg=nil)
+      def dump(arg = nil)
         set_or_return(
           :dump,
           arg,
-          :kind_of => [ Integer, FalseClass ]
+          :kind_of => [ Integer, FalseClass ],
         )
       end
 
-      def pass(arg=nil)
+      def pass(arg = nil)
         set_or_return(
           :pass,
           arg,
-          :kind_of => [ Integer, FalseClass ]
+          :kind_of => [ Integer, FalseClass ],
         )
       end
 
-      def mounted(arg=nil)
+      def mounted(arg = nil)
         set_or_return(
           :mounted,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def enabled(arg=nil)
+      def enabled(arg = nil)
         set_or_return(
           :enabled,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def supports(args={})
+      def supports(args = {})
         if args.is_a? Array
           args.each { |arg| @supports[arg] = true }
         elsif args.any?
@@ -152,30 +150,38 @@ class Chef
         end
       end
 
-      def username(arg=nil)
+      def username(arg = nil)
         set_or_return(
           :username,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def password(arg=nil)
+      def password(arg = nil)
         set_or_return(
           :password,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def domain(arg=nil)
+      def domain(arg = nil)
         set_or_return(
           :domain,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
+      private
+
+      # Used by the AIX provider to set fstype to nil.
+      # TODO use property to make nil a valid value for fstype
+      def clear_fstype
+        @fstype = nil
+      end
+
     end
   end
 end
diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb
index b567db4..5211e2f 100644
--- a/lib/chef/resource/ohai.rb
+++ b/lib/chef/resource/ohai.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Michael Leinartas (<mleinartas at gmail.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2010-2016, Michael Leinartas
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,28 +25,27 @@ class Chef
 
       state_attrs :plugin
 
-      def initialize(name, run_context=nil)
+      default_action :reload
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :ohai
         @name = name
-        @allowed_actions.push(:reload)
-        @action = :reload
         @plugin = nil
       end
 
-      def plugin(arg=nil)
+      def plugin(arg = nil)
         set_or_return(
           :plugin,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def name(arg=nil)
+      def name(arg = nil)
         set_or_return(
           :name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
     end
diff --git a/lib/chef/resource/openbsd_package.rb b/lib/chef/resource/openbsd_package.rb
index 20a2523..d0f9fe8 100644
--- a/lib/chef/resource/openbsd_package.rb
+++ b/lib/chef/resource/openbsd_package.rb
@@ -1,9 +1,9 @@
 #
-# Authors:: AJ Christensen (<aj at opscode.com>)
+# Authors:: AJ Christensen (<aj at chef.io>)
 #           Richard Manyanza (<liseki at nyikacraftsmen.com>)
 #           Scott Bonds (<scott at ggr.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,33 +19,17 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/openbsd'
-require 'chef/mixin/shell_out'
+require "chef/resource/package"
+require "chef/provider/package/openbsd"
+require "chef/mixin/shell_out"
 
 class Chef
   class Resource
     class OpenbsdPackage < Chef::Resource::Package
       include Chef::Mixin::ShellOut
 
+      resource_name :openbsd_package
       provides :package, os: "openbsd"
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :openbsd_package
-      end
-
-      def after_created
-        assign_provider
-      end
-
-      private
-
-      def assign_provider
-        @provider = Chef::Provider::Package::Openbsd
-      end
-
     end
   end
 end
-
diff --git a/lib/chef/resource/osx_profile.rb b/lib/chef/resource/osx_profile.rb
new file mode 100644
index 0000000..920d09a
--- /dev/null
+++ b/lib/chef/resource/osx_profile.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Nate Walck (<nate.walck at gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource"
+
+class Chef
+  class Resource
+    class OsxProfile < Chef::Resource
+      provides :osx_profile, os: "darwin"
+      provides :osx_config_profile, os: "darwin"
+
+      identity_attr :profile_name
+
+      default_action :install
+      allowed_actions :install, :remove
+
+      def initialize(name, run_context = nil)
+        super
+        @profile_name = name
+        @profile = nil
+        @identifier = nil
+        @path = nil
+      end
+
+      def profile_name(arg = nil)
+        set_or_return(
+          :profile_name,
+          arg,
+          :kind_of => [ String ],
+        )
+      end
+
+      def profile(arg = nil)
+        set_or_return(
+          :profile,
+          arg,
+          :kind_of => [ String, Hash ],
+        )
+      end
+
+      def identifier(arg = nil)
+        set_or_return(
+          :identifier,
+          arg,
+          :kind_of => [ String ],
+        )
+      end
+
+      def path(arg = nil)
+        set_or_return(
+          :path,
+          arg,
+          :kind_of => [ String ],
+        )
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/resource/package.rb b/lib/chef/resource/package.rb
index f4f49b5..32339e1 100644
--- a/lib/chef/resource/package.rb
+++ b/lib/chef/resource/package.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,86 +17,30 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class Package < Chef::Resource
+      resource_name :package
 
-      identity_attr :package_name
+      default_action :install
+      allowed_actions :install, :upgrade, :remove, :purge, :reconfig
 
-      state_attrs :version, :options
-
-      def initialize(name, run_context=nil)
+      def initialize(name, *args)
+        # We capture name here, before it gets coerced to name
+        package_name name
         super
-        @action = :install
-        @allowed_actions.push(:install, :upgrade, :remove, :purge, :reconfig)
-        @candidate_version = nil
-        @options = nil
-        @package_name = name
-        @resource_name = :package
-        @response_file = nil
-        @response_file_variables = Hash.new
-        @source = nil
-        @version = nil
-        @timeout = 900
-      end
-
-      def package_name(arg=nil)
-        set_or_return(
-          :package_name,
-          arg,
-          :kind_of => [ String, Array ]
-        )
       end
 
-      def version(arg=nil)
-        set_or_return(
-          :version,
-          arg,
-          :kind_of => [ String, Array ]
-        )
-      end
+      property :package_name, [ String, Array ], identity: true
 
-      def response_file(arg=nil)
-        set_or_return(
-          :response_file,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
-
-      def response_file_variables(arg=nil)
-        set_or_return(
-          :response_file_variables,
-          arg,
-          :kind_of => [ Hash ]
-        )
-      end
-
-      def source(arg=nil)
-        set_or_return(
-          :source,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
-
-      def options(arg=nil)
-        set_or_return(
-      	  :options,
-      	  arg,
-      	  :kind_of => [ String ]
-      	)
-      end
-
-      def timeout(arg=nil)
-        set_or_return(
-          :timeout,
-          arg,
-          :kind_of => [String, Integer]
-        )
-      end
+      property :version, [ String, Array ]
+      property :options, String
+      property :response_file, String, desired_state: false
+      property :response_file_variables, Hash, default: lazy { {} }, desired_state: false
+      property :source, String, desired_state: false
+      property :timeout, [ String, Integer ], desired_state: false
 
     end
   end
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index 4c45dd0..66b39d1 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
+require "chef/resource/package"
 
 class Chef
   class Resource
     class PacmanPackage < Chef::Resource::Package
-
+      resource_name :pacman_package
       provides :pacman_package, os: "linux"
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :pacman_package
-      end
-
     end
   end
 end
diff --git a/lib/chef/resource/paludis_package.rb b/lib/chef/resource/paludis_package.rb
index 552c968..31c0f31 100644
--- a/lib/chef/resource/paludis_package.rb
+++ b/lib/chef/resource/paludis_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Vasiliy Tolstov (<v.tolstov at selfip.ru>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,18 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/paludis'
+require "chef/resource/package"
+require "chef/provider/package/paludis"
 
 class Chef
   class Resource
     class PaludisPackage < Chef::Resource::Package
-
+      resource_name :paludis_package
       provides :paludis_package, os: "linux"
 
-      def initialize(name, run_context=nil)
-        super(name, run_context)
-        @resource_name = :paludis_package
-        @allowed_actions.push(:install, :remove, :upgrade)
-        @timeout = 3600
-      end
+      allowed_actions :install, :remove, :upgrade
+
+      property :timeout, default: 3600
     end
   end
 end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index c4bdb6e..60af0e9 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Perl < Chef::Resource::Script
-
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :perl
         @interpreter = "perl"
       end
 
diff --git a/lib/chef/resource/portage_package.rb b/lib/chef/resource/portage_package.rb
index 42c0356..ad66c7b 100644
--- a/lib/chef/resource/portage_package.rb
+++ b/lib/chef/resource/portage_package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
+require "chef/resource/package"
 
 class Chef
   class Resource
     class PortagePackage < Chef::Resource::Package
-
-      def initialize(name, run_context=nil)
+      resource_name :portage_package
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :portage_package
         @provider = Chef::Provider::Package::Portage
       end
 
diff --git a/lib/chef/resource/powershell_script.rb b/lib/chef/resource/powershell_script.rb
index 43aafe4..e66db9f 100644
--- a/lib/chef/resource/powershell_script.rb
+++ b/lib/chef/resource/powershell_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,24 +15,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/resource/windows_script'
+require "chef/resource/windows_script"
 
 class Chef
   class Resource
     class PowershellScript < Chef::Resource::WindowsScript
-
       provides :powershell_script, os: "windows"
 
-      def initialize(name, run_context=nil)
-        super(name, run_context, :powershell_script, "powershell.exe")
+      def initialize(name, run_context = nil)
+        super(name, run_context, nil, "powershell.exe")
         @convert_boolean_return = false
       end
 
-      def convert_boolean_return(arg=nil)
+      def convert_boolean_return(arg = nil)
         set_or_return(
           :convert_boolean_return,
           arg,
-          :kind_of => [ FalseClass, TrueClass ]
+          :kind_of => [ FalseClass, TrueClass ],
         )
       end
 
@@ -44,7 +43,7 @@ class Chef
       # guard context and recipe resource context will have the
       # same behavior.
       def self.get_default_attributes(opts)
-        {:convert_boolean_return => true}
+        { :convert_boolean_return => true }
       end
     end
   end
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index b1f23d1..bcad3d0 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -1,5 +1,5 @@
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,16 +15,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Python < Chef::Resource::Script
-
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :python
         @interpreter = "python"
       end
 
diff --git a/lib/chef/resource/reboot.rb b/lib/chef/resource/reboot.rb
index c111b23..24d6e74 100644
--- a/lib/chef/resource/reboot.rb
+++ b/lib/chef/resource/reboot.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Chris Doherty <cdoherty at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 # In using this resource via notifications, it's important to *only* use
 # immediate notifications. Delayed notifications produce unintuitive and
@@ -24,11 +24,11 @@ require 'chef/resource'
 class Chef
   class Resource
     class Reboot < Chef::Resource
-      def initialize(name, run_context=nil)
+      allowed_actions :request_reboot, :reboot_now, :cancel
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :reboot
         @provider = Chef::Provider::Reboot
-        @allowed_actions.push(:request_reboot, :reboot_now, :cancel)
 
         @reason = "Reboot by Chef"
         @delay_mins = 0
@@ -36,11 +36,11 @@ class Chef
         # no default action.
       end
 
-      def reason(arg=nil)
+      def reason(arg = nil)
         set_or_return(:reason, arg, :kind_of => String)
       end
 
-      def delay_mins(arg=nil)
+      def delay_mins(arg = nil)
         set_or_return(:delay_mins, arg, :kind_of => Fixnum)
       end
     end
diff --git a/lib/chef/resource/registry_key.rb b/lib/chef/resource/registry_key.rb
index 8126ccf..135e63d 100644
--- a/lib/chef/resource/registry_key.rb
+++ b/lib/chef/resource/registry_key.rb
@@ -1,7 +1,7 @@
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
 #
-# Copyright:: 2011, Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,17 +15,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/provider/registry_key'
-require 'chef/resource'
-require 'chef/digester'
+require "chef/provider/registry_key"
+require "chef/resource"
+require "chef/digester"
 
 class Chef
   class Resource
     class RegistryKey < Chef::Resource
-
       identity_attr :key
       state_attrs :values
 
+      default_action :create
+      allowed_actions :create, :create_if_missing, :delete, :delete_key
+
       # Some registry key data types may not be safely reported as json.
       # Example (CHEF-5323):
       #
@@ -57,26 +59,23 @@ class Chef
       # See lib/chef/resource_reporter.rb for more information.
       attr_reader :unscrubbed_values
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :registry_key
-        @action = :create
         @architecture = :machine
         @recursive = false
         @key = name
         @values, @unscrubbed_values = [], []
-        @allowed_actions.push(:create, :create_if_missing, :delete, :delete_key)
       end
 
-      def key(arg=nil)
+      def key(arg = nil)
         set_or_return(
           :key,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def values(arg=nil)
+      def values(arg = nil)
         if not arg.nil?
           if arg.is_a?(Hash)
             @values = [ arg ]
@@ -91,10 +90,10 @@ class Chef
             raise ArgumentError, "Missing type key in RegistryKey values hash" unless v.has_key?(:type)
             raise ArgumentError, "Missing data key in RegistryKey values hash" unless v.has_key?(:data)
             v.each_key do |key|
-              raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless [:name,:type,:data].include?(key)
+              raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless [:name, :type, :data].include?(key)
             end
             raise ArgumentError, "Type of name => #{v[:name]} should be string" unless v[:name].is_a?(String)
-            raise Argument Error "Type of type => #{v[:name]} should be symbol" unless v[:type].is_a?(Symbol)
+            raise ArgumentError, "Type of type => #{v[:type]} should be symbol" unless v[:type].is_a?(Symbol)
           end
           @unscrubbed_values = @values
         elsif self.instance_variable_defined?(:@values)
@@ -102,19 +101,19 @@ class Chef
         end
       end
 
-      def recursive(arg=nil)
+      def recursive(arg = nil)
         set_or_return(
           :recursive,
           arg,
-          :kind_of => [TrueClass, FalseClass]
+          :kind_of => [TrueClass, FalseClass],
         )
       end
 
-      def architecture(arg=nil)
+      def architecture(arg = nil)
         set_or_return(
           :architecture,
           arg,
-          :kind_of => Symbol
+          :kind_of => Symbol,
         )
       end
 
@@ -126,7 +125,7 @@ class Chef
           scrubbed_value = value.dup
           if needs_checksum?(scrubbed_value)
             data_io = StringIO.new(scrubbed_value[:data].to_s)
-            scrubbed_value[:data] = Chef::Digester.instance.generate_md5_checksum(data_io)
+            scrubbed_value[:data] = Chef::Digester.instance.generate_checksum(data_io)
           end
           scrubbed << scrubbed_value
         end
diff --git a/lib/chef/resource/remote_directory.rb b/lib/chef/resource/remote_directory.rb
index d4108da..600ee51 100644
--- a/lib/chef/resource/remote_directory.rb
+++ b/lib/chef/resource/remote_directory.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,28 +17,27 @@
 # limitations under the License.
 #
 
-require 'chef/resource/directory'
-require 'chef/provider/remote_directory'
-require 'chef/mixin/securable'
+require "chef/resource/directory"
+require "chef/provider/remote_directory"
+require "chef/mixin/securable"
 
 class Chef
   class Resource
     class RemoteDirectory < Chef::Resource::Directory
       include Chef::Mixin::Securable
 
-      provides :remote_directory
-
       identity_attr :path
 
       state_attrs :files_owner, :files_group, :files_mode
 
-      def initialize(name, run_context=nil)
+      default_action :create
+      allowed_actions :create, :create_if_missing, :delete
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :remote_directory
         @path = name
         @source = ::File.basename(name)
         @delete = false
-        @action = :create
         @recursive = true
         @purge = false
         @files_backup = 5
@@ -46,7 +45,6 @@ class Chef
         @files_group = nil
         @files_mode = 0644 unless Chef::Platform.windows?
         @overwrite = true
-        @allowed_actions.push(:create, :create_if_missing, :delete)
         @cookbook = nil
       end
 
@@ -55,68 +53,67 @@ class Chef
         rights_attribute(:files_rights)
       end
 
-
-      def source(args=nil)
+      def source(args = nil)
         set_or_return(
           :source,
           args,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def files_backup(arg=nil)
+      def files_backup(arg = nil)
         set_or_return(
           :files_backup,
           arg,
-          :kind_of => [ Integer, FalseClass ]
+          :kind_of => [ Integer, FalseClass ],
         )
       end
 
-      def purge(arg=nil)
+      def purge(arg = nil)
         set_or_return(
           :purge,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def files_group(arg=nil)
+      def files_group(arg = nil)
         set_or_return(
           :files_group,
           arg,
-          :regex => Chef::Config[:group_valid_regex]
+          :regex => Chef::Config[:group_valid_regex],
         )
       end
 
-      def files_mode(arg=nil)
+      def files_mode(arg = nil)
         set_or_return(
           :files_mode,
           arg,
-          :regex => /^\d{3,4}$/
+          :regex => /^\d{3,4}$/,
         )
       end
 
-      def files_owner(arg=nil)
+      def files_owner(arg = nil)
         set_or_return(
           :files_owner,
           arg,
-          :regex => Chef::Config[:user_valid_regex]
+          :regex => Chef::Config[:user_valid_regex],
         )
       end
 
-      def overwrite(arg=nil)
+      def overwrite(arg = nil)
         set_or_return(
           :overwrite,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def cookbook(args=nil)
+      def cookbook(args = nil)
         set_or_return(
           :cookbook,
           args,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index e56f699..36f1c61 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,22 +17,19 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'chef/resource/file'
-require 'chef/provider/remote_file'
-require 'chef/mixin/securable'
+require "uri"
+require "chef/resource/file"
+require "chef/provider/remote_file"
+require "chef/mixin/securable"
+require "chef/mixin/uris"
 
 class Chef
   class Resource
     class RemoteFile < Chef::Resource::File
       include Chef::Mixin::Securable
 
-      provides :remote_file
-
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :remote_file
-        @action = "create"
         @source = []
         @use_etag = true
         @use_last_modified = true
@@ -55,7 +52,7 @@ class Chef
                             arg,
                             { :callbacks => {
                                 :validate_source => method(:validate_source)
-                              }})
+                              } })
         if ret.is_a? String
           Array(ret)
         else
@@ -68,18 +65,18 @@ class Chef
           nil
         elsif args[0].is_a?(Chef::DelayedEvaluator) && args.count == 1
           args[0]
-        elsif args.any? {|a| a.is_a?(Chef::DelayedEvaluator)} && args.count > 1
+        elsif args.any? { |a| a.is_a?(Chef::DelayedEvaluator) } && args.count > 1
           raise Exceptions::InvalidRemoteFileURI, "Only 1 source argument allowed when using a lazy evaluator"
         else
           Array(args).flatten
         end
       end
 
-      def checksum(args=nil)
+      def checksum(args = nil)
         set_or_return(
           :checksum,
           args,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
@@ -91,42 +88,44 @@ class Chef
         use_last_modified(true_or_false)
       end
 
-      def use_etag(args=nil)
+      def use_etag(args = nil)
         set_or_return(
           :use_etag,
           args,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
       alias :use_etags :use_etag
 
-      def use_last_modified(args=nil)
+      def use_last_modified(args = nil)
         set_or_return(
           :use_last_modified,
           args,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def ftp_active_mode(args=nil)
+      def ftp_active_mode(args = nil)
         set_or_return(
           :ftp_active_mode,
           args,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def headers(args=nil)
+      def headers(args = nil)
         set_or_return(
           :headers,
           args,
-          :kind_of => Hash
+          :kind_of => Hash,
         )
       end
 
       private
 
+      include Chef::Mixin::Uris
+
       def validate_source(source)
         source = Array(source).flatten
         raise ArgumentError, "#{resource_name} has an empty source" if source.empty?
@@ -140,7 +139,7 @@ class Chef
       end
 
       def absolute_uri?(source)
-        source.kind_of?(String) and URI.parse(source).absolute?
+        Chef::Provider::RemoteFile::Fetcher.network_share?(source) or (source.kind_of?(String) and as_uri(source).absolute?)
       rescue URI::InvalidURIError
         false
       end
diff --git a/lib/chef/resource/resource_notification.rb b/lib/chef/resource/resource_notification.rb
index a27ed96..ee90064 100644
--- a/lib/chef/resource/resource_notification.rb
+++ b/lib/chef/resource/resource_notification.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,19 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
-    class Notification < Struct.new(:resource, :action, :notifying_resource)
+    class Notification
+
+      attr_accessor :resource, :action, :notifying_resource
+
+      def initialize(resource, action, notifying_resource)
+        @resource = resource
+        @action = action
+        @notifying_resource = notifying_resource
+      end
 
       def duplicates?(other_notification)
         unless other_notification.respond_to?(:resource) && other_notification.respond_to?(:action)
@@ -104,6 +112,11 @@ is defined near #{resource.source_line}
         raise err
       end
 
+      def ==(other)
+        return false unless other.is_a?(self.class)
+        other.resource == resource && other.action == action && other.notifying_resource == notifying_resource
+      end
+
     end
   end
 end
diff --git a/lib/chef/resource/route.rb b/lib/chef/resource/route.rb
index 942905d..bbfbada 100644
--- a/lib/chef/resource/route.rb
+++ b/lib/chef/resource/route.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,22 +17,21 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class Route < Chef::Resource
-
       identity_attr :target
 
       state_attrs :netmask, :gateway
 
-      def initialize(name, run_context=nil)
+      default_action :add
+      allowed_actions :add, :delete
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :route
         @target = name
-        @action = [:add]
-        @allowed_actions.push(:add, :delete)
         @netmask = nil
         @gateway = nil
         @metric = nil
@@ -45,96 +44,94 @@ class Chef
         @domain = nil
       end
 
-      def networking(arg=nil)
+      def networking(arg = nil)
         set_or_return(
           :networking,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def networking_ipv6(arg=nil)
+      def networking_ipv6(arg = nil)
         set_or_return(
           :networking_ipv6,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def hostname(arg=nil)
+      def hostname(arg = nil)
         set_or_return(
           :hostname,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def domainname(arg=nil)
+      def domainname(arg = nil)
         set_or_return(
           :domainname,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def domain(arg=nil)
+      def domain(arg = nil)
         set_or_return(
           :domain,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def target(arg=nil)
+      def target(arg = nil)
         set_or_return(
           :target,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def netmask(arg=nil)
+      def netmask(arg = nil)
         set_or_return(
           :netmask,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def gateway(arg=nil)
+      def gateway(arg = nil)
         set_or_return(
           :gateway,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def metric(arg=nil)
+      def metric(arg = nil)
         set_or_return(
           :metric,
           arg,
-          :kind_of => Integer
+          :kind_of => Integer,
         )
       end
 
-      def device(arg=nil)
+      def device(arg = nil)
         set_or_return(
           :device,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def route_type(arg=nil)
+      def route_type(arg = nil)
         real_arg = arg.kind_of?(String) ? arg.to_sym : arg
         set_or_return(
           :route_type,
           real_arg,
-          :equal_to => [ :host, :net ]
+          :equal_to => [ :host, :net ],
         )
       end
     end
   end
 end
-
-
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index f00121d..fdb5913 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/rpm'
+require "chef/resource/package"
+require "chef/provider/package/rpm"
 
 class Chef
   class Resource
     class RpmPackage < Chef::Resource::Package
-
+      resource_name :rpm_package
       provides :rpm_package, os: [ "linux", "aix" ]
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :rpm_package
-        @allow_downgrade = false
-      end
-
-      def allow_downgrade(arg=nil)
-        set_or_return(
-          :allow_downgrade,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
+      property :allow_downgrade, [ true, false ], default: false, desired_state: false
 
     end
   end
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 2b2aa02..91805a1 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,16 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/provider/script'
+require "chef/resource/script"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Ruby < Chef::Resource::Script
-
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :ruby
         @interpreter = "ruby"
       end
-
     end
   end
 end
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index a9cbf23..7bb433b 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,19 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/provider/ruby_block'
+require "chef/resource"
+require "chef/provider/ruby_block"
 
 class Chef
   class Resource
     class RubyBlock < Chef::Resource
+      default_action :run
+      allowed_actions :create, :run
 
       identity_attr :block_name
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :ruby_block
-        @action = "run"
-        @allowed_actions << :create << :run
         @block_name = name
       end
 
@@ -42,11 +41,11 @@ class Chef
         end
       end
 
-      def block_name(arg=nil)
+      def block_name(arg = nil)
         set_or_return(
           :block_name,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
     end
diff --git a/lib/chef/resource/scm.rb b/lib/chef/resource/scm.rb
index 87c217b..4ba31cd 100644
--- a/lib/chef/resource/scm.rb
+++ b/lib/chef/resource/scm.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,99 +16,97 @@
 # limitations under the License.
 #
 
-
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class Scm < Chef::Resource
-
       identity_attr :destination
 
       state_attrs :revision
 
-      def initialize(name, run_context=nil)
+      default_action :sync
+      allowed_actions :checkout, :export, :sync, :diff, :log
+
+      def initialize(name, run_context = nil)
         super
         @destination = name
-        @resource_name = :scm
         @enable_submodules = false
         @enable_checkout = true
         @revision = "HEAD"
         @remote = "origin"
         @ssh_wrapper = nil
         @depth = nil
-        @allowed_actions.push(:checkout, :export, :sync, :diff, :log)
-        @action = [:sync]
         @checkout_branch = "deploy"
         @environment = nil
       end
 
-      def destination(arg=nil)
+      def destination(arg = nil)
         set_or_return(
           :destination,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def repository(arg=nil)
+      def repository(arg = nil)
         set_or_return(
           :repository,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def revision(arg=nil)
+      def revision(arg = nil)
         set_or_return(
           :revision,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def user(arg=nil)
+      def user(arg = nil)
         set_or_return(
           :user,
           arg,
-          :kind_of => [String, Integer]
+          :kind_of => [String, Integer],
         )
       end
 
-      def group(arg=nil)
+      def group(arg = nil)
         set_or_return(
           :group,
           arg,
-          :kind_of => [String, Integer]
+          :kind_of => [String, Integer],
         )
       end
 
-      def svn_username(arg=nil)
+      def svn_username(arg = nil)
         set_or_return(
           :svn_username,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def svn_password(arg=nil)
+      def svn_password(arg = nil)
         set_or_return(
           :svn_password,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def svn_arguments(arg=nil)
+      def svn_arguments(arg = nil)
         @svn_arguments, arg = nil, nil if arg == false
         set_or_return(
           :svn_arguments,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def svn_info_args(arg=nil)
+      def svn_info_args(arg = nil)
         @svn_info_args, arg = nil, nil if arg == false
         set_or_return(
           :svn_info_args,
@@ -117,67 +115,67 @@ class Chef
       end
 
       # Capistrano and git-deploy use ``shallow clone''
-      def depth(arg=nil)
+      def depth(arg = nil)
         set_or_return(
           :depth,
           arg,
-          :kind_of => Integer
+          :kind_of => Integer,
         )
       end
 
-      def enable_submodules(arg=nil)
+      def enable_submodules(arg = nil)
         set_or_return(
           :enable_submodules,
           arg,
-          :kind_of => [TrueClass, FalseClass]
+          :kind_of => [TrueClass, FalseClass],
         )
       end
 
-      def enable_checkout(arg=nil)
+      def enable_checkout(arg = nil)
         set_or_return(
           :enable_checkout,
           arg,
-          :kind_of => [TrueClass, FalseClass]
+          :kind_of => [TrueClass, FalseClass],
         )
       end
 
-      def remote(arg=nil)
+      def remote(arg = nil)
         set_or_return(
           :remote,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def ssh_wrapper(arg=nil)
+      def ssh_wrapper(arg = nil)
         set_or_return(
           :ssh_wrapper,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def timeout(arg=nil)
+      def timeout(arg = nil)
         set_or_return(
           :timeout,
           arg,
-          :kind_of => Integer
+          :kind_of => Integer,
         )
       end
 
-      def checkout_branch(arg=nil)
+      def checkout_branch(arg = nil)
         set_or_return(
           :checkout_branch,
           arg,
-          :kind_of => String
+          :kind_of => String,
         )
       end
 
-      def environment(arg=nil)
+      def environment(arg = nil)
         set_or_return(
           :environment,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index fd0fd5a..d80effb 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,17 @@
 # limitations under the License.
 #
 
-require 'chef/resource/execute'
-require 'chef/provider/script'
+require "chef/resource/execute"
+require "chef/provider/script"
 
 class Chef
   class Resource
     class Script < Chef::Resource::Execute
-
       # Chef-13: go back to using :name as the identity attr
       identity_attr :command
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :script
         # Chef-13: the command variable should be initialized to nil
         @command = name
         @code = nil
@@ -38,36 +36,36 @@ class Chef
         @default_guard_interpreter = :default
       end
 
-      def command(arg=nil)
+      def command(arg = nil)
         unless arg.nil?
           # Chef-13: change this to raise if the user is trying to set a value here
           Chef::Log.warn "Specifying command attribute on a script resource is a coding error, use the 'code' attribute, or the execute resource"
-          Chef::Log.warn "This attribute is deprecated and must be fixed or this code will fail on Chef-13"
+          Chef::Log.warn "This attribute is deprecated and must be fixed or this code will fail on Chef 13"
         end
         super
       end
 
-      def code(arg=nil)
+      def code(arg = nil)
         set_or_return(
           :code,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def interpreter(arg=nil)
+      def interpreter(arg = nil)
         set_or_return(
           :interpreter,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def flags(arg=nil)
+      def flags(arg = nil)
         set_or_return(
           :flags,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 36df7c8..5288e1b 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -1,7 +1,7 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,20 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class Service < Chef::Resource
-
       identity_attr :service_name
 
       state_attrs :enabled, :running
 
-      def initialize(name, run_context=nil)
+      default_action :nothing
+      allowed_actions :enable, :disable, :start, :stop, :restart, :reload
+
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :service
         @service_name = name
         @enabled = nil
         @running = nil
@@ -43,69 +44,68 @@ class Chef
         @init_command = nil
         @priority = nil
         @timeout = nil
-        @action = "nothing"
-        @supports = { :restart => false, :reload => false, :status => false }
-        @allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
+        @run_levels = nil
+        @supports = { :restart => nil, :reload => nil, :status => nil }
       end
 
-      def service_name(arg=nil)
+      def service_name(arg = nil)
         set_or_return(
           :service_name,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # regex for match against ps -ef when !supports[:has_status] && status == nil
-      def pattern(arg=nil)
+      def pattern(arg = nil)
         set_or_return(
           :pattern,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # command to call to start service
-      def start_command(arg=nil)
+      def start_command(arg = nil)
         set_or_return(
           :start_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # command to call to stop service
-      def stop_command(arg=nil)
+      def stop_command(arg = nil)
         set_or_return(
           :stop_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # command to call to get status of service
-      def status_command(arg=nil)
+      def status_command(arg = nil)
         set_or_return(
           :status_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # command to call to restart service
-      def restart_command(arg=nil)
+      def restart_command(arg = nil)
         set_or_return(
           :restart_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def reload_command(arg=nil)
+      def reload_command(arg = nil)
         set_or_return(
           :reload_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
@@ -114,29 +114,29 @@ class Chef
       # non-standard configurations setting this value will save having to
       # specify overrides for the start_command, stop_command and
       # restart_command attributes.
-      def init_command(arg=nil)
+      def init_command(arg = nil)
         set_or_return(
           :init_command,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
       # if the service is enabled or not
-      def enabled(arg=nil)
+      def enabled(arg = nil)
         set_or_return(
           :enabled,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
       # if the service is running or not
-      def running(arg=nil)
+      def running(arg = nil)
         set_or_return(
           :running,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
@@ -150,32 +150,39 @@ class Chef
       #   runlevel 2, stopped in 3 with priority 55 and no symlinks or
       #   similar for other runlevels
       #
-      def priority(arg=nil)
+      def priority(arg = nil)
         set_or_return(
           :priority,
           arg,
-          :kind_of => [ Integer, String, Hash ]
+          :kind_of => [ Integer, String, Hash ],
         )
       end
 
       # timeout only applies to the windows service manager
-      def timeout(arg=nil)
+      def timeout(arg = nil)
         set_or_return(
           :timeout,
           arg,
-          :kind_of => Integer
+          :kind_of => Integer,
         )
       end
 
-      def parameters(arg=nil)
+      def parameters(arg = nil)
         set_or_return(
           :parameters,
           arg,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
-      def supports(args={})
+      def run_levels(arg = nil)
+        set_or_return(
+          :run_levels,
+          arg,
+          :kind_of => [ Array ] )
+      end
+
+      def supports(args = {})
         if args.is_a? Array
           args.each { |arg| @supports[arg] = true }
         elsif args.any?
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index 99b3b95..87173cc 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/smartos'
+require "chef/resource/package"
+require "chef/provider/package/smartos"
 
 class Chef
   class Resource
     class SmartosPackage < Chef::Resource::Package
-
-      provides :smartos_package
+      resource_name :smartos_package
       provides :package, os: "solaris2", platform_family: "smartos"
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :smartos_package
-      end
-
     end
   end
 end
-
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index 94be469..d0f8c14 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
 # Author:: Prabhu Das (<prabhu.das at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,27 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/solaris'
+require "chef/resource/package"
+require "chef/provider/package/solaris"
 
 class Chef
   class Resource
     class SolarisPackage < Chef::Resource::Package
-
-      provides :solaris_package
+      resource_name :solaris_package
       provides :package, os: "solaris2", platform_family: "nexentacore"
-      provides :package, os: "solaris2", platform_family: "solaris2" do |node|
-        # on >= Solaris 11 we default to IPS packages instead
-        node[:platform_version].to_f <= 5.10
-      end
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :solaris_package
-      end
-
+      provides :package, os: "solaris2", platform_family: "solaris2", platform_version: "<= 5.10"
     end
   end
 end
-
-
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index 3afbe0b..9966614 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,19 +22,23 @@ require "chef/resource/scm"
 class Chef
   class Resource
     class Subversion < Chef::Resource::Scm
+      allowed_actions :force_export
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @svn_arguments = '--no-auth-cache'
-        @svn_info_args = '--no-auth-cache'
-        @resource_name = :subversion
-        allowed_actions << :force_export
+        @svn_arguments = "--no-auth-cache"
+        @svn_info_args = "--no-auth-cache"
+        @svn_binary = nil
       end
 
       # Override exception to strip password if any, so it won't appear in logs and different Chef notifications
       def custom_exception_message(e)
         "#{self} (#{defined_at}) had an error: #{e.class.name}: #{svn_password ? e.message.gsub(svn_password, "[hidden_password]") : e.message}"
       end
+
+      def svn_binary(arg = nil)
+        set_or_return(:svn_binary, arg, :kind_of => [String])
+      end
     end
   end
 end
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index 67a9e6a..1570af2 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,24 +18,20 @@
 # limitations under the License.
 #
 
-require 'chef/resource/file'
-require 'chef/provider/template'
-require 'chef/mixin/securable'
+require "chef/resource/file"
+require "chef/provider/template"
+require "chef/mixin/securable"
 
 class Chef
   class Resource
     class Template < Chef::Resource::File
       include Chef::Mixin::Securable
 
-      provides :template
-
       attr_reader :inline_helper_blocks
       attr_reader :inline_helper_modules
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :template
-        @action = "create"
         @source = "#{::File.basename(name)}.erb"
         @cookbook = nil
         @local = false
@@ -45,35 +41,35 @@ class Chef
         @helper_modules = []
       end
 
-      def source(file=nil)
+      def source(file = nil)
         set_or_return(
           :source,
           file,
-          :kind_of => [ String, Array ]
+          :kind_of => [ String, Array ],
         )
       end
 
-      def variables(args=nil)
+      def variables(args = nil)
         set_or_return(
           :variables,
           args,
-          :kind_of => [ Hash ]
+          :kind_of => [ Hash ],
         )
       end
 
-      def cookbook(args=nil)
+      def cookbook(args = nil)
         set_or_return(
           :cookbook,
           args,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def local(args=nil)
+      def local(args = nil)
         set_or_return(
           :local,
           args,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
@@ -164,7 +160,7 @@ class Chef
       # And in the template resource:
       #   helpers(MyTemplateHelper)
       # The template code in the above example will work unmodified.
-      def helpers(module_name=nil,&block)
+      def helpers(module_name = nil, &block)
         if block_given? and !module_name.nil?
           raise Exceptions::ValidationFailed,
             "Passing both a module and block to #helpers is not supported. Call #helpers multiple times instead"
@@ -175,8 +171,8 @@ class Chef
         elsif module_name.nil?
           raise Exceptions::ValidationFailed,
             "#helpers requires either a module name or inline module code as a block.\n" +
-            "e.g.: helpers do; helper_code; end;\n" +
-            "OR: helpers(MyHelpersModule)"
+              "e.g.: helpers do; helper_code; end;\n" +
+              "OR: helpers(MyHelpersModule)"
         else
           raise Exceptions::ValidationFailed,
             "Argument to #helpers must be a module. You gave #{module_name.inspect} (#{module_name.class})"
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index b2109db..1d6b07a 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,10 +21,6 @@ class Chef
     # Convenience class for using the deploy resource with the timestamped
     # deployment strategy (provider)
     class TimestampedDeploy < Chef::Resource::Deploy
-      provides :timestamped_deploy
-      def initialize(*args, &block)
-        super(*args, &block)
-      end
     end
   end
 end
diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb
index 7d2ec25..5aa94ae 100644
--- a/lib/chef/resource/user.rb
+++ b/lib/chef/resource/user.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,20 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
+require "chef/resource"
 
 class Chef
   class Resource
     class User < Chef::Resource
-
       identity_attr :username
 
       state_attrs :uid, :gid, :home
 
-      provides :user
+      default_action :create
+      allowed_actions :create, :remove, :modify, :manage, :lock, :unlock
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :user
         @username = name
         @comment = nil
         @uid = nil
@@ -42,119 +41,117 @@ class Chef
         @manage_home = false
         @force = false
         @non_unique = false
-        @action = :create
         @supports = {
           :manage_home => false,
-          :non_unique => false
+          :non_unique => false,
         }
         @iterations = 27855
         @salt = nil
-        @allowed_actions.push(:create, :remove, :modify, :manage, :lock, :unlock)
       end
 
-      def username(arg=nil)
+      def username(arg = nil)
         set_or_return(
           :username,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def comment(arg=nil)
+      def comment(arg = nil)
         set_or_return(
           :comment,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def uid(arg=nil)
+      def uid(arg = nil)
         set_or_return(
           :uid,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
-      def gid(arg=nil)
+      def gid(arg = nil)
         set_or_return(
           :gid,
           arg,
-          :kind_of => [ String, Integer ]
+          :kind_of => [ String, Integer ],
         )
       end
 
       alias_method :group, :gid
 
-      def home(arg=nil)
+      def home(arg = nil)
         set_or_return(
           :home,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def shell(arg=nil)
+      def shell(arg = nil)
         set_or_return(
           :shell,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def password(arg=nil)
+      def password(arg = nil)
         set_or_return(
           :password,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def salt(arg=nil)
+      def salt(arg = nil)
         set_or_return(
           :salt,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def iterations(arg=nil)
+      def iterations(arg = nil)
         set_or_return(
           :iterations,
           arg,
-          :kind_of => [ Integer ]
+          :kind_of => [ Integer ],
         )
       end
 
-      def system(arg=nil)
+      def system(arg = nil)
         set_or_return(
           :system,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def manage_home(arg=nil)
+      def manage_home(arg = nil)
         set_or_return(
           :manage_home,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def force(arg=nil)
+      def force(arg = nil)
         set_or_return(
           :force,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
-      def non_unique(arg=nil)
+      def non_unique(arg = nil)
         set_or_return(
           :non_unique,
           arg,
-          :kind_of => [ TrueClass, FalseClass ]
+          :kind_of => [ TrueClass, FalseClass ],
         )
       end
 
diff --git a/lib/chef/resource/whyrun_safe_ruby_block.rb b/lib/chef/resource/whyrun_safe_ruby_block.rb
index 6fa5383..db11ba3 100644
--- a/lib/chef/resource/whyrun_safe_ruby_block.rb
+++ b/lib/chef/resource/whyrun_safe_ruby_block.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Phil Dibowitz (<phild at fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,6 @@
 class Chef
   class Resource
     class WhyrunSafeRubyBlock < Chef::Resource::RubyBlock
-
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :whyrun_safe_ruby_block
-      end
-
     end
   end
 end
diff --git a/lib/chef/resource/windows_package.rb b/lib/chef/resource/windows_package.rb
index 16cfcf8..0e8dd39 100644
--- a/lib/chef/resource/windows_package.rb
+++ b/lib/chef/resource/windows_package.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,63 +16,40 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/windows'
-require 'chef/win32/error' if RUBY_PLATFORM =~ /mswin|mingw|windows/
+require "chef/mixin/uris"
+require "chef/resource/package"
+require "chef/provider/package/windows"
+require "chef/win32/error" if RUBY_PLATFORM =~ /mswin|mingw|windows/
 
 class Chef
   class Resource
     class WindowsPackage < Chef::Resource::Package
+      include Chef::Mixin::Uris
 
-      provides :package, os: "windows"
+      resource_name :windows_package
       provides :windows_package, os: "windows"
+      provides :package, os: "windows"
 
-      def initialize(name, run_context=nil)
-        super
-        @allowed_actions.push(:install, :remove)
-        @resource_name = :windows_package
-        @source ||= source(@package_name)
-
-        # Unique to this resource
-        @installer_type = nil
-        @timeout = 600
-        # In the past we accepted return code 127 for an unknown reason and 42 because of a bug
-        @returns = [ 0 ]
-      end
-
-      def installer_type(arg=nil)
-        set_or_return(
-          :installer_type,
-          arg,
-          :kind_of => [ Symbol ]
-        )
-      end
-
-      def timeout(arg=nil)
-        set_or_return(
-          :timeout,
-          arg,
-          :kind_of => [ String, Integer ]
-        )
-      end
+      allowed_actions :install, :remove
 
-      def returns(arg=nil)
-        set_or_return(
-          :returns,
-          arg,
-          :kind_of => [ String, Integer, Array ]
-        )
+      def initialize(name, run_context = nil)
+        super
+        @source ||= source(@package_name) if @package_name.downcase.end_with?(".msi")
       end
 
-      def source(arg=nil)
-        if arg == nil && self.instance_variable_defined?(:@source) == true
-          @source
-        else
-          raise ArgumentError, "Bad type for WindowsPackage resource, use a String" unless arg.is_a?(String)
-          Chef::Log.debug("#{package_name}: sanitizing source path '#{arg}'")
-          @source = ::File.absolute_path(arg).gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR)
-        end
-      end
+      # Unique to this resource
+      property :installer_type, Symbol
+      property :timeout, [ String, Integer ], default: 600
+      # In the past we accepted return code 127 for an unknown reason and 42 because of a bug
+      property :returns, [ String, Integer, Array ], default: [ 0 ], desired_state: false
+      property :source, String,
+                coerce: (proc do |s|
+                  unless s.nil?
+                    uri_scheme?(s) ? s : Chef::Util::PathHelper.canonical_path(s, false)
+                  end
+                end)
+      property :checksum, String, desired_state: false
+      property :remote_file_attributes, Hash, desired_state: false
     end
   end
 end
diff --git a/lib/chef/resource/windows_script.rb b/lib/chef/resource/windows_script.rb
index 6b0827b..44f1d8d 100644
--- a/lib/chef/resource/windows_script.rb
+++ b/lib/chef/resource/windows_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/resource/script'
-require 'chef/mixin/windows_architecture_helper'
+require "chef/platform/query_helpers"
+require "chef/resource/script"
+require "chef/mixin/windows_architecture_helper"
 
 class Chef
   class Resource
     class WindowsScript < Chef::Resource::Script
+      # This is an abstract resource meant to be subclasses; thus no 'provides'
 
       set_guard_inherited_attributes(:architecture)
 
@@ -30,29 +32,32 @@ class Chef
       def initialize(name, run_context, resource_name, interpreter_command)
         super(name, run_context)
         @interpreter = interpreter_command
-        @resource_name = resource_name
-        @default_guard_interpreter = resource_name
+        @resource_name = resource_name if resource_name
+        @default_guard_interpreter = self.resource_name
       end
 
       include Chef::Mixin::WindowsArchitectureHelper
 
       public
 
-      def architecture(arg=nil)
+      def architecture(arg = nil)
         assert_architecture_compatible!(arg) if ! arg.nil?
         result = set_or_return(
           :architecture,
           arg,
-          :kind_of => Symbol
+          :kind_of => Symbol,
         )
       end
 
       protected
 
       def assert_architecture_compatible!(desired_architecture)
-        if ! node_supports_windows_architecture?(node, desired_architecture)
+        if desired_architecture == :i386 && Chef::Platform.windows_nano_server?
           raise Chef::Exceptions::Win32ArchitectureIncorrect,
-          "cannot execute script with requested architecture '#{desired_architecture.to_s}' on a system with architecture '#{node_windows_architecture(node)}'"
+            "cannot execute script with requested architecture 'i386' on Windows Nano Server"
+        elsif ! node_supports_windows_architecture?(node, desired_architecture)
+          raise Chef::Exceptions::Win32ArchitectureIncorrect,
+            "cannot execute script with requested architecture '#{desired_architecture}' on a system with architecture '#{node_windows_architecture(node)}'"
         end
       end
     end
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index 8090adc..635edbb 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/resource/service'
+require "chef/resource/service"
 
 class Chef
   class Resource
@@ -25,45 +25,45 @@ class Chef
       # Until #1773 is resolved, you need to manually specify the windows_service resource
       # to use action :configure_startup and attribute startup_type
 
-      provides :service, os: "windows"
       provides :windows_service, os: "windows"
+      provides :service, os: "windows"
+
+      allowed_actions :configure_startup
 
       identity_attr :service_name
 
       state_attrs :enabled, :running
 
-      def initialize(name, run_context=nil)
+      def initialize(name, run_context = nil)
         super
-        @resource_name = :windows_service
-        @allowed_actions.push(:configure_startup)
         @startup_type = :automatic
         @run_as_user = ""
         @run_as_password = ""
       end
 
-      def startup_type(arg=nil)
+      def startup_type(arg = nil)
         # Set-Service arguments are automatic and manual
         # Win32::Service returns 'auto start' or 'demand start' respectively, which the provider currently uses
         set_or_return(
           :startup_type,
           arg,
-          :equal_to => [ :automatic, :manual, :disabled ]
+          :equal_to => [ :automatic, :manual, :disabled ],
         )
       end
 
-      def run_as_user(arg=nil)
+      def run_as_user(arg = nil)
         set_or_return(
           :run_as_user,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
 
-      def run_as_password(arg=nil)
+      def run_as_password(arg = nil)
         set_or_return(
           :run_as_password,
           arg,
-          :kind_of => [ String ]
+          :kind_of => [ String ],
         )
       end
     end
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index 8fbca9b..f2dd772 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,49 +16,31 @@
 # limitations under the License.
 #
 
-require 'chef/resource/package'
-require 'chef/provider/package/yum'
+require "chef/resource/package"
+require "chef/provider/package/yum"
 
 class Chef
   class Resource
     class YumPackage < Chef::Resource::Package
-
-      provides :yum_package
+      resource_name :yum_package
       provides :package, os: "linux", platform_family: [ "rhel", "fedora" ]
 
-      def initialize(name, run_context=nil)
-        super
-        @resource_name = :yum_package
-        @flush_cache = { :before => false, :after => false }
-        @allow_downgrade = false
-      end
-
       # Install a specific arch
-      def arch(arg=nil)
-        set_or_return(
-          :arch,
-          arg,
-          :kind_of => [ String ]
-        )
-      end
-
-      def flush_cache(args={})
-        if args.is_a? Array
-          args.each { |arg| @flush_cache[arg] = true }
-        elsif args.any?
-          @flush_cache = args
+      property :arch, [ String, Array ]
+      property :flush_cache, Hash, default: { before: false, after: false }, coerce: proc { |v|
+        # TODO these append rather than set. This is probably wrong behavior, but we're preserving it until we know
+        if v.is_a?(Array)
+          v.each { |arg| flush_cache[arg] = true }
+          flush_cache
+        elsif v.any?
+          v
         else
-          @flush_cache
+          # TODO calling flush_cache({}) does a get instead of a set. This is probably wrong behavior, but we're preserving it until we know
+          flush_cache
         end
-      end
-
-      def allow_downgrade(arg=nil)
-        set_or_return(
-          :allow_downgrade,
-          arg,
-          :kind_of => [ TrueClass, FalseClass ]
-        )
-      end
+      }
+      property :allow_downgrade, [ true, false ], default: false
+      property :yum_binary, String
 
     end
   end
diff --git a/lib/chef/resource/zypper_package.rb b/lib/chef/resource/zypper_package.rb
new file mode 100644
index 0000000..f9e3eef
--- /dev/null
+++ b/lib/chef/resource/zypper_package.rb
@@ -0,0 +1,28 @@
+#
+# Author:: Joe Williams (<joe at joetify.com>)
+# Copyright:: Copyright 2009-2016, Joe Williams
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/resource/package"
+
+class Chef
+  class Resource
+    class ZypperPackage < Chef::Resource::Package
+      resource_name :zypper_package
+      provides :package, platform_family: "suse"
+    end
+  end
+end
diff --git a/lib/chef/resource_builder.rb b/lib/chef/resource_builder.rb
index bb0962d..f3ca2e9 100644
--- a/lib/chef/resource_builder.rb
+++ b/lib/chef/resource_builder.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,6 +46,9 @@ class Chef
       raise ArgumentError, "You must supply a name when declaring a #{type} resource" if name.nil?
 
       @resource = resource_class.new(name, run_context)
+      if resource.resource_name.nil?
+        raise Chef::Exceptions::InvalidResourceSpecification, "#{resource}.resource_name is `nil`!  Did you forget to put `provides :blah` or `resource_name :blah` in your resource class?"
+      end
       resource.source_line = created_at
       resource.declared_type = type
 
@@ -67,7 +70,14 @@ class Chef
       resource.params = params
 
       # Evaluate resource attribute DSL
-      resource.instance_eval(&block) if block_given?
+      if block_given?
+        resource.resource_initializing = true
+        begin
+          resource.instance_eval(&block)
+        ensure
+          resource.resource_initializing = false
+        end
+      end
 
       # emit a cloned resource warning if it is warranted
       if prior_resource
@@ -127,7 +137,7 @@ class Chef
       @prior_resource ||=
         begin
           key = "#{type}[#{name}]"
-          prior_resource = run_context.resource_collection.lookup(key)
+          run_context.resource_collection.lookup(key)
         rescue Chef::Exceptions::ResourceNotFound
           nil
         end
@@ -135,3 +145,7 @@ class Chef
 
   end
 end
+
+require "chef/exceptions"
+require "chef/resource"
+require "chef/log"
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index 4fd6fca..293a999 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'chef/resource_collection/resource_set'
-require 'chef/resource_collection/resource_list'
-require 'chef/resource_collection/resource_collection_serialization'
-require 'chef/log'
-require 'forwardable'
+require "chef/resource_collection/resource_set"
+require "chef/resource_collection/resource_list"
+require "chef/resource_collection/resource_collection_serialization"
+require "chef/log"
+require "forwardable"
 
 ##
 # ResourceCollection currently handles two tasks:
@@ -45,7 +45,7 @@ class Chef
     # @param instance_name [String] If known, the recource name as used in the recipe, IE `vim` in `package 'vim'`
     # This method is meant to be the 1 insert method necessary in the future.  It should support all known use cases
     #   for writing into the ResourceCollection.
-    def insert(resource, opts={})
+    def insert(resource, opts = {})
       resource_type ||= opts[:resource_type] # Would rather use Ruby 2.x syntax, but oh well
       instance_name ||= opts[:instance_name]
       resource_list.insert(resource)
@@ -78,8 +78,8 @@ class Chef
     # Read-only methods are simple to delegate - doing that below
 
     resource_list_methods = Enumerable.instance_methods +
-        [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] -
-        [:find] # find needs to run on the set
+                            [:iterator, :all_resources, :[], :each, :execute_each_resource, :each_index, :empty?] -
+                            [:find] # find needs to run on the set
     resource_set_methods = [:lookup, :find, :resources, :keys, :validate_lookup_spec!]
 
     def_delegators :resource_list, *resource_list_methods
diff --git a/lib/chef/resource_collection/resource_collection_serialization.rb b/lib/chef/resource_collection/resource_collection_serialization.rb
index 3651fb2..0e76296 100644
--- a/lib/chef/resource_collection/resource_collection_serialization.rb
+++ b/lib/chef/resource_collection/resource_collection_serialization.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,8 +25,8 @@ class Chef
           instance_vars[iv] = self.instance_variable_get(iv)
         end
         {
-            'json_class' => self.class.name,
-            'instance_vars' => instance_vars
+            "json_class" => self.class.name,
+            "instance_vars" => instance_vars,
         }
       end
 
@@ -41,7 +41,7 @@ class Chef
       module ClassMethods
         def json_create(o)
           collection = self.new()
-          o["instance_vars"].each do |k,v|
+          o["instance_vars"].each do |k, v|
             collection.instance_variable_set(k.to_sym, v)
           end
           collection
diff --git a/lib/chef/resource_collection/resource_list.rb b/lib/chef/resource_collection/resource_list.rb
index a26bd34..20bfc7b 100644
--- a/lib/chef/resource_collection/resource_list.rb
+++ b/lib/chef/resource_collection/resource_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/resource_collection/stepable_iterator'
-require 'chef/resource_collection/resource_collection_serialization'
-require 'forwardable'
+require "chef/resource"
+require "chef/resource_collection/stepable_iterator"
+require "chef/resource_collection/resource_collection_serialization"
+require "forwardable"
 
 # This class keeps the list of all known Resources in the order they are to be executed in.  It also keeps a pointer
 # to the most recently executed resource so we can add resources-to-execute after this point.
diff --git a/lib/chef/resource_collection/resource_set.rb b/lib/chef/resource_collection/resource_set.rb
index 1b39298..2a65335 100644
--- a/lib/chef/resource_collection/resource_set.rb
+++ b/lib/chef/resource_collection/resource_set.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/resource'
-require 'chef/resource_collection/resource_collection_serialization'
+require "chef/resource"
+require "chef/resource_collection/resource_collection_serialization"
 
 class Chef
   class ResourceCollection
@@ -40,7 +40,7 @@ class Chef
         @resources_by_key.keys
       end
 
-      def insert_as(resource, resource_type=nil, instance_name=nil)
+      def insert_as(resource, resource_type = nil, instance_name = nil)
         is_chef_resource!(resource)
         resource_type ||= resource.resource_name
         instance_name ||= resource.name
@@ -124,7 +124,7 @@ class Chef
           else
             raise Chef::Exceptions::InvalidResourceSpecification,
                   "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
-                      "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
+                    "Use a String like `resource_type[resource_name]' or a Chef::Resource object"
         end
       end
 
diff --git a/lib/chef/resource_collection/stepable_iterator.rb b/lib/chef/resource_collection/stepable_iterator.rb
index 4d5fc1f..d116576 100644
--- a/lib/chef/resource_collection/stepable_iterator.rb
+++ b/lib/chef/resource_collection/stepable_iterator.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ class Chef
       attr_accessor :collection
       attr_reader :position
 
-      def initialize(collection=[])
+      def initialize(collection = [])
         @position = 0
         @paused = false
         @collection = collection
@@ -72,11 +72,11 @@ class Chef
         @position = 0
       end
 
-      def skip_back(skips=1)
+      def skip_back(skips = 1)
         @position -= skips
       end
 
-      def skip_forward(skips=1)
+      def skip_forward(skips = 1)
         @position += skips
       end
 
diff --git a/lib/chef/resource_definition.rb b/lib/chef/resource_definition.rb
index 9d68441..aa114af 100644
--- a/lib/chef/resource_definition.rb
+++ b/lib/chef/resource_definition.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/from_file'
-require 'chef/mixin/params_validate'
+require "chef/mixin/from_file"
+require "chef/mixin/params_validate"
 
 class Chef
   class ResourceDefinition
@@ -27,14 +27,14 @@ class Chef
 
     attr_accessor :name, :params, :recipe, :node
 
-    def initialize(node=nil)
+    def initialize(node = nil)
       @name = nil
       @params = Hash.new
       @recipe = nil
       @node = node
     end
 
-    def define(resource_name, prototype_params=nil, &block)
+    def define(resource_name, prototype_params = nil, &block)
       unless resource_name.kind_of?(Symbol)
         raise ArgumentError, "You must use a symbol when defining a new resource!"
       end
@@ -50,6 +50,7 @@ class Chef
       else
         raise ArgumentError, "You must pass a block to a definition."
       end
+      Chef::DSL::Definitions.add_definition(name)
       true
     end
 
@@ -61,7 +62,7 @@ class Chef
     end
 
     def to_s
-      "#{name.to_s}"
+      "#{name}"
     end
   end
 end
diff --git a/lib/chef/resource_definition_list.rb b/lib/chef/resource_definition_list.rb
index 5501409..2275124 100644
--- a/lib/chef/resource_definition_list.rb
+++ b/lib/chef/resource_definition_list.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/from_file'
-require 'chef/resource_definition'
+require "chef/mixin/from_file"
+require "chef/resource_definition"
 
 class Chef
   class ResourceDefinitionList
@@ -29,7 +29,7 @@ class Chef
       @defines = Hash.new
     end
 
-    def define(resource_name, prototype_params=nil, &block)
+    def define(resource_name, prototype_params = nil, &block)
       @defines[resource_name] = ResourceDefinition.new
       @defines[resource_name].define(resource_name, prototype_params, &block)
       true
diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb
index 1816fc8..4135483 100644
--- a/lib/chef/resource_reporter.rb
+++ b/lib/chef/resource_reporter.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Prajakta Purohit (prajakta at opscode.com>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Prajakta Purohit (prajakta at chef.io>)
 # Auther:: Tyler Cloke (<tyler at opscode.com>)
 #
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
 # limitations under the License.
 #
 
-require 'uri'
-require 'securerandom'
-require 'chef/event_dispatch/base'
+require "uri"
+require "securerandom"
+require "chef/event_dispatch/base"
 
 class Chef
   class ResourceReporter < EventDispatch::Base
@@ -59,11 +59,11 @@ class Chef
       # attrs.
       def for_json
         as_hash = {}
-        as_hash["type"]   = new_resource.class.dsl_name
+        as_hash["type"]   = new_resource.resource_name.to_sym
         as_hash["name"]   = new_resource.name.to_s
         as_hash["id"]     = new_resource.identity.to_s
-        as_hash["after"]  = state(new_resource)
-        as_hash["before"] = current_resource ? state(current_resource) : {}
+        as_hash["after"]  = new_resource.state_for_resource_reporter
+        as_hash["before"] = current_resource ? current_resource.state_for_resource_reporter : {}
         as_hash["duration"] = (elapsed_time * 1000).to_i.to_s
         as_hash["delta"]  = new_resource.diff if new_resource.respond_to?("diff")
         as_hash["delta"]  = "" if as_hash["delta"].nil?
@@ -89,13 +89,6 @@ class Chef
       def success?
         !self.exception
       end
-
-      def state(r)
-        r.class.state_attrs.inject({}) do |state_attrs, attr_name|
-          state_attrs[attr_name] = r.send(attr_name)
-          state_attrs
-        end
-      end
     end # End class ResouceReport
 
     attr_reader :updated_resources
@@ -104,7 +97,7 @@ class Chef
     attr_reader :run_id
     attr_reader :error_descriptions
 
-    PROTOCOL_VERSION = '0.1.0'
+    PROTOCOL_VERSION = "0.1.0"
 
     def initialize(rest_client)
       if Chef::Config[:enable_reporting] && !Chef::Config[:why_run]
@@ -119,6 +112,7 @@ class Chef
       @exception = nil
       @rest_client = rest_client
       @error_descriptions = {}
+      @expanded_run_list = {}
     end
 
     def run_started(run_status)
@@ -127,8 +121,8 @@ class Chef
       if reporting_enabled?
         begin
           resource_history_url = "reports/nodes/#{node_name}/runs"
-          server_response = @rest_client.post_rest(resource_history_url, {:action => :start, :run_id => run_id,
-                                                                          :start_time => start_time.to_s}, headers)
+          server_response = @rest_client.post(resource_history_url, { :action => :start, :run_id => run_id,
+                                                                      :start_time => start_time.to_s }, headers)
         rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
           handle_error_starting_run(e, resource_history_url)
         end
@@ -220,10 +214,14 @@ class Chef
       # If we failed before we received the run_started callback, there's not much we can do
       # in terms of reporting
       if @run_status
-          post_reporting_data
+        post_reporting_data
       end
     end
 
+    def run_list_expanded(run_list_expansion)
+      @expanded_run_list = run_list_expansion
+    end
+
     def post_reporting_data
       if reporting_enabled?
         run_data = prepare_run_data
@@ -232,10 +230,9 @@ class Chef
         Chef::Log.debug run_data.inspect
         compressed_data = encode_gzip(Chef::JSONCompat.to_json(run_data))
         Chef::Log.debug("Sending compressed run data...")
-        # Since we're posting compressed data we can not directly call post_rest which expects JSON
-        reporting_url = @rest_client.create_url(resource_history_url)
+        # Since we're posting compressed data we can not directly call post which expects JSON
         begin
-          @rest_client.raw_http_request(:POST, reporting_url, headers({'Content-Encoding' => 'gzip'}), compressed_data)
+          @rest_client.raw_request(:POST, resource_history_url, headers({ "Content-Encoding" => "gzip" }), compressed_data)
         rescue StandardError => e
           if e.respond_to? :response
             Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640)
@@ -250,7 +247,7 @@ class Chef
     end
 
     def headers(additional_headers = {})
-      options = {'X-Ops-Reporting-Protocol-Version' => PROTOCOL_VERSION}
+      options = { "X-Ops-Reporting-Protocol-Version" => PROTOCOL_VERSION }
       options.merge(additional_headers)
     end
 
@@ -278,13 +275,14 @@ class Chef
       run_data["data"] = {}
       run_data["start_time"] = start_time.to_s
       run_data["end_time"] = end_time.to_s
+      run_data["expanded_run_list"] = Chef::JSONCompat.to_json(@expanded_run_list)
 
       if exception
         exception_data = {}
         exception_data["class"] = exception.inspect
         exception_data["message"] = exception.message
         exception_data["backtrace"] = Chef::JSONCompat.to_json(exception.backtrace)
-        exception_data["description"] =  @error_descriptions
+        exception_data["description"] = @error_descriptions
         run_data["data"]["exception"] = exception_data
       end
       run_data
@@ -321,7 +319,7 @@ class Chef
 
     def encode_gzip(data)
       "".tap do |out|
-        Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data }
+        Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
       end
     end
 
diff --git a/lib/chef/resource_resolver.rb b/lib/chef/resource_resolver.rb
index ff9d7ae..769272d 100644
--- a/lib/chef/resource_resolver.rb
+++ b/lib/chef/resource_resolver.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,86 +16,170 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/platform/resource_priority_map'
+require "chef/exceptions"
+require "chef/platform/resource_priority_map"
+require "chef/mixin/convert_to_class_name"
 
 class Chef
   class ResourceResolver
+    #
+    # Resolve a resource by name.
+    #
+    # @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
+    # @param node [Chef::Node] The node against which to resolve. `nil` causes
+    #   platform filters to be ignored.
+    #
+    def self.resolve(resource_name, node: nil, canonical: nil)
+      new(node, resource_name, canonical: canonical).resolve
+    end
+
+    #
+    # Resolve a list of all resources that implement the given DSL (in order of
+    # preference).
+    #
+    # @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
+    # @param node [Chef::Node] The node against which to resolve. `nil` causes
+    #   platform filters to be ignored.
+    # @param canonical [Boolean] `true` or `false` to match canonical or
+    #   non-canonical values only. `nil` to ignore canonicality.
+    #
+    def self.list(resource_name, node: nil, canonical: nil)
+      new(node, resource_name, canonical: canonical).list
+    end
+
+    include Chef::Mixin::ConvertToClassName
 
+    # @api private
     attr_reader :node
-    attr_reader :resource
+    # @api private
+    attr_reader :resource_name
+    # @api private
+    def resource
+      Chef.log_deprecation("Chef::ResourceResolver.resource deprecated.  Use resource_name instead.")
+      resource_name
+    end
+    # @api private
     attr_reader :action
-
-    def initialize(node, resource)
+    # @api private
+    attr_reader :canonical
+
+    #
+    # Create a resolver.
+    #
+    # @param node [Chef::Node] The node against which to resolve. `nil` causes
+    #   platform filters to be ignored.
+    # @param resource_name [Symbol] The resource DSL name (e.g. `:file`).
+    # @param canonical [Boolean] `true` or `false` to match canonical or
+    #   non-canonical values only. `nil` to ignore canonicality.  Default: `nil`
+    #
+    # @api private use Chef::ResourceResolver.resolve or .list instead.
+    def initialize(node, resource_name, canonical: nil)
       @node = node
-      @resource = resource
+      @resource_name = resource_name.to_sym
+      @canonical = canonical
     end
 
-    # return a deterministically sorted list of Chef::Resource subclasses
-    def resources
-      @resources ||= Chef::Resource.descendants
+    # @api private use Chef::ResourceResolver.resolve instead.
+    def resolve
+      # log this so we know what resources will work for the generic resource on the node (early cut)
+      Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
+
+      handler = prioritized_handlers.first
+
+      if handler
+        Chef::Log.debug "Resource for #{resource_name} is #{handler}"
+      else
+        Chef::Log.debug "Dynamic resource resolver FAILED to resolve a resource for #{resource_name}"
+      end
+
+      handler
     end
 
-    def resolve
-      maybe_dynamic_resource_resolution(resource) ||
-        maybe_chef_platform_lookup(resource)
+    # @api private
+    def list
+      Chef::Log.debug "Resources for generic #{resource_name} resource enabled on node include: #{prioritized_handlers}"
+      prioritized_handlers
     end
 
-    # this cut looks at if the resource can handle the resource type on the node
-    def enabled_handlers
-      @enabled_handlers ||=
-        resources.select do |klass|
-          klass.provides?(node, resource)
-        end.sort {|a,b| a.to_s <=> b.to_s }
-      @enabled_handlers
+    #
+    # Whether this DSL is provided by the given resource_class.
+    #
+    # Does NOT call provides? on the resource (it is assumed this is being
+    # called *from* provides?).
+    #
+    # @api private
+    def provided_by?(resource_class)
+      potential_handlers.include?(resource_class)
     end
 
-    private
+    #
+    # Whether the given handler attempts to provide the resource class at all.
+    #
+    # @api private
+    def self.includes_handler?(resource_name, resource_class)
+      handler_map.list(nil, resource_name).include?(resource_class)
+    end
 
-    # try dynamically finding a resource based on querying the resources to see what they support
-    def maybe_dynamic_resource_resolution(resource)
-      # log this so we know what resources will work for the generic resource on the node (early cut)
-      Chef::Log.debug "resources for generic #{resource} resource enabled on node include: #{enabled_handlers}"
-
-      # if none of the resources specifically support the resource, we still need to pick one of the resources that are
-      # enabled on the node to handle the why-run use case.
-      handlers = enabled_handlers
-
-      if handlers.count >= 2
-        # this magic stack ranks the resources by where they appear in the resource_priority_map
-        priority_list = [ get_priority_array(node, resource) ].flatten.compact
-        handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
-        if priority_list.index(handlers.first).nil?
-          # if we had more than one and we picked one with a precidence of infinity that means that the resource_priority_map
-          # entry for this resource is missing -- we should probably raise here and force resolution of the ambiguity.
-          Chef::Log.warn "Ambiguous resource precedence: #{handlers}, please use Chef.set_resource_priority_array to provide determinism"
-        end
-        handlers = [ handlers.first ]
-      end
+    protected
 
-      Chef::Log.debug "resources that survived replacement include: #{handlers}"
+    def self.priority_map
+      Chef.resource_priority_map
+    end
 
-      raise Chef::Exceptions::AmbiguousResourceResolution.new(resource, handlers) if handlers.count >= 2
+    def self.handler_map
+      Chef.resource_handler_map
+    end
 
-      Chef::Log.debug "dynamic resource resolver FAILED to resolve a resouce" if handlers.empty?
+    def priority_map
+      Chef.resource_priority_map
+    end
 
-      return nil if handlers.empty?
+    def handler_map
+      Chef.resource_handler_map
+    end
 
-      handlers[0]
+    # @api private
+    def potential_handlers
+      handler_map.list(node, resource_name, canonical: canonical).uniq
     end
 
-    # try the old static lookup of resources by mangling name to resource klass
-    def maybe_chef_platform_lookup(resource)
-      Chef::Resource.resource_matching_short_name(resource)
+    def enabled_handlers
+      potential_handlers.select { |handler| !overrode_provides?(handler) || handler.provides?(node, resource_name) }
     end
 
-    # dep injection hooks
-    def get_priority_array(node, resource_name)
-      resource_priority_map.get_priority_array(node, resource_name)
+    def prioritized_handlers
+      @prioritized_handlers ||= begin
+        enabled_handlers = self.enabled_handlers
+
+        prioritized = priority_map.list(node, resource_name, canonical: canonical).flatten(1)
+        prioritized &= enabled_handlers # Filter the priority map by the actual enabled handlers
+        prioritized |= enabled_handlers # Bring back any handlers that aren't in the priority map, at the *end* (ordered set)
+        prioritized
+      end
+    end
+
+    def overrode_provides?(handler)
+      handler.method(:provides?).owner != Chef::Resource.method(:provides?).owner
     end
 
-    def resource_priority_map
-      Chef::Platform::ResourcePriorityMap.instance
+    module Deprecated
+      # return a deterministically sorted list of Chef::Resource subclasses
+      def resources
+        Chef::Resource.sorted_descendants
+      end
+
+      def enabled_handlers
+        handlers = super
+        if handlers.empty?
+          handlers = resources.select { |handler| overrode_provides?(handler) && handler.provides?(node, resource_name) }
+          handlers.each do |handler|
+            Chef.log_deprecation("#{handler}.provides? returned true when asked if it provides DSL #{resource_name}, but provides #{resource_name.inspect} was never called!")
+            Chef.log_deprecation("In Chef 13, this will break: you must call provides to mark the names you provide, even if you also override provides? yourself.")
+          end
+        end
+        handlers
+      end
     end
+    prepend Deprecated
   end
 end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 40b12a7..71fe281 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,74 +16,72 @@
 # limitations under the License.
 #
 
-require 'chef/resource/apt_package'
-require 'chef/resource/bash'
-require 'chef/resource/batch'
-require 'chef/resource/breakpoint'
-require 'chef/resource/cookbook_file'
-require 'chef/resource/chef_gem'
-require 'chef/resource/cron'
-require 'chef/resource/csh'
-require 'chef/resource/deploy'
-require 'chef/resource/deploy_revision'
-require 'chef/resource/directory'
-require 'chef/resource/dpkg_package'
-require 'chef/resource/dsc_script'
-require 'chef/resource/dsc_resource'
-require 'chef/resource/easy_install_package'
-require 'chef/resource/env'
-require 'chef/resource/erl_call'
-require 'chef/resource/execute'
-require 'chef/resource/file'
-require 'chef/resource/freebsd_package'
-require 'chef/resource/ips_package'
-require 'chef/resource/gem_package'
-require 'chef/resource/git'
-require 'chef/resource/group'
-require 'chef/resource/http_request'
-require 'chef/resource/homebrew_package'
-require 'chef/resource/ifconfig'
-require 'chef/resource/link'
-require 'chef/resource/log'
-require 'chef/resource/macports_package'
-require 'chef/resource/mdadm'
-require 'chef/resource/mount'
-require 'chef/resource/ohai'
-require 'chef/resource/openbsd_package'
-require 'chef/resource/package'
-require 'chef/resource/pacman_package'
-require 'chef/resource/paludis_package'
-require 'chef/resource/perl'
-require 'chef/resource/portage_package'
-require 'chef/resource/powershell_script'
-require 'chef/resource/python'
-require 'chef/resource/reboot'
-require 'chef/resource/registry_key'
-require 'chef/resource/remote_directory'
-require 'chef/resource/remote_file'
-require 'chef/resource/rpm_package'
-require 'chef/resource/solaris_package'
-require 'chef/resource/route'
-require 'chef/resource/ruby'
-require 'chef/resource/ruby_block'
-require 'chef/resource/scm'
-require 'chef/resource/script'
-require 'chef/resource/service'
-require 'chef/resource/windows_service'
-require 'chef/resource/subversion'
-require 'chef/resource/smartos_package'
-require 'chef/resource/template'
-require 'chef/resource/timestamped_deploy'
-require 'chef/resource/user'
-require 'chef/resource/whyrun_safe_ruby_block'
-require 'chef/resource/windows_package'
-require 'chef/resource/yum_package'
-require 'chef/resource/lwrp_base'
-require 'chef/resource/bff_package'
-
-begin
-  # Optional resources chef_node, chef_client, machine, machine_image, etc.
-  require 'cheffish'
-  require 'chef/provisioning'
-rescue LoadError
-end
+require "chef/resource/apt_package"
+require "chef/resource/apt_update"
+require "chef/resource/bash"
+require "chef/resource/batch"
+require "chef/resource/breakpoint"
+require "chef/resource/cookbook_file"
+require "chef/resource/chef_gem"
+require "chef/resource/chocolatey_package"
+require "chef/resource/cron"
+require "chef/resource/csh"
+require "chef/resource/deploy"
+require "chef/resource/deploy_revision"
+require "chef/resource/directory"
+require "chef/resource/dpkg_package"
+require "chef/resource/dsc_script"
+require "chef/resource/dsc_resource"
+require "chef/resource/easy_install_package"
+require "chef/resource/env"
+require "chef/resource/erl_call"
+require "chef/resource/execute"
+require "chef/resource/file"
+require "chef/resource/freebsd_package"
+require "chef/resource/ips_package"
+require "chef/resource/gem_package"
+require "chef/resource/git"
+require "chef/resource/group"
+require "chef/resource/http_request"
+require "chef/resource/homebrew_package"
+require "chef/resource/ifconfig"
+require "chef/resource/ksh"
+require "chef/resource/link"
+require "chef/resource/log"
+require "chef/resource/macports_package"
+require "chef/resource/mdadm"
+require "chef/resource/mount"
+require "chef/resource/ohai"
+require "chef/resource/openbsd_package"
+require "chef/resource/package"
+require "chef/resource/pacman_package"
+require "chef/resource/paludis_package"
+require "chef/resource/perl"
+require "chef/resource/portage_package"
+require "chef/resource/powershell_script"
+require "chef/resource/osx_profile"
+require "chef/resource/python"
+require "chef/resource/reboot"
+require "chef/resource/registry_key"
+require "chef/resource/remote_directory"
+require "chef/resource/remote_file"
+require "chef/resource/rpm_package"
+require "chef/resource/solaris_package"
+require "chef/resource/route"
+require "chef/resource/ruby"
+require "chef/resource/ruby_block"
+require "chef/resource/scm"
+require "chef/resource/script"
+require "chef/resource/service"
+require "chef/resource/windows_service"
+require "chef/resource/subversion"
+require "chef/resource/smartos_package"
+require "chef/resource/template"
+require "chef/resource/timestamped_deploy"
+require "chef/resource/user"
+require "chef/resource/whyrun_safe_ruby_block"
+require "chef/resource/windows_package"
+require "chef/resource/yum_package"
+require "chef/resource/lwrp_base"
+require "chef/resource/bff_package"
+require "chef/resource/zypper_package"
diff --git a/lib/chef/rest.rb b/lib/chef/rest.rb
index 2612714..a3c5c66 100644
--- a/lib/chef/rest.rb
+++ b/lib/chef/rest.rb
@@ -1,10 +1,10 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Thom May (<thom at clearairturbulence.org>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,23 +20,23 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'chef/http'
+require "tempfile"
+require "chef/http"
 class Chef
   class HTTP; end
   class REST < HTTP; end
 end
 
-require 'chef/http/authenticator'
-require 'chef/http/decompressor'
-require 'chef/http/json_input'
-require 'chef/http/json_to_model_output'
-require 'chef/http/cookie_manager'
-require 'chef/http/validate_content_length'
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/platform/query_helpers'
-require 'chef/http/remote_request_id'
+require "chef/http/authenticator"
+require "chef/http/decompressor"
+require "chef/http/json_input"
+require "chef/http/json_to_model_output"
+require "chef/http/cookie_manager"
+require "chef/http/validate_content_length"
+require "chef/config"
+require "chef/exceptions"
+require "chef/platform/query_helpers"
+require "chef/http/remote_request_id"
 
 class Chef
 
@@ -57,13 +57,15 @@ class Chef
     # all subsequent requests. For example, when initialized with a base url
     # http://localhost:4000, a call to +get_rest+ with 'nodes' will make an
     # HTTP GET request to http://localhost:4000/nodes
-    def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={})
+    def initialize(url, client_name = Chef::Config[:node_name], signing_key_filename = Chef::Config[:client_key], options = {})
+      Chef.log_deprecation("Chef::REST is deprecated. Please use Chef::ServerAPI, or investigate Ridley or ChefAPI.")
 
       signing_key_filename = nil if chef_zero_uri?(url)
 
       options = options.dup
       options[:client_name] = client_name
       options[:signing_key_filename] = signing_key_filename
+
       super(url, options)
 
       @decompressor = Decompressor.new(options)
@@ -81,7 +83,6 @@ class Chef
       # because the order of middlewares is reversed when handling
       # responses.
       @middlewares << ValidateContentLength.new(options)
-
     end
 
     def signing_key_filename
@@ -112,7 +113,7 @@ class Chef
     # path:: The path to GET
     # raw:: Whether you want the raw body returned, or JSON inflated.  Defaults
     #   to JSON inflated.
-    def get(path, raw=false, headers={})
+    def get(path, raw = false, headers = {})
       if raw
         streaming_request(path, headers)
       else
@@ -133,8 +134,8 @@ class Chef
     # If you rename the tempfile, it will not be deleted.
     # Beware that if the server streams infinite content, this method will
     # stream it until you run out of disk space.
-    def fetch(path, headers={})
-      streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file }
+    def fetch(path, headers = {})
+      streaming_request(create_url(path), headers) { |tmp_file| yield tmp_file }
     end
 
     alias :api_request :request
@@ -165,7 +166,7 @@ class Chef
     def retriable_http_request(method, url, req_body, headers)
       rest_request = Chef::HTTP::HTTPRequest.new(method, url, req_body, headers)
 
-      Chef::Log.debug("Sending HTTP Request via #{method} to #{url.host}:#{url.port}#{rest_request.path}")
+      Chef::Log.debug("Sending HTTP request via #{method} to #{url.host}:#{url.port}#{rest_request.path}")
 
       retrying_http_errors(url) do
         yield rest_request
@@ -200,7 +201,7 @@ class Chef
       @decompressor.decompress_body(body)
     end
 
-    def authentication_headers(method, url, json_body=nil)
+    def authentication_headers(method, url, json_body = nil)
       authenticator.authentication_headers(method, url, json_body)
     end
 
diff --git a/lib/chef/role.rb b/lib/chef/role.rb
index c085d1d..a5a33c2 100644
--- a/lib/chef/role.rb
+++ b/lib/chef/role.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,13 +18,14 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/run_list'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/run_list"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/server_api"
+require "chef/search/query"
 
 class Chef
   class Role
@@ -36,35 +37,35 @@ class Chef
 
     # Create a new Chef::Role object.
     def initialize(chef_server_rest: nil)
-      @name = ''
-      @description = ''
+      @name = ""
+      @description = ""
       @default_attributes = Mash.new
       @override_attributes = Mash.new
-      @env_run_lists = {"_default" => Chef::RunList.new}
+      @env_run_lists = { "_default" => Chef::RunList.new }
       @chef_server_rest = chef_server_rest
     end
 
     def chef_server_rest
-      @chef_server_rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
+      @chef_server_rest ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
     def self.chef_server_rest
-      Chef::REST.new(Chef::Config[:chef_server_url])
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url])
     end
 
-    def name(arg=nil)
+    def name(arg = nil)
       set_or_return(
         :name,
         arg,
-        :regex => /^[\-[:alnum:]_]+$/
+        :regex => /^[\-[:alnum:]_]+$/,
       )
     end
 
-    def description(arg=nil)
+    def description(arg = nil)
       set_or_return(
         :description,
         arg,
-        :kind_of => String
+        :kind_of => String,
       )
     end
 
@@ -87,11 +88,11 @@ class Chef
     end
 
     def active_run_list_for(environment)
-      @env_run_lists.has_key?(environment) ? environment : '_default'
+      @env_run_lists.has_key?(environment) ? environment : "_default"
     end
 
     # Per environment run lists
-    def env_run_lists(env_run_lists=nil)
+    def env_run_lists(env_run_lists = nil)
       if (!env_run_lists.nil?)
         unless env_run_lists.key?("_default")
           msg = "_default key is required in env_run_lists.\n"
@@ -99,36 +100,35 @@ class Chef
           raise Chef::Exceptions::InvalidEnvironmentRunListSpecification, msg
         end
         @env_run_lists.clear
-        env_run_lists.each { |k,v| @env_run_lists[k] = Chef::RunList.new(*Array(v))}
+        env_run_lists.each { |k, v| @env_run_lists[k] = Chef::RunList.new(*Array(v)) }
       end
       @env_run_lists
     end
 
     alias :env_run_list :env_run_lists
 
-    def env_run_lists_add(env_run_lists=nil)
+    def env_run_lists_add(env_run_lists = nil)
       if (!env_run_lists.nil?)
-        env_run_lists.each { |k,v| @env_run_lists[k] = Chef::RunList.new(*Array(v))}
+        env_run_lists.each { |k, v| @env_run_lists[k] = Chef::RunList.new(*Array(v)) }
       end
       @env_run_lists
     end
 
     alias :env_run_list_add :env_run_lists_add
 
-
-    def default_attributes(arg=nil)
+    def default_attributes(arg = nil)
       set_or_return(
         :default_attributes,
         arg,
-        :kind_of => Hash
+        :kind_of => Hash,
       )
     end
 
-    def override_attributes(arg=nil)
+    def override_attributes(arg = nil)
       set_or_return(
         :override_attributes,
         arg,
-        :kind_of => Hash
+        :kind_of => Hash,
       )
     end
 
@@ -138,7 +138,7 @@ class Chef
       result = {
         "name" => @name,
         "description" => @description,
-        'json_class' => self.class.name,
+        "json_class" => self.class.name,
         "default_attributes" => @default_attributes,
         "override_attributes" => @override_attributes,
         "chef_type" => "role",
@@ -149,7 +149,7 @@ class Chef
         "env_run_lists" => env_run_lists_without_default.inject({}) do |accumulator, (k, v)|
           accumulator[k] = v.map { |x| x.to_s }
           accumulator
-        end
+        end,
       }
       result
     end
@@ -170,6 +170,11 @@ class Chef
 
     # Create a Chef::Role from JSON
     def self.json_create(o)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::Role#from_hash")
+      from_hash(o)
+    end
+
+    def self.from_hash(o)
       role = new
       role.name(o["name"])
       role.description(o["description"])
@@ -178,7 +183,7 @@ class Chef
 
       # _default run_list is in 'run_list' for newer clients, and
       # 'recipes' for older clients.
-      env_run_list_hash = {"_default" => (o.has_key?("run_list") ? o["run_list"] : o["recipes"])}
+      env_run_list_hash = { "_default" => (o.has_key?("run_list") ? o["run_list"] : o["recipes"]) }
 
       # Clients before 0.10 do not include env_run_lists, so only
       # merge if it's there.
@@ -191,7 +196,7 @@ class Chef
     end
 
     # Get the list of all roles from the API.
-    def self.list(inflate=false)
+    def self.list(inflate = false)
       if inflate
         response = Hash.new
         Chef::Search::Query.new.search(:role) do |n|
@@ -199,42 +204,42 @@ class Chef
         end
         response
       else
-        chef_server_rest.get_rest("roles")
+        chef_server_rest.get("roles")
       end
     end
 
     # Load a role by name from the API
     def self.load(name)
-      chef_server_rest.get_rest("roles/#{name}")
+      from_hash(chef_server_rest.get("roles/#{name}"))
     end
 
     def environment(env_name)
-      chef_server_rest.get_rest("roles/#{@name}/environments/#{env_name}")
+      chef_server_rest.get("roles/#{@name}/environments/#{env_name}")
     end
 
     def environments
-      chef_server_rest.get_rest("roles/#{@name}/environments")
+      chef_server_rest.get("roles/#{@name}/environments")
     end
 
     # Remove this role via the REST API
     def destroy
-      chef_server_rest.delete_rest("roles/#{@name}")
+      chef_server_rest.delete("roles/#{@name}")
     end
 
     # Save this role via the REST API
     def save
       begin
-        chef_server_rest.put_rest("roles/#{@name}", self)
+        chef_server_rest.put("roles/#{@name}", self)
       rescue Net::HTTPServerException => e
         raise e unless e.response.code == "404"
-        chef_server_rest.post_rest("roles", self)
+        chef_server_rest.post("roles", self)
       end
       self
     end
 
     # Create the role via the REST API
     def create
-      chef_server_rest.post_rest("roles", self)
+      chef_server_rest.post("roles", self)
       self
     end
 
@@ -258,7 +263,8 @@ class Chef
 
         if js_path && File.exists?(js_path)
           # from_json returns object.class => json_class in the JSON.
-          return Chef::JSONCompat.from_json(IO.read(js_path))
+          hsh = Chef::JSONCompat.parse(IO.read(js_path))
+          return from_hash(hsh)
         elsif rb_path && File.exists?(rb_path)
           role = Chef::Role.new
           role.name(name)
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 4f0215b..ecb16c1 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,125 +17,271 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/resource_collection'
-require 'chef/cookbook_version'
-require 'chef/node'
-require 'chef/role'
-require 'chef/log'
-require 'chef/recipe'
-require 'chef/run_context/cookbook_compiler'
-require 'chef/event_dispatch/events_output_stream'
+require "chef/resource_collection"
+require "chef/cookbook_version"
+require "chef/node"
+require "chef/role"
+require "chef/log"
+require "chef/recipe"
+require "chef/run_context/cookbook_compiler"
+require "chef/event_dispatch/events_output_stream"
+require "forwardable"
 
 class Chef
 
   # == Chef::RunContext
   # Value object that loads and tracks the context of a Chef run
   class RunContext
+    #
+    # Global state
+    #
 
-    # Chef::Node object for this run
+    #
+    # The node for this run
+    #
+    # @return [Chef::Node]
+    #
     attr_reader :node
 
-    # Chef::CookbookCollection for this run
+    #
+    # The set of cookbooks involved in this run
+    #
+    # @return [Chef::CookbookCollection]
+    #
     attr_reader :cookbook_collection
 
+    #
     # Resource Definitions for this run. Populated when the files in
     # +definitions/+ are evaluated (this is triggered by #load).
+    #
+    # @return [Array[Chef::ResourceDefinition]]
+    #
     attr_reader :definitions
 
-    ###
-    # These need to be settable so deploy can run a resource_collection
-    # independent of any cookbooks via +recipe_eval+
+    #
+    # Event dispatcher for this run.
+    #
+    # @return [Chef::EventDispatch::Dispatcher]
+    #
+    attr_reader :events
+
+    #
+    # Hash of factoids for a reboot request.
+    #
+    # @return [Hash]
+    #
+    attr_accessor :reboot_info
+
+    #
+    # Scoped state
+    #
+
+    #
+    # The parent run context.
+    #
+    # @return [Chef::RunContext] The parent run context, or `nil` if this is the
+    #   root context.
+    #
+    attr_reader :parent_run_context
 
-    # The Chef::ResourceCollection for this run. Populated by evaluating
-    # recipes, which is triggered by #load. (See also: CookbookCompiler)
-    attr_accessor :resource_collection
+    #
+    # The collection of resources intended to be converged (and able to be
+    # notified).
+    #
+    # @return [Chef::ResourceCollection]
+    #
+    # @see CookbookCompiler
+    #
+    attr_reader :resource_collection
 
+    #
     # The list of control groups to execute during the audit phase
-    attr_accessor :audits
+    #
+    attr_reader :audits
+
+    #
+    # Notification handling
+    #
+
+    #
+    # A Hash containing the before notifications triggered by resources
+    # during the converge phase of the chef run.
+    #
+    # @return [Hash[String, Array[Chef::Resource::Notification]]] A hash from
+    #   <notifying resource name> => <list of notifications it sent>
+    #
+    attr_reader :before_notification_collection
 
+    #
     # A Hash containing the immediate notifications triggered by resources
     # during the converge phase of the chef run.
-    attr_accessor :immediate_notification_collection
+    #
+    # @return [Hash[String, Array[Chef::Resource::Notification]]] A hash from
+    #   <notifying resource name> => <list of notifications it sent>
+    #
+    attr_reader :immediate_notification_collection
 
+    #
     # A Hash containing the delayed (end of run) notifications triggered by
     # resources during the converge phase of the chef run.
-    attr_accessor :delayed_notification_collection
-
-    # Event dispatcher for this run.
-    attr_reader :events
-
-    # Hash of factoids for a reboot request.
-    attr_reader :reboot_info
+    #
+    # @return [Hash[String, Array[Chef::Resource::Notification]]] A hash from
+    #   <notifying resource name> => <list of notifications it sent>
+    #
+    attr_reader :delayed_notification_collection
 
     # Creates a new Chef::RunContext object and populates its fields. This object gets
     # used by the Chef Server to generate a fully compiled recipe list for a node.
     #
-    # === Returns
-    # object<Chef::RunContext>:: Duh. :)
+    # @param node [Chef::Node] The node to run against.
+    # @param cookbook_collection [Chef::CookbookCollection] The cookbooks
+    #   involved in this run.
+    # @param events [EventDispatch::Dispatcher] The event dispatcher for this
+    #   run.
+    #
     def initialize(node, cookbook_collection, events)
       @node = node
       @cookbook_collection = cookbook_collection
-      @resource_collection = Chef::ResourceCollection.new
-      @audits = {}
-      @immediate_notification_collection = Hash.new {|h,k| h[k] = []}
-      @delayed_notification_collection = Hash.new {|h,k| h[k] = []}
-      @definitions = Hash.new
-      @loaded_recipes = {}
-      @loaded_attributes = {}
       @events = events
-      @reboot_info = {}
 
-      @node.run_context = self
+      node.run_context = self
+      node.set_cookbook_attribute
+
+      @definitions = Hash.new
+      @loaded_recipes_hash = {}
+      @loaded_attributes_hash = {}
+      @reboot_info = {}
       @cookbook_compiler = nil
+
+      initialize_child_state
     end
 
-    # Triggers the compile phase of the chef run. Implemented by
-    # Chef::RunContext::CookbookCompiler
+    #
+    # Triggers the compile phase of the chef run.
+    #
+    # @param run_list_expansion [Chef::RunList::RunListExpansion] The run list.
+    # @see Chef::RunContext::CookbookCompiler
+    #
     def load(run_list_expansion)
       @cookbook_compiler = CookbookCompiler.new(self, run_list_expansion, events)
-      @cookbook_compiler.compile
+      cookbook_compiler.compile
+    end
+
+    #
+    # Initialize state that applies to both Chef::RunContext and Chef::ChildRunContext
+    #
+    def initialize_child_state
+      @audits = {}
+      @resource_collection = Chef::ResourceCollection.new
+      @before_notification_collection = Hash.new { |h, k| h[k] = [] }
+      @immediate_notification_collection = Hash.new { |h, k| h[k] = [] }
+      @delayed_notification_collection = Hash.new { |h, k| h[k] = [] }
+    end
+
+    #
+    # Adds an before notification to the +before_notification_collection+.
+    #
+    # @param [Chef::Resource::Notification] The notification to add.
+    #
+    def notifies_before(notification)
+      nr = notification.notifying_resource
+      if nr.instance_of?(Chef::Resource)
+        before_notification_collection[nr.name] << notification
+      else
+        before_notification_collection[nr.declared_key] << notification
+      end
     end
 
-    # Adds an immediate notification to the
-    # +immediate_notification_collection+. The notification should be a
-    # Chef::Resource::Notification or duck type.
+    #
+    # Adds an immediate notification to the +immediate_notification_collection+.
+    #
+    # @param [Chef::Resource::Notification] The notification to add.
+    #
     def notifies_immediately(notification)
       nr = notification.notifying_resource
       if nr.instance_of?(Chef::Resource)
-        @immediate_notification_collection[nr.name] << notification
+        immediate_notification_collection[nr.name] << notification
       else
-        @immediate_notification_collection[nr.declared_key] << notification
+        immediate_notification_collection[nr.declared_key] << notification
       end
     end
 
-    # Adds a delayed notification to the +delayed_notification_collection+. The
-    # notification should be a Chef::Resource::Notification or duck type.
+    #
+    # Adds a delayed notification to the +delayed_notification_collection+.
+    #
+    # @param [Chef::Resource::Notification] The notification to add.
+    #
     def notifies_delayed(notification)
       nr = notification.notifying_resource
       if nr.instance_of?(Chef::Resource)
-        @delayed_notification_collection[nr.name] << notification
+        delayed_notification_collection[nr.name] << notification
+      else
+        delayed_notification_collection[nr.declared_key] << notification
+      end
+    end
+
+    #
+    # Get the list of before notifications sent by the given resource.
+    #
+    # TODO seriously, this is actually wrong.  resource.name is not unique,
+    # you need the type as well.
+    #
+    # @return [Array[Notification]]
+    #
+    def before_notifications(resource)
+      if resource.instance_of?(Chef::Resource)
+        return before_notification_collection[resource.name]
       else
-        @delayed_notification_collection[nr.declared_key] << notification
+        return before_notification_collection[resource.declared_key]
       end
     end
 
+    #
+    # Get the list of immediate notifications sent by the given resource.
+    #
+    # TODO seriously, this is actually wrong.  resource.name is not unique,
+    # you need the type as well.
+    #
+    # @return [Array[Notification]]
+    #
     def immediate_notifications(resource)
       if resource.instance_of?(Chef::Resource)
-        return @immediate_notification_collection[resource.name]
+        return immediate_notification_collection[resource.name]
       else
-        return @immediate_notification_collection[resource.declared_key]
+        return immediate_notification_collection[resource.declared_key]
       end
     end
 
+    #
+    # Get the list of delayed (end of run) notifications sent by the given
+    # resource.
+    #
+    # TODO seriously, this is actually wrong.  resource.name is not unique,
+    # you need the type as well.
+    #
+    # @return [Array[Notification]]
+    #
     def delayed_notifications(resource)
       if resource.instance_of?(Chef::Resource)
-        return @delayed_notification_collection[resource.name]
+        return delayed_notification_collection[resource.name]
       else
-        return @delayed_notification_collection[resource.declared_key]
+        return delayed_notification_collection[resource.declared_key]
       end
     end
 
+    #
+    # Cookbook and recipe loading
+    #
+
+    #
     # Evaluates the recipes +recipe_names+. Used by DSL::IncludeRecipe
+    #
+    # @param recipe_names [Array[String]] The list of recipe names (e.g.
+    #   'my_cookbook' or 'my_cookbook::my_resource').
+    # @param current_cookbook The cookbook we are currently running in.
+    #
+    # @see DSL::IncludeRecipe#include_recipe
+    #
     def include_recipe(*recipe_names, current_cookbook: nil)
       result_recipes = Array.new
       recipe_names.flatten.each do |recipe_name|
@@ -146,9 +292,23 @@ class Chef
       result_recipes
     end
 
+    #
     # Evaluates the recipe +recipe_name+. Used by DSL::IncludeRecipe
+    #
+    # TODO I am sort of confused why we have both this and include_recipe ...
+    #      I don't see anything different beyond accepting and returning an
+    #      array of recipes.
+    #
+    # @param recipe_names [Array[String]] The recipe name (e.g 'my_cookbook' or
+    #   'my_cookbook::my_resource').
+    # @param current_cookbook The cookbook we are currently running in.
+    #
+    # @return A truthy value if the load occurred; `false` if already loaded.
+    #
+    # @see DSL::IncludeRecipe#load_recipe
+    #
     def load_recipe(recipe_name, current_cookbook: nil)
-      Chef::Log.debug("Loading Recipe #{recipe_name} via include_recipe")
+      Chef::Log.debug("Loading recipe #{recipe_name} via include_recipe")
 
       cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name, current_cookbook: current_cookbook)
 
@@ -162,7 +322,6 @@ including it from in that cookbook's metadata.
 ERROR_MESSAGE
       end
 
-
       if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name)
         Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.")
         false
@@ -174,19 +333,39 @@ ERROR_MESSAGE
       end
     end
 
+    #
+    # Load the given recipe from a filename.
+    #
+    # @param recipe_file [String] The recipe filename.
+    #
+    # @return [Chef::Recipe] The loaded recipe.
+    #
+    # @raise [Chef::Exceptions::RecipeNotFound] If the file does not exist.
+    #
     def load_recipe_file(recipe_file)
       if !File.exist?(recipe_file)
         raise Chef::Exceptions::RecipeNotFound, "could not find recipe file #{recipe_file}"
       end
 
-      Chef::Log.debug("Loading Recipe File #{recipe_file}")
-      recipe = Chef::Recipe.new('@recipe_files', recipe_file, self)
+      Chef::Log.debug("Loading recipe file #{recipe_file}")
+      recipe = Chef::Recipe.new("@recipe_files", recipe_file, self)
       recipe.from_file(recipe_file)
       recipe
     end
 
-    # Looks up an attribute file given the +cookbook_name+ and
-    # +attr_file_name+. Used by DSL::IncludeAttribute
+    #
+    # Look up an attribute filename.
+    #
+    # @param cookbook_name [String] The cookbook name of the attribute file.
+    # @param attr_file_name [String] The attribute file's name (not path).
+    #
+    # @return [String] The filename.
+    #
+    # @see DSL::IncludeAttribute#include_attribute
+    #
+    # @raise [Chef::Exceptions::CookbookNotFound] If the cookbook could not be found.
+    # @raise [Chef::Exceptions::AttributeNotFound] If the attribute file could not be found.
+    #
     def resolve_attribute(cookbook_name, attr_file_name)
       cookbook = cookbook_collection[cookbook_name]
       raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{cookbook_name} while loading attribute #{name}" unless cookbook
@@ -197,76 +376,152 @@ ERROR_MESSAGE
       attribute_filename
     end
 
-    # An Array of all recipes that have been loaded. This is stored internally
-    # as a Hash, so ordering is predictable.
     #
-    # Recipe names are given in fully qualified form, e.g., the recipe "nginx"
-    # will be given as "nginx::default"
+    # A list of all recipes that have been loaded.
+    #
+    # This is stored internally as a Hash, so ordering is predictable.
+    #
+    # TODO is the above statement true in a 1.9+ ruby world?  Is it relevant?
+    #
+    # @return [Array[String]] A list of recipes in fully qualified form, e.g.
+    #   the recipe "nginx" will be given as "nginx::default".
+    #
+    # @see #loaded_recipe? To determine if a particular recipe has been loaded.
     #
-    # To determine if a particular recipe has been loaded, use #loaded_recipe?
     def loaded_recipes
-      @loaded_recipes.keys
+      loaded_recipes_hash.keys
     end
 
-    # An Array of all attributes files that have been loaded. Stored internally
-    # using a Hash, so order is predictable.
     #
-    # Attribute file names are given in fully qualified form, e.g.,
-    # "nginx::default" instead of "nginx".
+    # A list of all attributes files that have been loaded.
+    #
+    # Stored internally using a Hash, so order is predictable.
+    #
+    # TODO is the above statement true in a 1.9+ ruby world?  Is it relevant?
+    #
+    # @return [Array[String]] A list of attribute file names in fully qualified
+    #   form, e.g. the "nginx" will be given as "nginx::default".
+    #
     def loaded_attributes
-      @loaded_attributes.keys
+      loaded_attributes_hash.keys
     end
 
+    #
+    # Find out if a given recipe has been loaded.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param recipe [String] Recipe name.
+    #
+    # @return [Boolean] `true` if the recipe has been loaded, `false` otherwise.
+    #
     def loaded_fully_qualified_recipe?(cookbook, recipe)
-      @loaded_recipes.has_key?("#{cookbook}::#{recipe}")
+      loaded_recipes_hash.has_key?("#{cookbook}::#{recipe}")
     end
 
-    # Returns true if +recipe+ has been loaded, false otherwise. Default recipe
-    # names are expanded, so `loaded_recipe?("nginx")` and
-    # `loaded_recipe?("nginx::default")` are valid and give identical results.
+    #
+    # Find out if a given recipe has been loaded.
+    #
+    # @param recipe [String] Recipe name.  "nginx" and "nginx::default" yield
+    #   the same results.
+    #
+    # @return [Boolean] `true` if the recipe has been loaded, `false` otherwise.
+    #
     def loaded_recipe?(recipe)
       cookbook, recipe_name = Chef::Recipe.parse_recipe_name(recipe)
       loaded_fully_qualified_recipe?(cookbook, recipe_name)
     end
 
+    #
+    # Mark a given recipe as having been loaded.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param recipe [String] Recipe name.
+    #
+    def loaded_recipe(cookbook, recipe)
+      loaded_recipes_hash["#{cookbook}::#{recipe}"] = true
+    end
+
+    #
+    # Find out if a given attribute file has been loaded.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param attribute_file [String] Attribute file name.
+    #
+    # @return [Boolean] `true` if the recipe has been loaded, `false` otherwise.
+    #
     def loaded_fully_qualified_attribute?(cookbook, attribute_file)
-      @loaded_attributes.has_key?("#{cookbook}::#{attribute_file}")
+      loaded_attributes_hash.has_key?("#{cookbook}::#{attribute_file}")
     end
 
+    #
+    # Mark a given attribute file as having been loaded.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param attribute_file [String] Attribute file name.
+    #
     def loaded_attribute(cookbook, attribute_file)
-      @loaded_attributes["#{cookbook}::#{attribute_file}"] = true
+      loaded_attributes_hash["#{cookbook}::#{attribute_file}"] = true
     end
 
     ##
     # Cookbook File Introspection
 
+    #
+    # Find out if the cookbook has the given template.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param template_name [String] Template name.
+    #
+    # @return [Boolean] `true` if the template is in the cookbook, `false`
+    #   otherwise.
+    # @see Chef::CookbookVersion#has_template_for_node?
+    #
     def has_template_in_cookbook?(cookbook, template_name)
       cookbook = cookbook_collection[cookbook]
       cookbook.has_template_for_node?(node, template_name)
     end
 
+    #
+    # Find out if the cookbook has the given file.
+    #
+    # @param cookbook [String] Cookbook name.
+    # @param cb_file_name [String] File name.
+    #
+    # @return [Boolean] `true` if the file is in the cookbook, `false`
+    #   otherwise.
+    # @see Chef::CookbookVersion#has_cookbook_file_for_node?
+    #
     def has_cookbook_file_in_cookbook?(cookbook, cb_file_name)
       cookbook = cookbook_collection[cookbook]
       cookbook.has_cookbook_file_for_node?(node, cb_file_name)
     end
 
-    # Delegates to CookbookCompiler#unreachable_cookbook?
-    # Used to raise an error when attempting to load a recipe belonging to a
-    # cookbook that is not in the dependency graph. See also: CHEF-4367
+    #
+    # Find out whether the given cookbook is in the cookbook dependency graph.
+    #
+    # @param cookbook_name [String] Cookbook name.
+    #
+    # @return [Boolean] `true` if the cookbook is reachable, `false` otherwise.
+    #
+    # @see Chef::CookbookCompiler#unreachable_cookbook?
     def unreachable_cookbook?(cookbook_name)
-      @cookbook_compiler.unreachable_cookbook?(cookbook_name)
+      cookbook_compiler.unreachable_cookbook?(cookbook_name)
     end
 
+    #
     # Open a stream object that can be printed into and will dispatch to events
     #
-    # == Arguments
-    # options is a hash with these possible options:
-    # - name: a string that identifies the stream to the user. Preferably short.
+    # @param name [String] The name of the stream.
+    # @param options [Hash] Other options for the stream.
+    #
+    # @return [EventDispatch::EventsOutputStream] The created stream.
     #
-    # Pass a block and the stream will be yielded to it, and close on its own
-    # at the end of the block.
-    def open_stream(options = {})
-      stream = EventDispatch::EventsOutputStream.new(events, options)
+    # @yield If a block is passed, it will be run and the stream will be closed
+    #   afterwards.
+    # @yieldparam stream [EventDispatch::EventsOutputStream] The created stream.
+    #
+    def open_stream(name: nil, **options)
+      stream = EventDispatch::EventsOutputStream.new(events, name: name, **options)
       if block_given?
         begin
           yield stream
@@ -279,31 +534,137 @@ ERROR_MESSAGE
     end
 
     # there are options for how to handle multiple calls to these functions:
-    # 1. first call always wins (never change @reboot_info once set).
-    # 2. last call always wins (happily change @reboot_info whenever).
+    # 1. first call always wins (never change reboot_info once set).
+    # 2. last call always wins (happily change reboot_info whenever).
     # 3. raise an exception on the first conflict.
     # 4. disable reboot after this run if anyone ever calls :cancel.
     # 5. raise an exception on any second call.
     # 6. ?
     def request_reboot(reboot_info)
-      Chef::Log::info "Changing reboot status from #{@reboot_info.inspect} to #{reboot_info.inspect}"
+      Chef::Log::info "Changing reboot status from #{self.reboot_info.inspect} to #{reboot_info.inspect}"
       @reboot_info = reboot_info
     end
 
     def cancel_reboot
-      Chef::Log::info "Changing reboot status from #{@reboot_info.inspect} to {}"
+      Chef::Log::info "Changing reboot status from #{reboot_info.inspect} to {}"
       @reboot_info = {}
     end
 
     def reboot_requested?
-      @reboot_info.size > 0
+      reboot_info.size > 0
+    end
+
+    #
+    # Create a child RunContext.
+    #
+    def create_child
+      ChildRunContext.new(self)
     end
 
-    private
+    # @api private
+    attr_writer :resource_collection
 
-    def loaded_recipe(cookbook, recipe)
-      @loaded_recipes["#{cookbook}::#{recipe}"] = true
+    protected
+
+    attr_reader :cookbook_compiler
+    attr_reader :loaded_attributes_hash
+    attr_reader :loaded_recipes_hash
+
+    module Deprecated
+      ###
+      # These need to be settable so deploy can run a resource_collection
+      # independent of any cookbooks via +recipe_eval+
+      def audits=(value)
+        Chef.log_deprecation("Setting run_context.audits will be removed in a future Chef.  Use run_context.create_child to create a new RunContext instead.")
+        @audits = value
+      end
+
+      def immediate_notification_collection=(value)
+        Chef.log_deprecation("Setting run_context.immediate_notification_collection will be removed in a future Chef.  Use run_context.create_child to create a new RunContext instead.")
+        @immediate_notification_collection = value
+      end
+
+      def delayed_notification_collection=(value)
+        Chef.log_deprecation("Setting run_context.delayed_notification_collection will be removed in a future Chef.  Use run_context.create_child to create a new RunContext instead.")
+        @delayed_notification_collection = value
+      end
     end
+    prepend Deprecated
 
+    #
+    # A child run context.  Delegates all root context calls to its parent.
+    #
+    # @api private
+    #
+    class ChildRunContext < RunContext
+      extend Forwardable
+      def_delegators :parent_run_context, *%w{
+        cancel_reboot
+        config
+        cookbook_collection
+        cookbook_compiler
+        definitions
+        events
+        has_cookbook_file_in_cookbook?
+        has_template_in_cookbook?
+        load
+        loaded_attribute
+        loaded_attributes
+        loaded_attributes_hash
+        loaded_fully_qualified_attribute?
+        loaded_fully_qualified_recipe?
+        loaded_recipe
+        loaded_recipe?
+        loaded_recipes
+        loaded_recipes_hash
+        node
+        open_stream
+        reboot_info
+        reboot_info=
+        reboot_requested?
+        request_reboot
+        resolve_attribute
+        unreachable_cookbook?
+      }
+
+      def initialize(parent_run_context)
+        @parent_run_context = parent_run_context
+
+        # We don't call super, because we don't bother initializing stuff we're
+        # going to delegate to the parent anyway.  Just initialize things that
+        # every instance needs.
+        initialize_child_state
+      end
+
+      CHILD_STATE = %w{
+        audits
+        audits=
+        create_child
+        delayed_notification_collection
+        delayed_notification_collection=
+        delayed_notifications
+        immediate_notification_collection
+        immediate_notification_collection=
+        immediate_notifications
+        before_notification_collection
+        before_notifications
+        include_recipe
+        initialize_child_state
+        load_recipe
+        load_recipe_file
+        notifies_before
+        notifies_immediately
+        notifies_delayed
+        parent_run_context
+        resource_collection
+        resource_collection=
+      }.map { |x| x.to_sym }
+
+      # Verify that we didn't miss any methods
+      missing_methods = superclass.instance_methods(false) - instance_methods(false) - CHILD_STATE
+      if !missing_methods.empty?
+        raise "ERROR: not all methods of RunContext accounted for in ChildRunContext! All methods must be marked as child methods with CHILD_STATE or delegated to the parent_run_context. Missing #{missing_methods.join(", ")}."
+      end
+    end
   end
 end
diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb
index abe5afa..e8311a1 100644
--- a/lib/chef/run_context/cookbook_compiler.rb
+++ b/lib/chef/run_context/cookbook_compiler.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'set'
-require 'chef/log'
-require 'chef/recipe'
-require 'chef/resource/lwrp_base'
-require 'chef/provider/lwrp_base'
-require 'chef/resource_definition_list'
+require "set"
+require "chef/log"
+require "chef/recipe"
+require "chef/resource/lwrp_base"
+require "chef/provider/lwrp_base"
+require "chef/resource_definition_list"
 
 class Chef
   class RunContext
@@ -165,7 +165,7 @@ class Chef
 
       def load_attributes_from_cookbook(cookbook_name)
         list_of_attr_files = files_in_cookbook_by_segment(cookbook_name, :attributes).dup
-        if default_file = list_of_attr_files.find {|path| File.basename(path) == "default.rb" }
+        if default_file = list_of_attr_files.find { |path| File.basename(path) == "default.rb" }
           list_of_attr_files.delete(default_file)
           load_attribute_file(cookbook_name.to_s, default_file)
         end
@@ -224,7 +224,6 @@ class Chef
         raise
       end
 
-
       def load_resource_definitions_from_cookbook(cookbook_name)
         files_in_cookbook_by_segment(cookbook_name, :definitions).each do |filename|
           begin
@@ -258,7 +257,6 @@ class Chef
         ordered_cookbooks << cookbook
       end
 
-
       def count_files_by_segment(segment)
         cookbook_collection.inject(0) do |count, cookbook_by_name|
           count + cookbook_by_name[1].segment_filenames(segment).size
@@ -275,7 +273,7 @@ class Chef
       # +cookbook_name+ in lexical sort order.
       def each_cookbook_dep(cookbook_name, &block)
         cookbook = cookbook_collection[cookbook_name]
-        cookbook.metadata.dependencies.keys.sort.map{|x| x.to_sym}.each(&block)
+        cookbook.metadata.dependencies.keys.sort.map { |x| x.to_sym }.each(&block)
       end
 
       # Given a +recipe_name+, finds the file associated with the recipe.
@@ -285,7 +283,6 @@ class Chef
         cookbook.recipe_filenames_by_name[recipe_short_name]
       end
 
-
     end
 
   end
diff --git a/lib/chef/run_list.rb b/lib/chef/run_list.rb
index 01e32ff..b9ec925 100644
--- a/lib/chef/run_list.rb
+++ b/lib/chef/run_list.rb
@@ -1,10 +1,10 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Nuo Yan (<nuoyan at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Nuo Yan (<nuoyan at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,10 +19,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/run_list/run_list_item'
-require 'chef/run_list/run_list_expansion'
-require 'chef/run_list/versioned_recipe_list'
-require 'chef/mixin/params_validate'
+require "chef/run_list/run_list_item"
+require "chef/run_list/run_list_expansion"
+require "chef/run_list/versioned_recipe_list"
+require "chef/mixin/params_validate"
 
 class Chef
   class RunList
@@ -47,13 +47,13 @@ class Chef
     end
 
     def role_names
-      @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.role? ; memo}
+      @run_list_items.inject([]) { |memo, run_list_item| memo << run_list_item.name if run_list_item.role? ; memo }
     end
 
     alias :roles :role_names
 
     def recipe_names
-      @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.recipe? ; memo}
+      @run_list_items.inject([]) { |memo, run_list_item| memo << run_list_item.name if run_list_item.recipe? ; memo }
     end
 
     alias :recipes :recipe_names
@@ -130,7 +130,7 @@ class Chef
     end
 
     def remove(item)
-      @run_list_items.delete_if{|i| i == item}
+      @run_list_items.delete_if { |i| i == item }
       self
     end
     alias :delete :remove
@@ -138,7 +138,7 @@ class Chef
     # Expands this run_list: recursively expand roles into their included
     # recipes.
     # Returns a RunListExpansion object.
-    def expand(environment, data_source='server', expansion_opts={})
+    def expand(environment, data_source = "server", expansion_opts = {})
       expansion = expansion_for_data_source(environment, data_source, expansion_opts)
       expansion.expand
       expansion
@@ -153,11 +153,11 @@ class Chef
       item.kind_of?(RunListItem) ? item : parse_entry(item)
     end
 
-    def expansion_for_data_source(environment, data_source, opts={})
+    def expansion_for_data_source(environment, data_source, opts = {})
       case data_source.to_s
-      when 'disk'
+      when "disk"
         RunListExpansionFromDisk.new(environment, @run_list_items)
-      when 'server'
+      when "server"
         RunListExpansionFromAPI.new(environment, @run_list_items, opts[:rest])
       end
     end
diff --git a/lib/chef/run_list/run_list_expansion.rb b/lib/chef/run_list/run_list_expansion.rb
index 46b45f1..b895b53 100644
--- a/lib/chef/run_list/run_list_expansion.rb
+++ b/lib/chef/run_list/run_list_expansion.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010, 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/mash'
+require "chef/mash"
 
-require 'chef/mixin/deep_merge'
+require "chef/mixin/deep_merge"
 
-require 'chef/role'
-require 'chef/rest'
+require "chef/role"
+require "chef/server_api"
+require "chef/json_compat"
 
 class Chef
   class RunList
@@ -44,7 +45,7 @@ class Chef
       attr_reader :missing_roles_with_including_role
 
       # The data source passed to the constructor. Not used in this class.
-      # In subclasses, this is a couchdb or Chef::REST object pre-configured
+      # In subclasses, this is a Chef::ServerAPI object pre-configured
       # to fetch roles from their correct location.
       attr_reader :source
 
@@ -54,7 +55,14 @@ class Chef
       # * Duplicate roles are not shown.
       attr_reader :run_list_trace
 
-      def initialize(environment, run_list_items, source=nil)
+      # Like run list trace but instead of saving the entries as strings it saves their objects
+      # The to_json method uses this list to construct json.
+      attr_reader :better_run_list_trace
+
+      attr_reader :all_missing_roles
+      attr_reader :role_errors
+
+      def initialize(environment, run_list_items, source = nil)
         @environment = environment
         @missing_roles_with_including_role = Array.new
 
@@ -67,7 +75,10 @@ class Chef
         @recipes = Chef::RunList::VersionedRecipeList.new
 
         @applied_roles = {}
-        @run_list_trace = Hash.new {|h, key| h[key] = [] }
+        @run_list_trace = Hash.new { |h, key| h[key] = [] }
+        @better_run_list_trace = Hash.new { |h, key| h[key] = [] }
+        @all_missing_roles = {}
+        @role_errors = {}
       end
 
       # Did we find any errors (expanding roles)?
@@ -124,11 +135,21 @@ class Chef
       def role_not_found(name, included_by)
         Chef::Log.error("Role #{name} (included by '#{included_by}') is in the runlist but does not exist. Skipping expand.")
         @missing_roles_with_including_role << [name, included_by]
+        @all_missing_roles[name] = true
         nil
       end
 
       def errors
-        @missing_roles_with_including_role.map {|item| item.first }
+        @missing_roles_with_including_role.map { |item| item.first }
+      end
+
+      def to_json(*a)
+        Chef::JSONCompat.to_json(to_hash, *a)
+      end
+
+      def to_hash
+        seen_items = { :recipe => {}, :role => {} }
+        { :id => @environment, :run_list => convert_run_list_trace("top level", seen_items) }
       end
 
       private
@@ -139,9 +160,10 @@ class Chef
         @applied_roles[role_name] = true
       end
 
-      def expand_run_list_items(items, included_by="top level")
+      def expand_run_list_items(items, included_by = "top level")
         if entry = items.shift
           @run_list_trace[included_by.to_s] << entry.to_s
+          @better_run_list_trace[included_by.to_s] << entry
 
           case entry.type
           when :recipe
@@ -156,6 +178,23 @@ class Chef
         end
       end
 
+      # Recursive helper to decode the non-nested hash form back into a tree
+      def convert_run_list_trace(base, seen_items)
+        @better_run_list_trace[base].map do |item|
+          skipped = seen_items[item.type][item.name]
+          seen_items[item.type][item.name] = true
+          case item.type
+            when :recipe
+              { :type => "recipe", :name => item.name, :version => item.version, :skipped => !!skipped }
+            when :role
+              error = @role_errors[item.name]
+              missing = @all_missing_roles[item.name]
+              { :type => :role, :name => item.name, :children => (missing || error || skipped) ? [] : convert_run_list_trace(item.to_s, seen_items),
+                :missing => missing, :error => error, :skipped => skipped }
+          end
+        end
+      end
+
     end
 
     # Expand a run list from disk. Suitable for chef-solo
@@ -173,18 +212,22 @@ class Chef
     class RunListExpansionFromAPI < RunListExpansion
 
       def rest
-        @rest ||= (source || Chef::REST.new(Chef::Config[:chef_server_url]))
+        @rest ||= (source || Chef::ServerAPI.new(Chef::Config[:chef_server_url]))
       end
 
       def fetch_role(name, included_by)
-        rest.get_rest("roles/#{name}")
+        Chef::Role.from_hash(rest.get("roles/#{name}"))
       rescue Net::HTTPServerException => e
         if e.message == '404 "Not Found"'
           role_not_found(name, included_by)
         else
           raise
         end
+      rescue Exception => e
+        @role_errors[name] = e.to_s
+        raise
       end
+
     end
 
   end
diff --git a/lib/chef/run_list/run_list_item.rb b/lib/chef/run_list/run_list_item.rb
index 43bb239..15e11b2 100644
--- a/lib/chef/run_list/run_list_item.rb
+++ b/lib/chef/run_list/run_list_item.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,16 +25,15 @@ class Chef
 
       attr_reader :name, :type, :version
 
-
       def initialize(item)
         @version = nil
         case item
         when Hash
           assert_hash_is_valid_run_list_item!(item)
-          @type = (item['type'] || item[:type]).to_sym
-          @name = item['name'] || item[:name]
-          if (item.has_key?('version') || item.has_key?(:version))
-            @version = item['version'] || item[:version]
+          @type = (item["type"] || item[:type]).to_sym
+          @name = item["name"] || item[:name]
+          if (item.has_key?("version") || item.has_key?(:version))
+            @version = item["version"] || item[:version]
           end
         when String
           if match = QUALIFIED_RECIPE.match(item)
@@ -69,7 +68,7 @@ class Chef
       end
 
       def to_s
-        "#{@type}[#{@name}#{@version ? "@#{@version}" :""}]"
+        "#{@type}[#{@name}#{@version ? "@#{@version}" : ""}]"
       end
 
       def role?
@@ -89,7 +88,7 @@ class Chef
       end
 
       def assert_hash_is_valid_run_list_item!(item)
-        unless (item.key?('type')|| item.key?(:type)) && (item.key?('name') || item.key?(:name))
+        unless (item.key?("type") || item.key?(:type)) && (item.key?("name") || item.key?(:name))
           raise ArgumentError, "Initializing a #{self.class} from a hash requires that it have a 'type' and 'name' key"
         end
       end
diff --git a/lib/chef/run_list/versioned_recipe_list.rb b/lib/chef/run_list/versioned_recipe_list.rb
index 0eefded..7845568 100644
--- a/lib/chef/run_list/versioned_recipe_list.rb
+++ b/lib/chef/run_list/versioned_recipe_list.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-require 'chef/version_class'
-require 'chef/version_constraint'
+require "chef/version_class"
+require "chef/version_constraint"
 
 # Why does this class exist?
 # Why did we not just modify RunList/RunListItem?
@@ -29,7 +29,7 @@ class Chef
         @versions = Hash.new
       end
 
-      def add_recipe(name, version=nil)
+      def add_recipe(name, version = nil)
         if version && @versions.has_key?(name)
           unless Chef::Version.new(@versions[name]) == Chef::Version.new(version)
             raise Chef::Exceptions::CookbookVersionConflict, "Run list requires #{name} at versions #{@versions[name]} and #{version}"
@@ -40,7 +40,7 @@ class Chef
       end
 
       def with_versions
-        self.map {|recipe_name| {:name => recipe_name, :version => @versions[recipe_name]}}
+        self.map { |recipe_name| { :name => recipe_name, :version => @versions[recipe_name] } }
       end
 
       # Return an Array of Hashes, each of the form:
@@ -63,6 +63,40 @@ class Chef
           end
         end
       end
+
+      # Get an array of strings of the fully-qualified recipe names (with ::default appended) and
+      # with the versions in "NAME at VERSION" format.
+      #
+      # @return [Array] Array of strings with fully-qualified recipe names
+      def with_fully_qualified_names_and_version_constraints
+        self.map do |recipe_name|
+          qualified_recipe = if recipe_name.include?("::")
+                               recipe_name
+                             else
+                               "#{recipe_name}::default"
+                             end
+
+          version = @versions[recipe_name]
+          qualified_recipe = "#{qualified_recipe}@#{version}" if version
+
+          qualified_recipe
+        end
+      end
+
+      # Get an array of strings of both fully-qualified and unexpanded recipe names
+      # in response to chef/chef#3767
+      # Chef-13 will revert to the behaviour of just including the fully-qualified name
+      #
+      # @return [Array] Array of strings with fully-qualified and unexpanded recipe names
+      def with_duplicate_names
+        self.map do |recipe_name|
+          if recipe_name.include?("::")
+            recipe_name
+          else
+            [recipe_name, "#{recipe_name}::default"]
+          end
+        end.flatten
+      end
     end
   end
 end
diff --git a/lib/chef/run_lock.rb b/lib/chef/run_lock.rb
index cefe637..be83494 100644
--- a/lib/chef/run_lock.rb
+++ b/lib/chef/run_lock.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/mixin/create_path'
-require 'fcntl'
+require "chef/mixin/create_path"
+require "fcntl"
 if Chef::Platform.windows?
-  require 'chef/win32/mutex'
+  require "chef/win32/mutex"
 end
-require 'chef/config'
-require 'chef/exceptions'
-require 'timeout'
+require "chef/config"
+require "chef/exceptions"
+require "timeout"
 
 class Chef
 
@@ -72,7 +72,7 @@ class Chef
               end
             end
           end
-        rescue Timeout::Error => e
+        rescue Timeout::Error
           exit_from_timeout
         end
       else
@@ -87,27 +87,8 @@ class Chef
     # Either acquire() or test() methods should be called in order to
     # get the ownership of run_lock.
     def test
-      # ensure the runlock_file path exists
-      create_path(File.dirname(runlock_file))
-      @runlock = File.open(runlock_file,'a+')
-
-      if Chef::Platform.windows?
-        acquire_win32_mutex
-      else
-        # If we support FD_CLOEXEC, then use it.
-        # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not
-        # ruby-1.8.7/1.9.3
-        if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
-          runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
-        end
-        # Flock will return 0 if it can acquire the lock otherwise it
-        # will return false
-        if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0
-          true
-        else
-          false
-        end
-      end
+      create_lock
+      acquire_lock
     end
 
     #
@@ -147,6 +128,34 @@ class Chef
       end
     end
 
+    # @api private solely for race condition tests
+    def create_lock
+      # ensure the runlock_file path exists
+      create_path(File.dirname(runlock_file))
+      @runlock = File.open(runlock_file, "a+")
+    end
+
+    # @api private solely for race condition tests
+    def acquire_lock
+      if Chef::Platform.windows?
+        acquire_win32_mutex
+      else
+        # If we support FD_CLOEXEC, then use it.
+        # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not
+        # ruby-1.8.7/1.9.3
+        if Fcntl.const_defined?("F_SETFD") && Fcntl.const_defined?("FD_CLOEXEC")
+          runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
+        end
+        # Flock will return 0 if it can acquire the lock otherwise it
+        # will return false
+        if runlock.flock(File::LOCK_NB | File::LOCK_EX) == 0
+          true
+        else
+          false
+        end
+      end
+    end
+
     private
 
     def reset
diff --git a/lib/chef/run_status.rb b/lib/chef/run_status.rb
index 0f18142..c3b7945 100644
--- a/lib/chef/run_status.rb
+++ b/lib/chef/run_status.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,15 +39,13 @@ class Chef::RunStatus
 
   attr_accessor :run_id
 
+  attr_accessor :node
+
   def initialize(node, events)
     @node = node
     @events = events
   end
 
-  def node
-    @node
-  end
-
   # sets +start_time+ to the current time.
   def start_clock
     @start_time = Time.now
@@ -115,7 +113,7 @@ class Chef::RunStatus
       :updated_resources => updated_resources,
       :exception => formatted_exception,
       :backtrace => backtrace,
-      :run_id => run_id}
+      :run_id => run_id }
   end
 
   # Returns a string of the format "ExceptionClass: message" or +nil+ if no
diff --git a/lib/chef/runner.rb b/lib/chef/runner.rb
index 6125fe5..ce12820 100644
--- a/lib/chef/runner.rb
+++ b/lib/chef/runner.rb
@@ -1,8 +1,8 @@
 #--
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/mixin/params_validate'
-require 'chef/node'
-require 'chef/resource_collection'
+require "chef/exceptions"
+require "chef/mixin/params_validate"
+require "chef/node"
+require "chef/resource_collection"
 
 class Chef
   # == Chef::Runner
@@ -45,7 +45,31 @@ class Chef
 
     # Determine the appropriate provider for the given resource, then
     # execute it.
-    def run_action(resource, action, notification_type=nil, notifying_resource=nil)
+    def run_action(resource, action, notification_type = nil, notifying_resource = nil)
+      # If there are any before notifications, why-run the resource
+      # and notify anyone who needs notifying
+      # TODO cheffish has a bug where it passes itself instead of the run_context to us, so doesn't have before_notifications. Fix there, update dependency requirement, and remove this if statement.
+      before_notifications = run_context.before_notifications(resource) if run_context.respond_to?(:before_notifications)
+      if before_notifications && !before_notifications.empty?
+        whyrun_before = Chef::Config[:why_run]
+        begin
+          Chef::Config[:why_run] = true
+          Chef::Log.info("#{resource} running why-run #{action} action to support before action")
+          resource.run_action(action, notification_type, notifying_resource)
+        ensure
+          Chef::Config[:why_run] = whyrun_before
+        end
+
+        if resource.updated_by_last_action?
+          before_notifications.each do |notification|
+            Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (before)")
+            run_action(notification.resource, notification.action, :before, resource)
+          end
+        end
+
+      end
+
+      # Actually run the action for realsies
       resource.run_action(action, notification_type, notifying_resource)
 
       # Execute any immediate and queue up any delayed notifications
@@ -78,7 +102,7 @@ class Chef
 
       # Execute each resource.
       run_context.resource_collection.execute_each_resource do |resource|
-        Array(resource.action).each {|action| run_action(resource, action)}
+        Array(resource.action).each { |action| run_action(resource, action) }
       end
 
     rescue Exception => e
@@ -92,7 +116,7 @@ class Chef
     private
 
     # Run all our :delayed actions
-    def run_delayed_notifications(error=nil)
+    def run_delayed_notifications(error = nil)
       collected_failures = Exceptions::MultipleFailures.new
       collected_failures.client_run_failure(error) unless error.nil?
       delayed_actions.each do |notification|
diff --git a/lib/chef/scan_access_control.rb b/lib/chef/scan_access_control.rb
index 01630a7..f55a106 100644
--- a/lib/chef/scan_access_control.rb
+++ b/lib/chef/scan_access_control.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -128,11 +128,11 @@ class Chef
 
     def stat
       @stat ||= if @new_resource.instance_of?(Chef::Resource::Link)
-        ::File.lstat(@new_resource.path)
-      else
-        realpath = ::File.realpath(@new_resource.path)
-        ::File.stat(realpath)
-      end
+                  ::File.lstat(@new_resource.path)
+                else
+                  realpath = ::File.realpath(@new_resource.path)
+                  ::File.stat(realpath)
+                end
     end
   end
 end
diff --git a/lib/chef/search/query.rb b/lib/chef/search/query.rb
index 6469a18..8a20516 100644
--- a/lib/chef/search/query.rb
+++ b/lib/chef/search/query.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/config'
-require 'chef/exceptions'
-require 'chef/rest'
+require "chef/config"
+require "chef/exceptions"
+require "chef/server_api"
 
-require 'uri'
+require "uri"
 
 class Chef
   class Search
@@ -29,18 +29,18 @@ class Chef
       attr_accessor :rest
       attr_reader :config
 
-      def initialize(url=nil, config:Chef::Config)
+      def initialize(url = nil, config:Chef::Config)
         @config = config
         @url = url
       end
 
       def rest
-        @rest ||= Chef::REST.new(@url || @config[:chef_server_url])
+        @rest ||= Chef::ServerAPI.new(@url || @config[:chef_server_url])
       end
 
       # Backwards compatability for cookbooks.
       # This can be removed in Chef > 12.
-      def partial_search(type, query='*:*', *args, &block)
+      def partial_search(type, query = "*:*", *args, &block)
         Chef::Log.warn(<<-WARNDEP)
 DEPRECATED: The 'partial_search' API is deprecated and will be removed in
 future releases. Please use 'search' with a :filter_result argument to get
@@ -80,7 +80,7 @@ WARNDEP
       # an example of the returned json may be:
       # {"ip_address":"127.0.0.1", "ruby_version": "1.9.3"}
       #
-      def search(type, query='*:*', *args, &block)
+      def search(type, query = "*:*", *args, &block)
         validate_type(type)
 
         args_h = hashify_args(*args)
@@ -88,8 +88,21 @@ WARNDEP
 
         if block
           response["rows"].each { |row| block.call(row) if row }
-          unless (response["start"] + response["rows"].length) >= response["total"]
-            args_h[:start] = response["start"] + response["rows"].length
+          #
+          # args_h[:rows] and args_h[:start] are the page size and
+          # start position requested of the search index backing the
+          # search API.
+          #
+          # The response may contain fewer rows than arg_h[:rows] if
+          # the page of index results included deleted nodes which
+          # have been filtered from the returned data. In this case,
+          # we still want to start the next page at start +
+          # args_h[:rows] to avoid asking the search backend for
+          # overlapping pages (which could result in duplicates).
+          #
+          next_start = response["start"] + (args_h[:rows] || response["rows"].length)
+          unless next_start >= response["total"]
+            args_h[:start] = next_start
             search(type, query, args_h, &block)
           end
           true
@@ -99,11 +112,12 @@ WARNDEP
       end
 
       private
+
       def validate_type(t)
         unless t.kind_of?(String) || t.kind_of?(Symbol)
           msg = "Invalid search object type #{t.inspect} (#{t.class}), must be a String or Symbol." +
-          "Usage: search(:node, QUERY[, OPTIONAL_ARGS])" +
-          "        `knife search environment QUERY (options)`"
+                "Usage: search(:node, QUERY[, OPTIONAL_ARGS])" +
+                "        `knife search environment QUERY (options)`"
           raise Chef::Exceptions::InvalidSearchQuery, msg
         end
       end
@@ -132,16 +146,30 @@ WARNDEP
         qstr
       end
 
-      def call_rest_service(type, query:'*:*', rows:nil, start:0, sort:'X_CHEF_id_CHEF_X asc', filter_result:nil)
+      def call_rest_service(type, query:"*:*", rows:nil, start:0, sort:"X_CHEF_id_CHEF_X asc", filter_result:nil)
         query_string = create_query_string(type, query, rows, start, sort)
 
         if filter_result
-          response = rest.post_rest(query_string, filter_result)
+          response = rest.post(query_string, filter_result)
           # response returns rows in the format of
           # { "url" => url_to_node, "data" => filter_result_hash }
-          response['rows'].map! { |row| row['data'] }
+          response["rows"].map! { |row| row["data"] }
         else
-          response = rest.get_rest(query_string)
+          response = rest.get(query_string)
+          response["rows"].map! do |row|
+            case type.to_s
+            when "node"
+              Chef::Node.from_hash(row)
+            when "role"
+              Chef::Role.from_hash(row)
+            when "environment"
+              Chef::Environment.from_hash(row)
+            when "client"
+              Chef::ApiClient.from_hash(row)
+            else
+              Chef::DataBagItem.from_hash(row)
+            end
+          end
         end
 
         response
diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb
index ec4a864..cad8586 100644
--- a/lib/chef/server_api.rb
+++ b/lib/chef/server_api.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,14 @@
 # limitations under the License.
 #
 
-require 'chef/http'
-require 'chef/http/authenticator'
-require 'chef/http/cookie_manager'
-require 'chef/http/decompressor'
-require 'chef/http/json_input'
-require 'chef/http/json_output'
-require 'chef/http/remote_request_id'
+require "chef/http"
+require "chef/http/authenticator"
+require "chef/http/cookie_manager"
+require "chef/http/decompressor"
+require "chef/http/json_input"
+require "chef/http/json_output"
+require "chef/http/remote_request_id"
+require "chef/http/validate_content_length"
 
 class Chef
   class ServerAPI < Chef::HTTP
@@ -31,6 +32,7 @@ class Chef
       options[:client_name] ||= Chef::Config[:node_name]
       options[:signing_key_filename] ||= Chef::Config[:client_key]
       options[:signing_key_filename] = nil if chef_zero_uri?(url)
+      options[:inflate_json_class] = false
       super(url, options)
     end
 
@@ -40,5 +42,37 @@ class Chef
     use Chef::HTTP::Decompressor
     use Chef::HTTP::Authenticator
     use Chef::HTTP::RemoteRequestID
+
+    # ValidateContentLength should come after Decompressor
+    # because the order of middlewares is reversed when handling
+    # responses.
+    use Chef::HTTP::ValidateContentLength
+
+    # for back compat with Chef::REST, expose `<verb>_rest` as an alias to `<verb>`
+    alias :get_rest :get
+    alias :delete_rest :delete
+    alias :post_rest :post
+    alias :put_rest :put
+
+    # Makes an HTTP request to +path+ with the given +method+, +headers+, and
+    # +data+ (if applicable). Does not apply any middleware, besides that
+    # needed for Authentication.
+    def raw_request(method, path, headers = {}, data = false)
+      url = create_url(path)
+      method, url, headers, data = Chef::HTTP::Authenticator.new(options).handle_request(method, url, headers, data)
+      method, url, headers, data = Chef::HTTP::RemoteRequestID.new(options).handle_request(method, url, headers, data)
+      response, rest_request, return_value = send_http_request(method, url, headers, data)
+      response.error! unless success_response?(response)
+      return_value
+    rescue Exception => exception
+      log_failed_request(response, return_value) unless response.nil?
+
+      if exception.respond_to?(:chef_rest_request=)
+        exception.chef_rest_request = rest_request
+      end
+      raise
+    end
   end
 end
+
+require "chef/config"
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index ee4fe78..72081b1 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,21 +15,21 @@
 # limitations under the License.
 #
 
-require 'singleton'
-require 'pp'
-require 'etc'
-require 'mixlib/cli'
+require "singleton"
+require "pp"
+require "etc"
+require "mixlib/cli"
 
-require 'chef'
-require 'chef/version'
-require 'chef/client'
-require 'chef/config'
-require 'chef/config_fetcher'
+require "chef"
+require "chef/version"
+require "chef/client"
+require "chef/config"
+require "chef/config_fetcher"
 
-require 'chef/shell/shell_session'
-require 'chef/shell/ext'
-require 'chef/json_compat'
-require 'chef/util/path_helper'
+require "chef/shell/shell_session"
+require "chef/shell/ext"
+require "chef/json_compat"
+require "chef/util/path_helper"
 
 # = Shell
 # Shell is Chef in an IRB session. Shell can interact with a Chef server via the
@@ -64,7 +64,6 @@ module Shell
 
     init(irb.context.main)
 
-
     irb_conf[:IRB_RC].call(irb.context) if irb_conf[:IRB_RC]
     irb_conf[:MAIN_CONTEXT] = irb.context
 
@@ -110,7 +109,7 @@ module Shell
 
       conf.prompt_c       = "chef#{leader(m)} > "
       conf.return_format  = " => %s \n"
-      conf.prompt_i       = "chef#{leader(m)} > "
+      conf.prompt_i       = "chef#{leader(m)} (#{Chef::VERSION})> "
       conf.prompt_n       = "chef#{leader(m)} ?> "
       conf.prompt_s       = "chef#{leader(m)}%l> "
       conf.use_tracer     = false
@@ -180,13 +179,13 @@ module Shell
   end
 
   def self.editor
-    @editor || Chef::Config[:editor] || ENV['EDITOR']
+    @editor || Chef::Config[:editor] || ENV["EDITOR"]
   end
 
   class Options
     include Mixlib::CLI
 
-    def self.footer(text=nil)
+    def self.footer(text = nil)
       @footer = text if text
       @footer
     end
@@ -216,7 +215,7 @@ FOOTER
 
     option :log_level,
       :short  => "-l LOG_LEVEL",
-      :long   => '--log-level LOG_LEVEL',
+      :long   => "--log-level LOG_LEVEL",
       :description => "Set the logging level",
       :proc         => proc { |level| Chef::Config.log_level = level.to_sym; Shell.setup_logger }
 
@@ -232,7 +231,7 @@ FOOTER
       :long         => "--solo",
       :description  => "chef-solo session",
       :boolean      => true,
-      :proc         => proc {Chef::Config[:solo] = true}
+      :proc         => proc { Chef::Config[:solo] = true }
 
     option :client,
       :short        => "-z",
@@ -257,14 +256,14 @@ FOOTER
       :long         => "--version",
       :description  => "Show chef version",
       :boolean      => true,
-      :proc         => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+      :proc         => lambda { |v| puts "Chef: #{::Chef::VERSION}" },
       :exit         => 0
 
     option :override_runlist,
       :short        => "-o RunlistItem,RunlistItem...",
       :long         => "--override-runlist RunlistItem,RunlistItem...",
       :description  => "Replace current run list with specified items",
-      :proc         => lambda { |items| items.split(',').map { |item| Chef::RunList::RunListItem.new(item) }}
+      :proc         => lambda { |items| items.split(",").map { |item| Chef::RunList::RunListItem.new(item) } }
 
     def self.print_help
       instance = new
@@ -296,19 +295,19 @@ FOOTER
     private
 
     def config_file_for_shell_mode(environment)
-      dot_chef_dir = Chef::Util::PathHelper.home('.chef')
+      dot_chef_dir = Chef::Util::PathHelper.home(".chef")
       if config[:config_file]
         config[:config_file]
       elsif environment
         Shell.env = environment
-        config_file_to_try = ::File.join(dot_chef_dir, environment, 'chef_shell.rb')
+        config_file_to_try = ::File.join(dot_chef_dir, environment, "chef_shell.rb")
         unless ::File.exist?(config_file_to_try)
           puts "could not find chef-shell config for environment #{environment} at #{config_file_to_try}"
           exit 1
         end
         config_file_to_try
-      elsif dot_chef_dir && ::File.exist?(File.join(dot_chef_dir, 'chef_shell.rb'))
-        File.join(dot_chef_dir, 'chef_shell.rb')
+      elsif dot_chef_dir && ::File.exist?(File.join(dot_chef_dir, "chef_shell.rb"))
+        File.join(dot_chef_dir, "chef_shell.rb")
       elsif config[:solo]
         Chef::Config.platform_specific_path("/etc/chef/solo.rb")
       elsif config[:client]
diff --git a/lib/chef/shell/ext.rb b/lib/chef/shell/ext.rb
index d516524..83863b1 100644
--- a/lib/chef/shell/ext.rb
+++ b/lib/chef/shell/ext.rb
@@ -1,6 +1,6 @@
 #--
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'chef/recipe'
-require 'fileutils'
-require 'chef/dsl/platform_introspection'
-require 'chef/version'
-require 'chef/shell/shell_session'
-require 'chef/shell/model_wrapper'
-require 'chef/shell/shell_rest'
-require 'chef/json_compat'
+require "tempfile"
+require "chef/recipe"
+require "fileutils"
+require "chef/dsl/platform_introspection"
+require "chef/version"
+require "chef/shell/shell_session"
+require "chef/shell/model_wrapper"
+require "chef/server_api"
+require "chef/json_compat"
 
 module Shell
   module Extensions
@@ -40,17 +40,17 @@ module Shell
         # so these methods need to be defined at the latest possible time.
         unless jobs.respond_to?(:select_session_by_context)
           def jobs.select_session_by_context(&block)
-            @jobs.select { |job| block.call(job[1].context.main)}
+            @jobs.select { |job| block.call(job[1].context.main) }
           end
         end
 
         unless jobs.respond_to?(:session_select)
           def jobs.select_shell_session(target_context)
             session = if target_context.kind_of?(Class)
-              select_session_by_context { |main| main.kind_of?(target_context) }
-            else
-              select_session_by_context { |main| main.equal?(target_context) }
-            end
+                        select_session_by_context { |main| main.kind_of?(target_context) }
+                      else
+                        select_session_by_context { |main| main.equal?(target_context) }
+                      end
             Array(session.first)[1]
           end
         end
@@ -125,7 +125,7 @@ module Shell
         @explain = explain_text
       end
 
-      def subcommands(subcommand_help={})
+      def subcommands(subcommand_help = {})
         @subcommand_help = subcommand_help
       end
 
@@ -196,8 +196,8 @@ module Shell
   chef-shell commands. When called with an argument COMMAND, +help+
   prints a detailed explanation of the command if available, or the
   description if no explanation is available.
-E
-      def help(commmand=nil)
+      E
+      def help(commmand = nil)
         if commmand
           explain_command(commmand)
         else
@@ -209,10 +209,10 @@ E
 
       desc "prints information about chef"
       def version
-        puts  "This is the chef-shell.\n" +
-              " Chef Version: #{::Chef::VERSION}\n" +
-              " http://www.chef.io/\n" +
-              " http://docs.chef.io/"
+        puts "This is the chef-shell.\n" +
+             " Chef Version: #{::Chef::VERSION}\n" +
+             " http://www.chef.io/\n" +
+             " http://docs.chef.io/"
         :ucanhaz_automation
       end
       alias :shell :version
@@ -295,7 +295,7 @@ E
       end
 
       desc "pretty print the node's attributes"
-      def ohai(key=nil)
+      def ohai(key = nil)
         pp(key ? node.attribute[key] : node.attribute)
       end
     end
@@ -314,7 +314,7 @@ E
   1. Looks for an EDITOR set by Shell.editor = "EDITOR"
   2. Looks for an EDITOR configured in your chef-shell config file
   3. Uses the value of the EDITOR environment variable
-E
+      E
       def edit(object)
         unless Shell.editor
           puts "Please set your editor with Shell.editor = \"vim|emacs|mate|ed\""
@@ -331,7 +331,7 @@ E
         edited_data = Tempfile.open([filename, ".js"]) do |tempfile|
           tempfile.sync = true
           tempfile.puts Chef::JSONCompat.to_json(object)
-          system("#{Shell.editor.to_s} #{tempfile.path}")
+          system("#{Shell.editor} #{tempfile.path}")
           tempfile.rewind
           tempfile.read
         end
@@ -392,7 +392,7 @@ E
       end
 
   This will strip the admin privileges from any client named after borat.
-E
+      E
       subcommands :all        => "list all api clients",
                   :show       => "load an api client by name",
                   :search     => "search for API clients",
@@ -454,7 +454,7 @@ E
       end
 
   This will assign the attribute to every node with a FQDN matching the regex.
-E
+      E
       subcommands :all        => "list all nodes",
                   :show       => "load a node by name",
                   :search     => "search for nodes",
@@ -476,7 +476,7 @@ E
 
 ## SEE ALSO ##
   See the help for +nodes+ for more information about the subcommands.
-E
+      E
       subcommands :all        => "list all roles",
                   :show       => "load a role by name",
                   :search     => "search for roles",
@@ -502,7 +502,7 @@ E
 ## SEE ALSO ##
   See the help for +nodes+ for more information about the subcommands.
 
-E
+      E
       subcommands :all        => "list all items in the data bag",
                   :show       => "load a data bag item by id",
                   :search     => "search for items in the data bag",
@@ -525,7 +525,7 @@ E
 
 ## SEE ALSO ##
   See the help for +nodes+ for more information about the subcommands.
-E
+      E
       subcommands :all        => "list all environments",
                   :show       => "load an environment by name",
                   :search     => "search for environments",
@@ -536,7 +536,7 @@ E
 
       desc "A REST Client configured to authenticate with the API"
       def api
-        @rest = Shell::ShellREST.new(Chef::Config[:chef_server_url])
+        @rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url])
       end
 
     end
diff --git a/lib/chef/shell/model_wrapper.rb b/lib/chef/shell/model_wrapper.rb
index 7ee39de..403f947 100644
--- a/lib/chef/shell/model_wrapper.rb
+++ b/lib/chef/shell/model_wrapper.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/mixin/convert_to_class_name'
-require 'chef/mixin/language'
+require "chef/mixin/convert_to_class_name"
+require "chef/mixin/language"
 
 module Shell
   class ModelWrapper
@@ -26,7 +26,7 @@ module Shell
 
     attr_reader :model_symbol
 
-    def initialize(model_class, symbol=nil)
+    def initialize(model_class, symbol = nil)
       @model_class = model_class
       @model_symbol = symbol || convert_to_snake_case(model_class.name, "Chef").to_sym
     end
@@ -79,8 +79,8 @@ module Shell
     # paper over inconsistencies in the model classes APIs, and return the objects
     # the user wanted instead of the URI=>object stuff
     def list_objects
-      objects = @model_class.method(:list).arity == 0? @model_class.list : @model_class.list(true)
-      objects.map { |obj| Array(obj).find {|o| o.kind_of?(@model_class)} }
+      objects = @model_class.method(:list).arity == 0 ? @model_class.list : @model_class.list(true)
+      objects.map { |obj| Array(obj).find { |o| o.kind_of?(@model_class) } }
     end
 
     def format_query(query)
@@ -98,7 +98,6 @@ module Shell
       @model_symbol = @databag_name = databag_name
     end
 
-
     alias :list :all
 
     def show(item)
diff --git a/lib/chef/shell/shell_rest.rb b/lib/chef/shell/shell_rest.rb
deleted file mode 100644
index a485a0a..0000000
--- a/lib/chef/shell/shell_rest.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-#--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-module Shell
-  class ShellREST < Chef::REST
-
-    alias :get    :get_rest
-    alias :put    :put_rest
-    alias :post   :post_rest
-    alias :delete :delete_rest
-
-  end
-end
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index 73e6c34..6d8b6f1 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -1,8 +1,8 @@
 #--
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,22 +18,22 @@
 # limitations under the License.
 #
 
-require 'chef/recipe'
-require 'chef/run_context'
-require 'chef/config'
-require 'chef/client'
-require 'chef/cookbook/cookbook_collection'
-require 'chef/cookbook_loader'
-require 'chef/run_list/run_list_expansion'
-require 'chef/formatters/base'
-require 'chef/formatters/doc'
-require 'chef/formatters/minimal'
+require "chef/recipe"
+require "chef/run_context"
+require "chef/config"
+require "chef/client"
+require "chef/cookbook/cookbook_collection"
+require "chef/cookbook_loader"
+require "chef/run_list/run_list_expansion"
+require "chef/formatters/base"
+require "chef/formatters/doc"
+require "chef/formatters/minimal"
 
 module Shell
   class ShellSession
     include Singleton
 
-    def self.session_type(type=nil)
+    def self.session_type(type = nil)
       @session_type = type if type
       @session_type
     end
@@ -201,7 +201,7 @@ module Shell
 
     def rebuild_context
       @run_status = Chef::RunStatus.new(@node, @events)
-      Chef::Cookbook::FileVendor.fetch_from_remote(Chef::REST.new(Chef::Config[:chef_server_url]))
+      Chef::Cookbook::FileVendor.fetch_from_remote(Chef::ServerAPI.new(Chef::Config[:chef_server_url]))
       cookbook_hash = @client.sync_cookbooks
       cookbook_collection = Chef::CookbookCollection.new(cookbook_hash)
       @run_context = Chef::RunContext.new(node, cookbook_collection, @events)
@@ -235,7 +235,7 @@ module Shell
     # Run the very smallest amount of ohai we can get away with and still
     # hope to have things work. Otherwise we're not very good doppelgangers
     def run_ohai
-      @ohai.require_plugin('os')
+      @ohai.require_plugin("os")
     end
 
     # DoppelGanger implementation of build_node. preserves as many of the node's
@@ -244,8 +244,8 @@ module Shell
       Chef::Log.debug("Building node object for #{@node_name}")
       @node = Chef::Node.find_or_create(node_name)
       ohai_data = @ohai.data.merge(@node.automatic_attrs)
-      @node.consume_external_attrs(ohai_data,nil)
-      @run_list_expansion = @node.expand!('server')
+      @node.consume_external_attrs(ohai_data, nil)
+      @run_list_expansion = @node.expand!("server")
       @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings
       Chef::Log.info("Run List is [#{@node.run_list}]")
       Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]")
@@ -253,7 +253,8 @@ module Shell
     end
 
     def register
-      @rest = Chef::REST.new(Chef::Config[:chef_server_url], Chef::Config[:node_name], Chef::Config[:client_key])
+      @rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url], :client_name => Chef::Config[:node_name],
+                                                                  :signing_key_filename => Chef::Config[:client_key])
     end
 
   end
diff --git a/lib/chef/shell_out.rb b/lib/chef/shell_out.rb
index 3febe36..54ff718 100644
--- a/lib/chef/shell_out.rb
+++ b/lib/chef/shell_out.rb
@@ -1,11 +1,11 @@
-require 'mixlib/shellout'
+require "mixlib/shellout"
 
 class Chef
   class ShellOut < Mixlib::ShellOut
 
     def initialize(*args)
       Chef::Log.warn("Chef::ShellOut is deprecated, please use Mixlib::ShellOut")
-      called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << "  #{trace_line}\n" }
+      called_from = caller[0..3].inject("Called from:\n") { |msg, trace_line| msg << "  #{trace_line}\n" }
       Chef::Log.warn(called_from)
       super
     end
diff --git a/lib/chef/tasks/chef_repo.rake b/lib/chef/tasks/chef_repo.rake
index 14a5bcc..543bd8d 100644
--- a/lib/chef/tasks/chef_repo.rake
+++ b/lib/chef/tasks/chef_repo.rake
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2014, Chef Software, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-TOPDIR = '.'
-require 'rake'
+TOPDIR = "."
+require "rake"
 
 desc "By default, print deprecation notice"
 task :default do
@@ -27,37 +27,37 @@ end
 desc "Install the latest copy of the repository on this Chef Server"
 task :install do
   puts deprecation_notice
-  puts 'The `install` rake task, which included the `update`, `roles`, and'
-  puts '`upload_cookbooks` rake tasks is replaced by the `knife upload`'
+  puts "The `install` rake task, which included the `update`, `roles`, and"
+  puts "`upload_cookbooks` rake tasks is replaced by the `knife upload`"
   puts 'sub-command. The notion of "installing" the chef-repo to the Chef'
-  puts 'Server. Previously the `install` task would manage server and'
-  puts 'client configuration. This will not work at all on Chef Server 11+'
-  puts 'and client configuration should be managed with the `chef-client`'
-  puts 'cookbook.'
+  puts "Server. Previously the `install` task would manage server and"
+  puts "client configuration. This will not work at all on Chef Server 11+"
+  puts "and client configuration should be managed with the `chef-client`"
+  puts "cookbook."
 end
 
 desc "Update your repository from source control"
 task :update do
   puts deprecation_notice
-  puts 'The `update` rake task previously updated the chef-repo from'
-  puts 'the detected version control system, either svn or git. However,'
-  puts 'it has not been recommended for users for years. Most users in'
-  puts 'the community use `git`, so the Subversion functionality is not'
-  puts 'required, and `git pull` is sufficient for many workflows. The'
-  puts 'world of git workflows is rather different now than it was when'
-  puts 'this rake task was created.'
+  puts "The `update` rake task previously updated the chef-repo from"
+  puts "the detected version control system, either svn or git. However,"
+  puts "it has not been recommended for users for years. Most users in"
+  puts "the community use `git`, so the Subversion functionality is not"
+  puts "required, and `git pull` is sufficient for many workflows. The"
+  puts "world of git workflows is rather different now than it was when"
+  puts "this rake task was created."
 end
 
 desc "Create a new cookbook (with COOKBOOK=name, optional CB_PREFIX=site-)"
 task :new_cookbook do
-  cb = ENV['COOKBOOK'] || 'my_cookbook_name'
+  cb = ENV["COOKBOOK"] || "my_cookbook_name"
   puts deprecation_notice
-  puts 'The `new_cookbook` rake task is replaced by the ChefDK cookbook'
-  puts 'generator. To generate a new cookbook run:'
+  puts "The `new_cookbook` rake task is replaced by the ChefDK cookbook"
+  puts "generator. To generate a new cookbook run:"
   puts
   puts "chef generate cookbook #{ENV['COOKBOOK']}"
   puts
-  puts 'Or, if you are not using ChefDK, use `knife cookbook create`:'
+  puts "Or, if you are not using ChefDK, use `knife cookbook create`:"
   puts
   puts "knife cookbook create #{ENV['COOKBOOK']}"
 end
@@ -65,46 +65,46 @@ end
 desc "Create a new self-signed SSL certificate for FQDN=foo.example.com"
 task :ssl_cert do
   puts deprecation_notice
-  puts 'The `ssl_cert` rake task is superseded by using the CHEF-maintained'
+  puts "The `ssl_cert` rake task is superseded by using the CHEF-maintained"
   puts '`openssl` cookbook\'s `openssl_x509` resource which can generate'
-  puts 'self-signed certificate chains as convergent resources.'
+  puts "self-signed certificate chains as convergent resources."
   puts
-  puts 'https://supermarket.getchef.com/cookbooks/openssl'
+  puts "https://supermarket.getchef.com/cookbooks/openssl"
 end
 
 desc "Build cookbook metadata.json from metadata.rb"
 task :metadata do
   puts deprecation_notice
-  puts 'The `metadata` rake task is not recommended. Cookbook'
-  puts '`metadata.json` is automatically generated from `metadata.rb`'
-  puts 'by `knife` when uploading cookbooks to the Chef Server.'
+  puts "The `metadata` rake task is not recommended. Cookbook"
+  puts "`metadata.json` is automatically generated from `metadata.rb`"
+  puts "by `knife` when uploading cookbooks to the Chef Server."
 end
 
 desc "Update roles"
 task :roles do
   puts deprecation_notice
-  puts 'The `roles` rake task is not recommended. If you are using Ruby'
-  puts 'role files (roles/*.rb), you can upload them all with:'
+  puts "The `roles` rake task is not recommended. If you are using Ruby"
+  puts "role files (roles/*.rb), you can upload them all with:"
   puts
-  puts 'knife role from file roles/*'
+  puts "knife role from file roles/*"
   puts
-  puts 'If you are using JSON role files (roles/*.json), you can upload'
-  puts 'them all with:'
+  puts "If you are using JSON role files (roles/*.json), you can upload"
+  puts "them all with:"
   puts
-  puts 'knife upload roles/*.json'
+  puts "knife upload roles/*.json"
 end
 
 desc "Update a specific role"
 task :role do
   puts deprecation_notice
-  puts 'The `role` rake task is not recommended. If you are using Ruby'
-  puts 'role files, you can upload a single role with:'
+  puts "The `role` rake task is not recommended. If you are using Ruby"
+  puts "role files, you can upload a single role with:"
   puts
-  puts 'knife role from file rolename.rb'
+  puts "knife role from file rolename.rb"
   puts
-  puts 'If you are using JSON role files, you can upload a single role with'
+  puts "If you are using JSON role files, you can upload a single role with"
   puts
-  puts 'knife upload roles/rolename.json'
+  puts "knife upload roles/rolename.json"
 end
 
 desc "Upload all cookbooks"
@@ -122,18 +122,18 @@ end
 desc "Test all cookbooks"
 task :test_cookbooks do
   puts deprecation_notice
-  puts 'The `test_cookbooks` rake task is no longer recommended. Previously'
-  puts 'it only performed a syntax check, and did no other kind of testing,'
-  puts 'and the Chef Community has a rich ecosystem of testing tools for'
-  puts 'various purposes:'
+  puts "The `test_cookbooks` rake task is no longer recommended. Previously"
+  puts "it only performed a syntax check, and did no other kind of testing,"
+  puts "and the Chef Community has a rich ecosystem of testing tools for"
+  puts "various purposes:"
   puts
-  puts '- knife cookbook test will perform a syntax check, as this task did'
-  puts '  before.'
-  puts '- rubocop and foodcritic will perform lint checking for Ruby and'
-  puts '  Chef cookbook style according to community standards.'
-  puts '- ChefSpec will perform unit testing'
-  puts '- Test Kitchen will perform convergence and post-convergence'
-  puts '  testing on virtual machines.'
+  puts "- knife cookbook test will perform a syntax check, as this task did"
+  puts "  before."
+  puts "- rubocop and foodcritic will perform lint checking for Ruby and"
+  puts "  Chef cookbook style according to community standards."
+  puts "- ChefSpec will perform unit testing"
+  puts "- Test Kitchen will perform convergence and post-convergence"
+  puts "  testing on virtual machines."
 end
 
 desc "Test a single cookbook"
@@ -143,19 +143,19 @@ namespace :databag do
   desc "Upload a single databag"
   task :upload do
     puts deprecation_notice
-    puts 'The `data_bags:upload` task is not recommended. You should use'
-    puts 'the `knife upload` sub-command for uploading data bag items.'
+    puts "The `data_bags:upload` task is not recommended. You should use"
+    puts "the `knife upload` sub-command for uploading data bag items."
     puts
-    puts 'knife upload data_bags/bagname/itemname.json'
+    puts "knife upload data_bags/bagname/itemname.json"
   end
 
   desc "Upload all databags"
   task :upload_all do
     puts deprecation_notice
-    puts 'The `data_bags:upload_all` task is not recommended. You should'
-    puts 'use the `knife upload` sub-command for uploading data bag items.'
+    puts "The `data_bags:upload_all` task is not recommended. You should"
+    puts "use the `knife upload` sub-command for uploading data bag items."
     puts
-    puts 'knife upload data_bags/*'
+    puts "knife upload data_bags/*"
   end
 
   desc "Create a databag"
@@ -172,23 +172,22 @@ namespace :databag do
 end
 
 def deprecation_notice
-  %Q[*************************************************
+  %Q{*************************************************
 NOTICE: Chef Repository Rake Tasks Are Deprecated
 *************************************************
-]
-
+}
 end
 
 def deprecated_cookbook_upload
-  %Q[
+  %Q{
 The `upload_cookbook` and `upload_cookbooks` rake tasks are not
 recommended. These tasks are replaced by other, better workflow
 tools, such as `knife cookbook upload`, `knife upload`, or `berks`
-]
+}
 end
 
 def deprecated_data_bag_creation
-  %Q[
+  %Q{
 The `data_bags:create` and `data_bags:create_item` tasks are not
 recommended. You should create data bag items as JSON files in the data_bags
 directory, with a sub-directory for each bag, and use `knife upload` to
@@ -197,5 +196,5 @@ upload them. For example, if you have a data bags named `users`, with
 
 ./data_bags/users/finn.json
 ./data-bags/users/jake.json
-]
+}
 end
diff --git a/lib/chef/user.rb b/lib/chef/user.rb
index 42fa6b5..a6fc216 100644
--- a/lib/chef/user.rb
+++ b/lib/chef/user.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (steve at opscode.com)
-# Copyright:: Copyright 2012 Opscode, Inc.
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +15,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/config'
-require 'chef/mixin/params_validate'
-require 'chef/mixin/from_file'
-require 'chef/mash'
-require 'chef/json_compat'
-require 'chef/search/query'
-
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/server_api"
+
+# TODO
+# DEPRECATION NOTE
+# This class will be replaced by Chef::UserV1 in Chef 13. It is the code to support the User object
+# corrosponding to the Open Source Chef Server 11 and only still exists to support
+# users still on OSC 11.
+#
+# Chef::UserV1 now supports Chef Server 12 and will be moved to this namespace in Chef 13.
+#
+# New development should occur in Chef::UserV1.
+# This file and corrosponding osc_user knife files
+# should be removed once client support for Open Source Chef Server 11 expires.
 class Chef
   class User
 
@@ -29,34 +41,38 @@ class Chef
     include Chef::Mixin::ParamsValidate
 
     def initialize
-      @name = ''
+      @name = ""
       @public_key = nil
       @private_key = nil
       @password = nil
       @admin = false
     end
 
-    def name(arg=nil)
+    def chef_rest_v0
+      @chef_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
+    end
+
+    def name(arg = nil)
       set_or_return(:name, arg,
                     :regex => /^[a-z0-9\-_]+$/)
     end
 
-    def admin(arg=nil)
+    def admin(arg = nil)
       set_or_return(:admin,
                     arg, :kind_of => [TrueClass, FalseClass])
     end
 
-    def public_key(arg=nil)
+    def public_key(arg = nil)
       set_or_return(:public_key,
                     arg, :kind_of => String)
     end
 
-    def private_key(arg=nil)
+    def private_key(arg = nil)
       set_or_return(:private_key,
                     arg, :kind_of => String)
     end
 
-    def password(arg=nil)
+    def password(arg = nil)
       set_or_return(:password,
                     arg, :kind_of => String)
     end
@@ -65,7 +81,7 @@ class Chef
       result = {
         "name" => @name,
         "public_key" => @public_key,
-        "admin" => @admin
+        "admin" => @admin,
       }
       result["private_key"] = @private_key if @private_key
       result["password"] = @password if @password
@@ -77,25 +93,25 @@ class Chef
     end
 
     def destroy
-      Chef::REST.new(Chef::Config[:chef_server_url]).delete_rest("users/#{@name}")
+      chef_rest_v0.delete("users/#{@name}")
     end
 
     def create
-      payload = {:name => self.name, :admin => self.admin, :password => self.password }
+      payload = { :name => self.name, :admin => self.admin, :password => self.password }
       payload[:public_key] = public_key if public_key
-      new_user =Chef::REST.new(Chef::Config[:chef_server_url]).post_rest("users", payload)
+      new_user = chef_rest_v0.post("users", payload)
       Chef::User.from_hash(self.to_hash.merge(new_user))
     end
 
-    def update(new_key=false)
-      payload = {:name => name, :admin => admin}
+    def update(new_key = false)
+      payload = { :name => name, :admin => admin }
       payload[:private_key] = new_key if new_key
       payload[:password] = password if password
-      updated_user = Chef::REST.new(Chef::Config[:chef_server_url]).put_rest("users/#{name}", payload)
+      updated_user = chef_rest_v0.put("users/#{name}", payload)
       Chef::User.from_hash(self.to_hash.merge(updated_user))
     end
 
-    def save(new_key=false)
+    def save(new_key = false)
       begin
         create
       rescue Net::HTTPServerException => e
@@ -108,8 +124,7 @@ class Chef
     end
 
     def reregister
-      r = Chef::REST.new(Chef::Config[:chef_server_url])
-      reregistered_self = r.put_rest("users/#{name}", { :name => name, :admin => admin, :private_key => true })
+      reregistered_self = chef_rest_v0.put("users/#{name}", { :name => name, :admin => admin, :private_key => true })
       private_key(reregistered_self["private_key"])
       self
     end
@@ -120,18 +135,18 @@ class Chef
 
     def inspect
       "Chef::User name:'#{name}' admin:'#{admin.inspect}'" +
-      "public_key:'#{public_key}' private_key:#{private_key}"
+        "public_key:'#{public_key}' private_key:#{private_key}"
     end
 
     # Class Methods
 
     def self.from_hash(user_hash)
       user = Chef::User.new
-      user.name user_hash['name']
-      user.private_key user_hash['private_key'] if user_hash.key?('private_key')
-      user.password user_hash['password'] if user_hash.key?('password')
-      user.public_key user_hash['public_key']
-      user.admin user_hash['admin']
+      user.name user_hash["name"]
+      user.private_key user_hash["private_key"] if user_hash.key?("private_key")
+      user.password user_hash["password"] if user_hash.key?("password")
+      user.public_key user_hash["public_key"]
+      user.admin user_hash["admin"]
       user
     end
 
@@ -139,17 +154,18 @@ class Chef
       Chef::User.from_hash(Chef::JSONCompat.from_json(json))
     end
 
-    class << self
-      alias_method :json_create, :from_json
+    def self.json_create(json)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::User#from_json or Chef::User#load.")
+      Chef::User.from_json(json)
     end
 
-    def self.list(inflate=false)
-      response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest('users')
+    def self.list(inflate = false)
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users")
       users = if response.is_a?(Array)
-        transform_ohc_list_response(response) # OHC/OPC
-      else
-        response # OSC
-      end
+                transform_ohc_list_response(response) # OHC/OPC
+              else
+                response # OSC
+              end
       if inflate
         users.inject({}) do |user_map, (name, _url)|
           user_map[name] = Chef::User.load(name)
@@ -161,7 +177,7 @@ class Chef
     end
 
     def self.load(name)
-      response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("users/#{name}")
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" }).get("users/#{name}")
       Chef::User.from_hash(response)
     end
 
@@ -172,7 +188,7 @@ class Chef
     def self.transform_ohc_list_response(response)
       new_response = Hash.new
       response.each do |u|
-        name = u['user']['username']
+        name = u["user"]["username"]
         new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}"
       end
       new_response
diff --git a/lib/chef/user_v1.rb b/lib/chef/user_v1.rb
new file mode 100644
index 0000000..3b7dc33
--- /dev/null
+++ b/lib/chef/user_v1.rb
@@ -0,0 +1,330 @@
+#
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "chef/config"
+require "chef/mixin/params_validate"
+require "chef/mixin/from_file"
+require "chef/mash"
+require "chef/json_compat"
+require "chef/search/query"
+require "chef/mixin/api_version_request_handling"
+require "chef/exceptions"
+require "chef/server_api"
+
+# OSC 11 BACKWARDS COMPATIBILITY NOTE (remove after OSC 11 support ends)
+#
+# In general, Chef::UserV1 is no longer expected to support Open Source Chef 11 Server requests.
+# The object that handles those requests remain in the Chef::User namespace.
+# This code will be moved to the Chef::User namespace as of Chef 13.
+#
+# Exception: self.list is backwards compatible with OSC 11
+class Chef
+  class UserV1
+
+    include Chef::Mixin::FromFile
+    include Chef::Mixin::ParamsValidate
+    include Chef::Mixin::ApiVersionRequestHandling
+
+    SUPPORTED_API_VERSIONS = [0, 1]
+
+    def initialize
+      @username = nil
+      @display_name = nil
+      @first_name = nil
+      @middle_name = nil
+      @last_name = nil
+      @email = nil
+      @password = nil
+      @public_key = nil
+      @private_key = nil
+      @create_key = nil
+    end
+
+    def chef_root_rest_v0
+      @chef_root_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "0" })
+    end
+
+    def chef_root_rest_v1
+      @chef_root_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "1" })
+    end
+
+    def username(arg = nil)
+      set_or_return(:username, arg,
+                    :regex => /^[a-z0-9\-_]+$/)
+    end
+
+    def display_name(arg = nil)
+      set_or_return(:display_name,
+                    arg, :kind_of => String)
+    end
+
+    def first_name(arg = nil)
+      set_or_return(:first_name,
+                    arg, :kind_of => String)
+    end
+
+    def middle_name(arg = nil)
+      set_or_return(:middle_name,
+                    arg, :kind_of => String)
+    end
+
+    def last_name(arg = nil)
+      set_or_return(:last_name,
+                    arg, :kind_of => String)
+    end
+
+    def email(arg = nil)
+      set_or_return(:email,
+                    arg, :kind_of => String)
+    end
+
+    def create_key(arg = nil)
+      set_or_return(:create_key, arg,
+                    :kind_of => [TrueClass, FalseClass])
+    end
+
+    def public_key(arg = nil)
+      set_or_return(:public_key,
+                    arg, :kind_of => String)
+    end
+
+    def private_key(arg = nil)
+      set_or_return(:private_key,
+                    arg, :kind_of => String)
+    end
+
+    def password(arg = nil)
+      set_or_return(:password,
+                    arg, :kind_of => String)
+    end
+
+    def to_hash
+      result = {
+        "username" => @username
+      }
+      result["display_name"] = @display_name unless @display_name.nil?
+      result["first_name"] = @first_name unless @first_name.nil?
+      result["middle_name"] = @middle_name unless @middle_name.nil?
+      result["last_name"] = @last_name unless @last_name.nil?
+      result["email"] = @email unless @email.nil?
+      result["password"] = @password unless @password.nil?
+      result["public_key"] = @public_key unless @public_key.nil?
+      result["private_key"] = @private_key unless @private_key.nil?
+      result["create_key"] = @create_key unless @create_key.nil?
+      result
+    end
+
+    def to_json(*a)
+      Chef::JSONCompat.to_json(to_hash, *a)
+    end
+
+    def destroy
+      # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
+      Chef::ServerAPI.new(Chef::Config[:chef_server_url]).delete("users/#{@username}")
+    end
+
+    def create
+      # try v1, fail back to v0 if v1 not supported
+      begin
+        payload = {
+          :username => @username,
+          :display_name => @display_name,
+          :first_name => @first_name,
+          :last_name => @last_name,
+          :email => @email,
+          :password => @password,
+        }
+        payload[:public_key] = @public_key unless @public_key.nil?
+        payload[:create_key] = @create_key unless @create_key.nil?
+        payload[:middle_name] = @middle_name unless @middle_name.nil?
+        raise Chef::Exceptions::InvalidUserAttribute, "You cannot set both public_key and create_key for create." if !@create_key.nil? && !@public_key.nil?
+        new_user = chef_root_rest_v1.post("users", payload)
+
+        # get the private_key out of the chef_key hash if it exists
+        if new_user["chef_key"]
+          if new_user["chef_key"]["private_key"]
+            new_user["private_key"] = new_user["chef_key"]["private_key"]
+          end
+          new_user["public_key"] = new_user["chef_key"]["public_key"]
+          new_user.delete("chef_key")
+        end
+      rescue Net::HTTPServerException => e
+        # rescue API V0 if 406 and the server supports V0
+        supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
+        raise e unless supported_versions && supported_versions.include?(0)
+        payload = {
+          :username => @username,
+          :display_name => @display_name,
+          :first_name => @first_name,
+          :last_name => @last_name,
+          :email => @email,
+          :password => @password,
+        }
+        payload[:middle_name] = @middle_name unless @middle_name.nil?
+        payload[:public_key] = @public_key unless @public_key.nil?
+        # under API V0, the server will create a key pair if public_key isn't passed
+        new_user = chef_root_rest_v0.post("users", payload)
+      end
+
+      Chef::UserV1.from_hash(self.to_hash.merge(new_user))
+    end
+
+    def update(new_key = false)
+      begin
+        payload = { :username => username }
+        payload[:display_name] = display_name unless display_name.nil?
+        payload[:first_name] = first_name unless first_name.nil?
+        payload[:middle_name] = middle_name unless middle_name.nil?
+        payload[:last_name] = last_name unless last_name.nil?
+        payload[:email] = email unless email.nil?
+        payload[:password] = password unless password.nil?
+
+        # API V1 will fail if these key fields are defined, and try V0 below if relevant 400 is returned
+        payload[:public_key] = public_key unless public_key.nil?
+        payload[:private_key] = new_key if new_key
+
+        updated_user = chef_root_rest_v1.put("users/#{username}", payload)
+      rescue Net::HTTPServerException => e
+        if e.response.code == "400"
+          # if a 400 is returned but the error message matches the error related to private / public key fields, try V0
+          # else, raise the 400
+          error = Chef::JSONCompat.from_json(e.response.body)["error"].first
+          error_match = /Since Server API v1, all keys must be updated via the keys endpoint/.match(error)
+          if error_match.nil?
+            raise e
+          end
+        else # for other types of errors, test for API versioning errors right away
+          supported_versions = server_client_api_version_intersection(e, SUPPORTED_API_VERSIONS)
+          raise e unless supported_versions && supported_versions.include?(0)
+        end
+        updated_user = chef_root_rest_v0.put("users/#{username}", payload)
+      end
+      Chef::UserV1.from_hash(self.to_hash.merge(updated_user))
+    end
+
+    def save(new_key = false)
+      begin
+        create
+      rescue Net::HTTPServerException => e
+        if e.response.code == "409"
+          update(new_key)
+        else
+          raise e
+        end
+      end
+    end
+
+    # Note: remove after API v0 no longer supported by client (and knife command).
+    def reregister
+      begin
+        payload = self.to_hash.merge({ "private_key" => true })
+        reregistered_self = chef_root_rest_v0.put("users/#{username}", payload)
+        private_key(reregistered_self["private_key"])
+      # only V0 supported for reregister
+      rescue Net::HTTPServerException => e
+        # if there was a 406 related to versioning, give error explaining that
+        # only API version 0 is supported for reregister command
+        if e.response.code == "406" && e.response["x-ops-server-api-version"]
+          version_header = Chef::JSONCompat.from_json(e.response["x-ops-server-api-version"])
+          min_version = version_header["min_version"]
+          max_version = version_header["max_version"]
+          error_msg = reregister_only_v0_supported_error_msg(max_version, min_version)
+          raise Chef::Exceptions::OnlyApiVersion0SupportedForAction.new(error_msg)
+        else
+          raise e
+        end
+      end
+      self
+    end
+
+    def to_s
+      "user[#{@username}]"
+    end
+
+    # Class Methods
+
+    def self.from_hash(user_hash)
+      user = Chef::UserV1.new
+      user.username user_hash["username"]
+      user.display_name user_hash["display_name"] if user_hash.key?("display_name")
+      user.first_name user_hash["first_name"] if user_hash.key?("first_name")
+      user.middle_name user_hash["middle_name"] if user_hash.key?("middle_name")
+      user.last_name user_hash["last_name"] if user_hash.key?("last_name")
+      user.email user_hash["email"] if user_hash.key?("email")
+      user.password user_hash["password"] if user_hash.key?("password")
+      user.public_key user_hash["public_key"] if user_hash.key?("public_key")
+      user.private_key user_hash["private_key"] if user_hash.key?("private_key")
+      user.create_key user_hash["create_key"] if user_hash.key?("create_key")
+      user
+    end
+
+    def self.from_json(json)
+      Chef::UserV1.from_hash(Chef::JSONCompat.from_json(json))
+    end
+
+    def self.json_create(json)
+      Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please use Chef::UserV1#from_json or Chef::UserV1#load.")
+      Chef::UserV1.from_json(json)
+    end
+
+    def self.list(inflate = false)
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("users")
+      users = if response.is_a?(Array)
+                # EC 11 / CS 12 V0, V1
+                #   GET /organizations/<org>/users
+                transform_list_response(response)
+              else
+                # OSC 11
+                #  GET /users
+                # EC 11 / CS 12 V0, V1
+                #  GET /users
+                response # OSC
+              end
+
+      if inflate
+        users.inject({}) do |user_map, (name, _url)|
+          user_map[name] = Chef::UserV1.load(name)
+          user_map
+        end
+      else
+        users
+      end
+    end
+
+    def self.load(username)
+      # will default to the current API version (Chef::Authenticator::DEFAULT_SERVER_API_VERSION)
+      response = Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get("users/#{username}")
+      Chef::UserV1.from_hash(response)
+    end
+
+    # Gross.  Transforms an API response in the form of:
+    # [ { "user" => { "username" => USERNAME }}, ...]
+    # into the form
+    # { "USERNAME" => "URI" }
+    def self.transform_list_response(response)
+      new_response = Hash.new
+      response.each do |u|
+        name = u["user"]["username"]
+        new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}"
+      end
+      new_response
+    end
+
+    private_class_method :transform_list_response
+
+  end
+end
diff --git a/lib/chef/util/backup.rb b/lib/chef/util/backup.rb
index 0cc009c..8bf2b3f 100644
--- a/lib/chef/util/backup.rb
+++ b/lib/chef/util/backup.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/util/path_helper'
+require "chef/util/path_helper"
 
 class Chef
   class Util
@@ -49,7 +49,7 @@ class Chef
       def backup_filename
         @backup_filename ||= begin
           time = Time.now
-          nanoseconds = sprintf("%6f", time.to_f).split('.')[1]
+          nanoseconds = sprintf("%6f", time.to_f).split(".")[1]
           savetime = time.strftime("%Y%m%d%H%M%S.#{nanoseconds}")
           backup_filename = "#{path}.chef-#{savetime}"
           backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows
@@ -78,8 +78,16 @@ class Chef
         Chef::Log.info("#{@new_resource} removed backup at #{backup_file}")
       end
 
+      def unsorted_backup_files
+        # If you replace this with Dir[], you will probably break Windows.
+        fn = Regexp.escape(::File.basename(path))
+        Dir.entries(::File.dirname(backup_path)).select do |f|
+          !!(f =~ /\A#{fn}.chef-[0-9.]*\B/)
+        end.map { |f| ::File.join(::File.dirname(backup_path), f) }
+      end
+
       def sorted_backup_files
-        Dir[Chef::Util::PathHelper.escape_glob(prefix, ".#{path}") + ".chef-*"].sort { |a,b| b <=> a }
+        unsorted_backup_files.sort { |a, b| b <=> a }
       end
     end
   end
diff --git a/lib/chef/util/diff.rb b/lib/chef/util/diff.rb
index c2dc6e0..bb1b4e2 100644
--- a/lib/chef/util/diff.rb
+++ b/lib/chef/util/diff.rb
@@ -1,5 +1,5 @@
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # Some portions of this file are derived from material in the diff-lcs
 # project licensed under the terms of the MIT license, provided below.
 #
-# Copyright:: Copyright (c) 2004-2013 Austin Ziegler
+# Copyright:: Copyright 2004-2016, Austin Ziegler
 # License:: MIT
 #
 # Permission is hereby granted, free of charge, to any person
@@ -40,8 +40,8 @@
 # CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE
 # SOFTWARE.
 
-require 'diff/lcs'
-require 'diff/lcs/hunk'
+require "diff/lcs"
+require "diff/lcs/hunk"
 
 class Chef
   class Util
@@ -64,7 +64,7 @@ class Chef
       def use_tempfile_if_missing(file)
         tempfile = nil
         unless File.exists?(file)
-          Chef::Log.debug("file #{file} does not exist to diff against, using empty tempfile")
+          Chef::Log.debug("File #{file} does not exist to diff against, using empty tempfile")
           tempfile = Tempfile.new("chef-diff")
           file = tempfile.path
         end
@@ -97,9 +97,9 @@ class Chef
         return "No differences encountered\n" if diff_data.empty?
 
         # write diff header (standard unified format)
-        ft = File.stat(old_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+        ft = File.stat(old_file).mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.%N %z")
         diff_str << "--- #{old_file}\t#{ft}\n"
-        ft = File.stat(new_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+        ft = File.stat(new_file).mtime.localtime.strftime("%Y-%m-%d %H:%M:%S.%N %z")
         diff_str << "+++ #{new_file}\t#{ft}\n"
 
         # loop over diff hunks. if a hunk overlaps with the last hunk,
@@ -139,7 +139,7 @@ class Chef
         return "(new content is binary, diff output suppressed)" if is_binary?(new_file)
 
         begin
-          Chef::Log.debug("running: diff -u #{old_file} #{new_file}")
+          Chef::Log.debug("Running: diff -u #{old_file} #{new_file}")
           diff_str = udiff(old_file, new_file)
 
         rescue Exception => e
@@ -176,7 +176,7 @@ class Chef
       end
 
       def encode_diff_for_json(diff_str)
-        diff_str.encode!('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
+        diff_str.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
       end
 
     end
diff --git a/lib/chef/util/dsc/configuration_generator.rb b/lib/chef/util/dsc/configuration_generator.rb
index 0d7296e..af9a71b 100644
--- a/lib/chef/util/dsc/configuration_generator.rb
+++ b/lib/chef/util/dsc/configuration_generator.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/util/powershell/cmdlet'
+require "chef/util/powershell/cmdlet"
 
 class Chef::Util::DSC
   class ConfigurationGenerator
@@ -27,9 +27,9 @@ class Chef::Util::DSC
 
     def configuration_document_from_script_code(code, configuration_flags, imports, shellout_flags)
       Chef::Log.debug("DSC: DSC code:\n '#{code}'")
-      generated_script_path = write_document_generation_script(code, 'chef_dsc', imports)
+      generated_script_path = write_document_generation_script(code, "chef_dsc", imports)
       begin
-        configuration_document_from_script_path(generated_script_path, 'chef_dsc', configuration_flags, shellout_flags)
+        configuration_document_from_script_path(generated_script_path, "chef_dsc", configuration_flags, shellout_flags)
       ensure
         ::FileUtils.rm(generated_script_path)
       end
@@ -70,9 +70,9 @@ class Chef::Util::DSC
     def get_merged_configuration_flags!(configuration_flags, configuration_name)
       merged_configuration_flags = { :outputpath  => configuration_document_directory(configuration_name) }
       if configuration_flags
-        configuration_flags.map do | switch, value |
+        configuration_flags.map do |switch, value|
           if merged_configuration_flags.key?(switch.to_s.downcase.to_sym)
-            raise ArgumentError, "The `flags` attribute for the dsc_script resource contained a command line switch :#{switch.to_s} that is disallowed."
+            raise ArgumentError, "The `flags` attribute for the dsc_script resource contained a command line switch :#{switch} that is disallowed."
           end
           merged_configuration_flags[switch.to_s.downcase.to_sym] = value
         end
@@ -97,7 +97,7 @@ Configuration '#{configuration_name}'
     def generate_import_resource_statements(imports)
       if imports
         imports.map do |resource_module, resources|
-          if resources.length == 0 || resources.include?('*')
+          if resources.length == 0 || resources.include?("*")
             "Import-DscResource -ModuleName #{resource_module}"
           else
             "Import-DscResource -ModuleName #{resource_module} -Name #{resources.join(',')}"
@@ -114,7 +114,7 @@ Configuration '#{configuration_name}'
 
     def write_document_generation_script(code, configuration_name, imports)
       script_path = "#{@config_directory}/chef_dsc_config.ps1"
-      ::File.open(script_path, 'wt') do | script |
+      ::File.open(script_path, "wt") do |script|
         script.write(configuration_code(code, configuration_name, imports))
       end
       script_path
@@ -122,7 +122,7 @@ Configuration '#{configuration_name}'
 
     def find_configuration_document(configuration_name)
       document_directory = configuration_document_directory(configuration_name)
-      document_file_name = ::Dir.entries(document_directory).find { | path | path =~ /.*.mof/ }
+      document_file_name = ::Dir.entries(document_directory).find { |path| path =~ /.*.mof/ }
       ::File.join(document_directory, document_file_name) if document_file_name
     end
 
@@ -131,7 +131,7 @@ Configuration '#{configuration_name}'
     end
 
     def get_configuration_document(document_path)
-      ::File.open(document_path, 'rb') do | file |
+      ::File.open(document_path, "rb") do |file|
         file.read
       end
     end
diff --git a/lib/chef/util/dsc/lcm_output_parser.rb b/lib/chef/util/dsc/lcm_output_parser.rb
index 754fde3..2e81b36 100644
--- a/lib/chef/util/dsc/lcm_output_parser.rb
+++ b/lib/chef/util/dsc/lcm_output_parser.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Jay Mundrawala (<jdm at getchef.com>)
+# Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/log'
-require 'chef/util/dsc/resource_info'
-require 'chef/exceptions'
+require "chef/log"
+require "chef/util/dsc/resource_info"
+require "chef/exceptions"
 
 class Chef
   class Util
@@ -73,7 +73,7 @@ class Chef
                   if current_resource[:name]
                     resources.push(current_resource)
                   end
-                  current_resource = {:name => info}
+                  current_resource = { :name => info }
                 else
                   Chef::Log.debug("Ignoring op_action #{op_action}: Read line #{line}")
                 end
@@ -108,8 +108,8 @@ class Chef
                 # If the line looks like
                 # What If: [machinename]: LCM: [op_action op_type] message
                 # extract op_action, op_type, and message
-                operation, info = match.captures
-                op_action, op_type = operation.strip.split(' ').map {|m| m.downcase.to_sym}
+              operation, info = match.captures
+              op_action, op_type = operation.strip.split(" ").map { |m| m.downcase.to_sym }
             else
               op_action = op_type = :info
               if match = line.match(/^.*?:.*?: \s+(.*)/)
diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb
index f839834..3b4eaa9 100644
--- a/lib/chef/util/dsc/local_configuration_manager.rb
+++ b/lib/chef/util/dsc/local_configuration_manager.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/dsc/lcm_output_parser'
+require "chef/util/powershell/cmdlet"
+require "chef/util/dsc/lcm_output_parser"
 
 class Chef::Util::DSC
   class LocalConfigurationManager
@@ -47,7 +47,7 @@ class Chef::Util::DSC
 
     def run_configuration_cmdlet(configuration_document, apply_configuration, shellout_flags)
       Chef::Log.debug("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
-      test_only_parameters = ! apply_configuration ? '-whatif; if (! $?) { exit 1 }' : ''
+      test_only_parameters = ! apply_configuration ? "-whatif; if (! $?) { exit 1 }" : ""
 
       start_operation_timing
       command_code = lcm_command_code(@configuration_path, test_only_parameters)
@@ -90,7 +90,7 @@ EOH
     end
 
     def whatif_not_supported?(what_if_exception_output)
-      !! (what_if_exception_output.gsub(/[\r\n]+/, '').gsub(/\s+/, ' ') =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
+      !! (what_if_exception_output.gsub(/[\r\n]+/, "").gsub(/\s+/, " ") =~ /A parameter cannot be found that matches parameter name 'Whatif'/i)
     end
 
     def dsc_module_import_failure?(what_if_output)
@@ -105,13 +105,13 @@ EOH
         Parser::parse(what_if_output)
       rescue Chef::Exceptions::LCMParser => e
         Chef::Log::warn("Could not parse LCM output: #{e}")
-        [Chef::Util::DSC::ResourceInfo.new('Unknown DSC Resources', true, ['Unknown changes because LCM output was not parsable.'])]
+        [Chef::Util::DSC::ResourceInfo.new("Unknown DSC Resources", true, ["Unknown changes because LCM output was not parsable."])]
       end
     end
 
     def save_configuration_document(configuration_document)
       ::FileUtils.mkdir_p(@configuration_path)
-      ::File.open(configuration_document_path, 'wb') do | file |
+      ::File.open(configuration_document_path, "wb") do |file|
         file.write(configuration_document)
       end
     end
@@ -121,7 +121,7 @@ EOH
     end
 
     def configuration_document_path
-      File.join(@configuration_path,'..mof')
+      File.join(@configuration_path, "..mof")
     end
 
     def clear_execution_time
diff --git a/lib/chef/util/dsc/resource_info.rb b/lib/chef/util/dsc/resource_info.rb
index 4a32451..d6dfcff 100644
--- a/lib/chef/util/dsc/resource_info.rb
+++ b/lib/chef/util/dsc/resource_info.rb
@@ -2,25 +2,25 @@
 class Chef
   class Util
     class DSC
-        class ResourceInfo
-          # The name is the text following [Start Set]
-          attr_reader :name
+      class ResourceInfo
+        # The name is the text following [Start Set]
+        attr_reader :name
 
-          # A list of all log messages between [Start Set] and [End Set].
-          # Each line is an element in the list.
-          attr_reader :change_log
+        # A list of all log messages between [Start Set] and [End Set].
+        # Each line is an element in the list.
+        attr_reader :change_log
 
-          def initialize(name, sets, change_log)
-            @name = name
-            @sets = sets
-            @change_log = change_log || []
-          end
+        def initialize(name, sets, change_log)
+          @name = name
+          @sets = sets
+          @change_log = change_log || []
+        end
 
-          # Does this resource change the state of the system?
-          def changes_state?
-            @sets
-          end
+        # Does this resource change the state of the system?
+        def changes_state?
+          @sets
         end
+      end
     end
   end
 end
diff --git a/lib/chef/util/dsc/resource_store.rb b/lib/chef/util/dsc/resource_store.rb
index fdcecc2..bb3480d 100644
--- a/lib/chef/util/dsc/resource_store.rb
+++ b/lib/chef/util/dsc/resource_store.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,95 +16,94 @@
 # limitations under the License.
 #
 
-require 'chef/util/powershell/cmdlet'
-require 'chef/util/powershell/cmdlet_result'
-require 'chef/exceptions'
+require "chef/util/powershell/cmdlet"
+require "chef/util/powershell/cmdlet_result"
+require "chef/exceptions"
 
 class Chef
-class Util
-class DSC
-  class ResourceStore
+  class Util
+    class DSC
+      class ResourceStore
 
-    def self.instance
-      @@instance ||= ResourceStore.new.tap do |store|
-        store.send(:populate_cache)
-      end
-    end
+        def self.instance
+          @@instance ||= ResourceStore.new.tap do |store|
+            store.send(:populate_cache)
+          end
+        end
 
-    def resources
-      @resources ||= []
-    end
+        def resources
+          @resources ||= []
+        end
 
-    def find(name, module_name=nil)
-      found = find_resources(name, module_name, resources)
+        def find(name, module_name = nil)
+          found = find_resources(name, module_name, resources)
 
-      # We don't have it, query for the resource...it might
-      # have been added since we last queried
-      if found.length == 0
-        rs = query_resource(name)
-        add_resources(rs)
-        found = find_resources(name, module_name, rs)
-      end
+          # We don't have it, query for the resource...it might
+          # have been added since we last queried
+          if found.length == 0
+            rs = query_resource(name)
+            add_resources(rs)
+            found = find_resources(name, module_name, rs)
+          end
 
-      found
-    end
-
-    private
+          found
+        end
 
-    def add_resource(new_r)
-      count = resources.count do |r|
-        r['ResourceType'].casecmp(new_r['ResourceType']) == 0
-      end
-      if count == 0
-        resources << new_r
-      end
-    end
+        private
 
-    def add_resources(rs)
-      rs.each do |r|
-        add_resource(r)
-      end
-    end
+        def add_resource(new_r)
+          count = resources.count do |r|
+            r["ResourceType"].casecmp(new_r["ResourceType"]) == 0
+          end
+          if count == 0
+            resources << new_r
+          end
+        end
 
-    def populate_cache
-      @resources = query_resources
-    end
+        def add_resources(rs)
+          rs.each do |r|
+            add_resource(r)
+          end
+        end
 
-    def find_resources(name, module_name, rs)
-      found = rs.find_all do |r|
-        name_matches = r['Name'].casecmp(name) == 0
-        if name_matches
-          module_name == nil || (r['Module'] and r['Module']['Name'].casecmp(module_name) == 0)
-        else
-          false
+        def populate_cache
+          @resources = query_resources
         end
-      end
-    end
 
+        def find_resources(name, module_name, rs)
+          found = rs.find_all do |r|
+            name_matches = r["Name"].casecmp(name) == 0
+            if name_matches
+              module_name == nil || (r["Module"] and r["Module"]["Name"].casecmp(module_name) == 0)
+            else
+              false
+            end
+          end
+        end
 
-    # Returns a list of dsc resources
-    def query_resources
-      cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, 'get-dscresource',
-          :object)
-      result = cmdlet.run
-      result.return_value
-    end
+        # Returns a list of dsc resources
+        def query_resources
+          cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource",
+              :object)
+          result = cmdlet.run
+          result.return_value
+        end
 
-    # Returns a list of dsc resources matching the provided name
-    def query_resource(resource_name)
-      cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource #{resource_name}",
-          :object)
-      result = cmdlet.run
-      ret_val = result.return_value
-      if ret_val.nil?
-        []
-      elsif ret_val.is_a? Array
-        ret_val
-      else
-        [ret_val]
+        # Returns a list of dsc resources matching the provided name
+        def query_resource(resource_name)
+          cmdlet = Chef::Util::Powershell::Cmdlet.new(nil, "get-dscresource #{resource_name}",
+              :object)
+          result = cmdlet.run
+          ret_val = result.return_value
+          if ret_val.nil?
+            []
+          elsif ret_val.is_a? Array
+            ret_val
+          else
+            [ret_val]
+          end
+        end
       end
     end
   end
 end
-end
-end
diff --git a/lib/chef/util/editor.rb b/lib/chef/util/editor.rb
index 973cf48..fa4f0ec 100644
--- a/lib/chef/util/editor.rb
+++ b/lib/chef/util/editor.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Chris Bandy (<bandy.chris at gmail.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -89,4 +89,3 @@ class Chef
     end
   end
 end
-
diff --git a/lib/chef/util/file_edit.rb b/lib/chef/util/file_edit.rb
index 4d2a9c0..5aa33fd 100644
--- a/lib/chef/util/file_edit.rb
+++ b/lib/chef/util/file_edit.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/util/editor'
-require 'fileutils'
+require "chef/util/editor"
+require "fileutils"
 
 class Chef
   class Util
@@ -61,7 +61,7 @@ class Chef
       #search the file line by line and match each line with the given regex
       #if matched, delete the match (all occurrences) from the line
       def search_file_delete(regex)
-        search_file_replace(regex, '')
+        search_file_replace(regex, "")
       end
 
       #search the file line by line and match each line with the given regex
diff --git a/lib/chef/util/path_helper.rb b/lib/chef/util/path_helper.rb
index 66c2e3f..6389458 100644
--- a/lib/chef/util/path_helper.rb
+++ b/lib/chef/util/path_helper.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,212 +16,10 @@
 # limitations under the License.
 #
 
+require "chef-config/path_helper"
+
 class Chef
   class Util
-    class PathHelper
-      # Maximum characters in a standard Windows path (260 including drive letter and NUL)
-      WIN_MAX_PATH = 259
-
-      def self.dirname(path)
-        if Chef::Platform.windows?
-          # Find the first slash, not counting trailing slashes
-          end_slash = path.size
-          loop do
-            slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]/, end_slash - 1)
-            if !slash
-              return end_slash == path.size ? '.' : path_separator
-            elsif slash == end_slash - 1
-              end_slash = slash
-            else
-              return path[0..slash-1]
-            end
-          end
-        else
-          ::File.dirname(path)
-        end
-      end
-
-      BACKSLASH = '\\'.freeze
-
-      def self.path_separator
-        if Chef::Platform.windows?
-          File::ALT_SEPARATOR || BACKSLASH
-        else
-          File::SEPARATOR
-        end
-      end
-
-      def self.join(*args)
-        args.flatten.inject do |joined_path, component|
-          # Joined path ends with /
-          joined_path = joined_path.sub(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]+$/, '')
-          component = component.sub(/^[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]+/, '')
-          joined_path += "#{path_separator}#{component}"
-        end
-      end
-
-      def self.validate_path(path)
-        if Chef::Platform.windows?
-          unless printable?(path)
-            msg = "Path '#{path}' contains non-printable characters. Check that backslashes are escaped with another backslash (e.g. C:\\\\Windows) in double-quoted strings."
-            Chef::Log.error(msg)
-            raise Chef::Exceptions::ValidationFailed, msg
-          end
-
-          if windows_max_length_exceeded?(path)
-            Chef::Log.debug("Path '#{path}' is longer than #{WIN_MAX_PATH}, prefixing with'\\\\?\\'")
-            path.insert(0, "\\\\?\\")
-          end
-        end
-
-        path
-      end
-
-      def self.windows_max_length_exceeded?(path)
-        # Check to see if paths without the \\?\ prefix are over the maximum allowed length for the Windows API
-        # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
-        unless path =~ /^\\\\?\\/
-          if path.length > WIN_MAX_PATH
-            return true
-          end
-        end
-
-        false
-      end
-
-      def self.printable?(string)
-        # returns true if string is free of non-printable characters (escape sequences)
-        # this returns false for whitespace escape sequences as well, e.g. \n\t
-        if string =~ /[^[:print:]]/
-          false
-        else
-          true
-        end
-      end
-
-      # Produces a comparable path.
-      def self.canonical_path(path, add_prefix=true)
-        # First remove extra separators and resolve any relative paths
-        abs_path = File.absolute_path(path)
-
-        if Chef::Platform.windows?
-          # Add the \\?\ API prefix on Windows unless add_prefix is false
-          # Downcase on Windows where paths are still case-insensitive
-          abs_path.gsub!(::File::SEPARATOR, path_separator)
-          if add_prefix && abs_path !~ /^\\\\?\\/
-            abs_path.insert(0, "\\\\?\\")
-          end
-
-          abs_path.downcase!
-        end
-
-        abs_path
-      end
-
-      def self.cleanpath(path)
-        path = Pathname.new(path).cleanpath.to_s
-        # ensure all forward slashes are backslashes
-        if Chef::Platform.windows?
-          path = path.gsub(File::SEPARATOR, path_separator)
-        end
-        path
-      end
-
-      def self.paths_eql?(path1, path2)
-        canonical_path(path1) == canonical_path(path2)
-      end
-
-      # Paths which may contain glob-reserved characters need
-      # to be escaped before globbing can be done.
-      # http://stackoverflow.com/questions/14127343
-      def self.escape_glob(*parts)
-        path = cleanpath(join(*parts))
-        path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\"+x }
-      end
-
-      def self.relative_path_from(from, to)
-        pathname = Pathname.new(Chef::Util::PathHelper.cleanpath(to)).relative_path_from(Pathname.new(Chef::Util::PathHelper.cleanpath(from)))
-      end
-
-      # Retrieves the "home directory" of the current user while trying to ascertain the existence
-      # of said directory.  The path returned uses / for all separators (the ruby standard format).
-      # If the home directory doesn't exist or an error is otherwise encountered, nil is returned.
-      # 
-      # If a set of path elements is provided, they are appended as-is to the home path if the
-      # homepath exists. 
-      # 
-      # If an optional block is provided, the joined path is passed to that block if the home path is
-      # valid and the result of the block is returned instead.
-      #
-      # Home-path discovery is performed once.  If a path is discovered, that value is memoized so
-      # that subsequent calls to home_dir don't bounce around.
-      #
-      # See self.all_homes.
-      def self.home(*args)
-        @@home_dir ||= self.all_homes { |p| break p }
-        if @@home_dir
-          path = File.join(@@home_dir, *args)
-          block_given? ? (yield path) : path
-        end
-      end
-
-      # See self.home.  This method performs a similar operation except that it yields all the different
-      # possible values of 'HOME' that one could have on this platform.  Hence, on windows, if
-      # HOMEDRIVE\HOMEPATH and USERPROFILE are different, the provided block will be called twice.
-      # This method goes out and checks the existence of each location at the time of the call.
-      #
-      # The return is a list of all the returned values from each block invocation or a list of paths
-      # if no block is provided.
-      def self.all_homes(*args)
-        paths = []
-        if Chef::Platform.windows?
-          # By default, Ruby uses the the following environment variables to determine Dir.home:
-          # HOME
-          # HOMEDRIVE HOMEPATH
-          # USERPROFILE
-          # Ruby only checks to see if the variable is specified - not if the directory actually exists.
-          # On Windows, HOMEDRIVE HOMEPATH can point to a different location (such as an unavailable network mounted drive)
-          # while USERPROFILE points to the location where the user application settings and profile are stored.  HOME
-          # is not defined as an environment variable (usually).  If the home path actually uses UNC, then the prefix is
-          # HOMESHARE instead of HOMEDRIVE.
-          #
-          # We instead walk down the following and only include paths that actually exist.
-          # HOME
-          # HOMEDRIVE HOMEPATH
-          # HOMESHARE HOMEPATH
-          # USERPROFILE
-
-          paths << ENV['HOME']
-          paths << ENV['HOMEDRIVE'] + ENV['HOMEPATH'] if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
-          paths << ENV['HOMESHARE'] + ENV['HOMEPATH'] if ENV['HOMESHARE'] && ENV['HOMEPATH']
-          paths << ENV['USERPROFILE']
-        end
-        paths << Dir.home if ENV['HOME']
-
-        # Depending on what environment variables we're using, the slashes can go in any which way.
-        # Just change them all to / to keep things consistent.
-        # Note: Maybe this is a bad idea on some unixy systems where \ might be a valid character depending on
-        # the particular brand of kool-aid you consume.  This code assumes that \ and / are both
-        # path separators on any system being used.
-        paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
-
-        # Filter out duplicate paths and paths that don't exist.
-        valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path) }
-        valid_paths = valid_paths.uniq
-
-        # Join all optional path elements at the end.
-        # If a block is provided, invoke it - otherwise just return what we've got.
-        joined_paths = valid_paths.map { |home_path| File.join(home_path, *args) }
-        if block_given?
-          joined_paths.each { |p| yield p }
-        else
-          joined_paths
-        end
-      end
-    end
+    PathHelper = ChefConfig::PathHelper
   end
 end
-
-# Break a require loop when require chef/util/path_helper
-require 'chef/platform'
-require 'chef/exceptions'
diff --git a/lib/chef/util/powershell/cmdlet.rb b/lib/chef/util/powershell/cmdlet.rb
index 47d63a2..6ab380c 100644
--- a/lib/chef/util/powershell/cmdlet.rb
+++ b/lib/chef/util/powershell/cmdlet.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,155 +16,155 @@
 # limitations under the License.
 #
 
-require 'mixlib/shellout'
-require 'chef/mixin/windows_architecture_helper'
-require 'chef/util/powershell/cmdlet_result'
+require "mixlib/shellout"
+require "chef/mixin/windows_architecture_helper"
+require "chef/util/powershell/cmdlet_result"
 
 class Chef
-class Util
-class Powershell
-  class Cmdlet
-    def initialize(node, cmdlet, output_format=nil, output_format_options={})
-      @output_format = output_format
-      @node = node
-
-      case output_format
-      when nil
-        @json_format = false
-      when :json
-        @json_format = true
-      when :text
-        @json_format = false
-      when :object
-        @json_format = true
-      else
-        raise ArgumentError, "Invalid output format #{output_format.to_s} specified"
-      end
-
-      @cmdlet = cmdlet
-      @output_format_options = output_format_options
-    end
-
-    attr_reader :output_format
+  class Util
+    class Powershell
+      class Cmdlet
+        def initialize(node, cmdlet, output_format = nil, output_format_options = {})
+          @output_format = output_format
+          @node = node
+
+          case output_format
+          when nil
+            @json_format = false
+          when :json
+            @json_format = true
+          when :text
+            @json_format = false
+          when :object
+            @json_format = true
+          else
+            raise ArgumentError, "Invalid output format #{output_format} specified"
+          end
 
-    def run(switches={}, execution_options={}, *arguments)
-      streams = { :json => CmdletStream.new('json'),
-                  :verbose => CmdletStream.new('verbose'),
-                }
+          @cmdlet = cmdlet
+          @output_format_options = output_format_options
+        end
 
-      arguments_string = arguments.join(' ')
+        attr_reader :output_format
 
-      switches_string = command_switches_string(switches)
+        def run(switches = {}, execution_options = {}, *arguments)
+          streams = { :json => CmdletStream.new("json"),
+                      :verbose => CmdletStream.new("verbose"),
+                    }
 
-      json_depth = 5
+          arguments_string = arguments.join(" ")
 
-      if @json_format && @output_format_options.has_key?(:depth)
-        json_depth = @output_format_options[:depth]
-      end
+          switches_string = command_switches_string(switches)
 
-      json_command = @json_format ? " | convertto-json -compress -depth #{json_depth} "\
-                                    "> #{streams[:json].path}" : ""
-      redirections = "4> '#{streams[:verbose].path}'"
-      command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive "\
-                       "-command \"trap [Exception] {write-error -exception "\
-                       "($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} "\
-                       "#{arguments_string} #{redirections}"\
-                       "#{json_command}\";if ( ! $? ) { exit 1 }"
+          json_depth = 5
 
-      augmented_options = {:returns => [0], :live_stream => false}.merge(execution_options)
-      command = Mixlib::ShellOut.new(command_string, augmented_options)
+          if @json_format && @output_format_options.has_key?(:depth)
+            json_depth = @output_format_options[:depth]
+          end
 
-      status = nil
+          json_command = @json_format ? " | convertto-json -compress -depth #{json_depth} "\
+                                        "> #{streams[:json].path}" : ""
+          redirections = "4> '#{streams[:verbose].path}'"
+          command_string = "powershell.exe -executionpolicy bypass -noprofile -noninteractive "\
+                           "-command \"trap [Exception] {write-error -exception "\
+                           "($_.Exception.Message);exit 1};#{@cmdlet} #{switches_string} "\
+                           "#{arguments_string} #{redirections}"\
+                           "#{json_command}\";if ( ! $? ) { exit 1 }"
 
-      with_os_architecture(@node) do
-        status = command.run_command
-      end
+          augmented_options = { :returns => [0], :live_stream => false }.merge(execution_options)
+          command = Mixlib::ShellOut.new(command_string, augmented_options)
 
-      CmdletResult.new(status, streams, @output_format)
-    end
+          status = nil
 
-    def run!(switches={}, execution_options={}, *arguments)
-      result = run(switches, execution_options, arguments)
+          with_os_architecture(@node) do
+            status = command.run_command
+          end
 
-      if ! result.succeeded?
-        raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
-      end
+          CmdletResult.new(status, streams, @output_format)
+        end
 
-      result
-    end
+        def run!(switches = {}, execution_options = {}, *arguments)
+          result = run(switches, execution_options, arguments)
 
-    protected
+          if ! result.succeeded?
+            raise Chef::Exceptions::PowershellCmdletException, "Powershell Cmdlet failed: #{result.stderr}"
+          end
 
-    include Chef::Mixin::WindowsArchitectureHelper
+          result
+        end
 
-    def validate_switch_name!(switch_parameter_name)
-      if !!(switch_parameter_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
-        raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
-      end
-    end
+        protected
 
-    def escape_parameter_value(parameter_value)
-      parameter_value.gsub(/(`|'|"|#)/,'`\1')
-    end
+        include Chef::Mixin::WindowsArchitectureHelper
 
-    def escape_string_parameter_value(parameter_value)
-      "'#{escape_parameter_value(parameter_value)}'"
-    end
+        def validate_switch_name!(switch_parameter_name)
+          if !!(switch_parameter_name =~ /\A[A-Za-z]+[_a-zA-Z0-9]*\Z/) == false
+            raise ArgumentError, "`#{switch_parameter_name}` is not a valid PowerShell cmdlet switch parameter name"
+          end
+        end
 
-    def command_switches_string(switches)
-      command_switches = switches.map do | switch_name, switch_value |
-        if switch_name.class != Symbol
-          raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name.to_s}'. The switch must be specified as a Symbol'"
+        def escape_parameter_value(parameter_value)
+          parameter_value.gsub(/(`|'|"|#)/, '`\1')
         end
 
-        validate_switch_name!(switch_name)
-
-        switch_argument = ''
-        switch_present = true
-
-        case switch_value
-        when Numeric
-          switch_argument = switch_value.to_s
-        when Float
-          switch_argument = switch_value.to_s
-        when FalseClass
-          switch_present = false
-        when TrueClass
-        when String
-          switch_argument = escape_string_parameter_value(switch_value)
-        else
-          raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name.to_s}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
+        def escape_string_parameter_value(parameter_value)
+          "'#{escape_parameter_value(parameter_value)}'"
         end
 
-        switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(' ').strip : ''
-      end
+        def command_switches_string(switches)
+          command_switches = switches.map do |switch_name, switch_value|
+            if switch_name.class != Symbol
+              raise ArgumentError, "Invalid type `#{switch_name} `for PowerShell switch '#{switch_name}'. The switch must be specified as a Symbol'"
+            end
+
+            validate_switch_name!(switch_name)
+
+            switch_argument = ""
+            switch_present = true
+
+            case switch_value
+            when Numeric
+              switch_argument = switch_value.to_s
+            when Float
+              switch_argument = switch_value.to_s
+            when FalseClass
+              switch_present = false
+            when TrueClass
+            when String
+              switch_argument = escape_string_parameter_value(switch_value)
+            else
+              raise ArgumentError, "Invalid argument type `#{switch_value.class}` specified for PowerShell switch `:#{switch_name}`. Arguments to PowerShell must be of type `String`, `Numeric`, `Float`, `FalseClass`, or `TrueClass`"
+            end
+
+            switch_present ? ["-#{switch_name.to_s.downcase}", switch_argument].join(" ").strip : ""
+          end
 
-      command_switches.join(' ')
-    end
+          command_switches.join(" ")
+        end
 
-    class CmdletStream
-      def initialize(name)
-        @filename = Dir::Tmpname.create(name) {}
-        ObjectSpace.define_finalizer(self, self.class.destroy(@filename))
-      end
+        class CmdletStream
+          def initialize(name)
+            @filename = Dir::Tmpname.create(name) {}
+            ObjectSpace.define_finalizer(self, self.class.destroy(@filename))
+          end
 
-      def path
-        @filename
-      end
+          def path
+            @filename
+          end
 
-      def read
-        if File.exist? @filename
-          File.open(@filename, 'rb:bom|UTF-16LE') do |f|
-            f.read.encode('UTF-8')
+          def read
+            if File.exist? @filename
+              File.open(@filename, "rb:bom|UTF-16LE") do |f|
+                f.read.encode("UTF-8")
+              end
+            end
           end
-        end
-      end
 
-      def self.destroy(name)
-        proc { File.delete(name) if File.exists? name }
+          def self.destroy(name)
+            proc { File.delete(name) if File.exists? name }
+          end
+        end
       end
     end
   end
 end
-end
-end
diff --git a/lib/chef/util/powershell/cmdlet_result.rb b/lib/chef/util/powershell/cmdlet_result.rb
index f1fdd96..82aef4d 100644
--- a/lib/chef/util/powershell/cmdlet_result.rb
+++ b/lib/chef/util/powershell/cmdlet_result.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,46 +16,46 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
+require "chef/json_compat"
 
 class Chef
-class Util
-class Powershell
-  class CmdletResult
-    attr_reader :output_format
-
-    def initialize(status, streams, output_format)
-      @status = status
-      @output_format = output_format
-      @streams = streams
-    end
+  class Util
+    class Powershell
+      class CmdletResult
+        attr_reader :output_format
 
-    def stdout
-      @status.stdout
-    end
-    
-    def stderr
-      @status.stderr
-    end
+        def initialize(status, streams, output_format)
+          @status = status
+          @output_format = output_format
+          @streams = streams
+        end
 
-    def stream(name)
-      @streams[name].read
-    end
+        def stdout
+          @status.stdout
+        end
 
-    def return_value
-      if output_format == :object
-        Chef::JSONCompat.parse(stream(:json))
-      elsif output_format == :json
-        stream(:json)
-      else
-        @status.stdout
-      end
-    end
+        def stderr
+          @status.stderr
+        end
 
-    def succeeded?
-      @succeeded = @status.status.exitstatus == 0
+        def stream(name)
+          @streams[name].read
+        end
+
+        def return_value
+          if output_format == :object
+            Chef::JSONCompat.parse(stream(:json))
+          elsif output_format == :json
+            stream(:json)
+          else
+            @status.stdout
+          end
+        end
+
+        def succeeded?
+          @succeeded = @status.status.exitstatus == 0
+        end
+      end
     end
   end
 end
-end
-end
diff --git a/lib/chef/util/powershell/ps_credential.rb b/lib/chef/util/powershell/ps_credential.rb
index 01f8c27..32810b9 100644
--- a/lib/chef/util/powershell/ps_credential.rb
+++ b/lib/chef/util/powershell/ps_credential.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/crypto' if Chef::Platform.windows?
+require "chef/win32/crypto" if Chef::Platform.windows?
 
 class Chef::Util::Powershell
   class PSCredential
@@ -29,6 +29,9 @@ class Chef::Util::Powershell
       "New-Object System.Management.Automation.PSCredential('#{@username}',('#{encrypt(@password)}' | ConvertTo-SecureString))"
     end
 
+    alias to_s to_psobject
+    alias to_text to_psobject
+
     private
 
     def encrypt(str)
diff --git a/lib/chef/util/selinux.rb b/lib/chef/util/selinux.rb
index 778da04..1aac7ee 100644
--- a/lib/chef/util/selinux.rb
+++ b/lib/chef/util/selinux.rb
@@ -1,10 +1,10 @@
 #
 # Author:: Sean O'Meara
 # Author:: Kevin Keane
-# Author:: Lamont Granquist (<lamont at opscode.com>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
 #
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
-# Copyright:: Copyright (c) 2013, North County Tech Center, LLC
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2016, North County Tech Center, LLC
 #
 # License:: Apache License, Version 2.0
 #
@@ -20,8 +20,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/mixin/shell_out'
-require 'chef/mixin/which'
+require "chef/mixin/shell_out"
+require "chef/mixin/which"
 
 class Chef
   class Util
@@ -71,7 +71,7 @@ class Chef
 
       def check_selinux_enabled?
         if selinuxenabled_path
-          cmd = shell_out!(selinuxenabled_path, :returns => [0,1])
+          cmd = shell_out!(selinuxenabled_path, :returns => [0, 1])
           case cmd.exitstatus
           when 1
             return false
diff --git a/lib/chef/util/threaded_job_queue.rb b/lib/chef/util/threaded_job_queue.rb
index 824cd0a..eaffd9e 100644
--- a/lib/chef/util/threaded_job_queue.rb
+++ b/lib/chef/util/threaded_job_queue.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'thread'
+require "thread"
 
 class Chef
   class Util
diff --git a/lib/chef/util/windows.rb b/lib/chef/util/windows.rb
index 777fe4a..7fa6e15 100644
--- a/lib/chef/util/windows.rb
+++ b/lib/chef/util/windows.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,42 +15,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-#requires: gem install windows-pr
-require 'windows/api'
-require 'windows/error'
-require 'windows/handle'
-require 'windows/unicode'
-require 'windows/msvcrt/buffer'
-require 'windows/msvcrt/string'
-require 'windows/network/management'
 
 class Chef
   class Util
     class Windows
-      protected
-
-      include ::Windows::Error
-      include ::Windows::Unicode
-      include ::Windows::MSVCRT::Buffer
-      include ::Windows::MSVCRT::String
-      include ::Windows::Network::Management
-
-      PTR_SIZE = 4 #XXX 64-bit
-
-      def lpwstr_to_s(buffer, offset)
-        str = 0.chr * (256 * 2) #XXX unhardcode this length (*2 for WCHAR)
-        wcscpy str, buffer[offset*PTR_SIZE,PTR_SIZE].unpack('L')[0]
-        wide_to_multi str
-      end
-
-      def dword_to_i(buffer, offset)
-        buffer[offset*PTR_SIZE,PTR_SIZE].unpack('i')[0] || 0
-      end
-
-      #return pointer for use with pack('L')
-      def str_to_ptr(v)
-        [v].pack('p*').unpack('L')[0]
-      end
     end
   end
 end
diff --git a/lib/chef/util/windows/net_group.rb b/lib/chef/util/windows/net_group.rb
index 924bd39..6dd6e39 100644
--- a/lib/chef/util/windows/net_group.rb
+++ b/lib/chef/util/windows/net_group.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,91 +16,69 @@
 # limitations under the License.
 #
 
-require 'chef/util/windows'
+require "chef/util/windows"
+require "chef/win32/net"
 
 #wrapper around a subset of the NetGroup* APIs.
-#nothing Chef specific, but not complete enough to be its own gem, so util for now.
-class Chef::Util::Windows::NetGroup < Chef::Util::Windows
+class Chef::Util::Windows::NetGroup
 
   private
 
-  def pack_str(s)
-    [str_to_ptr(s)].pack('L')
-  end
-
-  def modify_members(members, func)
-    buffer = 0.chr * (members.size * PTR_SIZE)
-    members.each_with_index do |member,offset|
-      buffer[offset*PTR_SIZE,PTR_SIZE] = pack_str(multi_to_wide(member))
-    end
-    rc = func.call(nil, @name, 3, buffer, members.size)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
-    end
+  def groupname
+    @groupname
   end
 
   public
 
   def initialize(groupname)
-    @name = multi_to_wide(groupname)
+    @groupname = groupname
   end
 
   def local_get_members
-    group_members = []
-    handle = 0.chr * PTR_SIZE
-    rc = ERROR_MORE_DATA
-
-    while rc == ERROR_MORE_DATA
-      ptr   = 0.chr * PTR_SIZE
-      nread = 0.chr * PTR_SIZE
-      total = 0.chr * PTR_SIZE
-
-      rc = NetLocalGroupGetMembers.call(nil, @name, 0, ptr, -1,
-                                        nread, total, handle)
-      if (rc == NERR_Success) || (rc == ERROR_MORE_DATA)
-        ptr = ptr.unpack('L')[0]
-        nread = nread.unpack('i')[0]
-        members = 0.chr * (nread * PTR_SIZE ) #nread * sizeof(LOCALGROUP_MEMBERS_INFO_0)
-        memcpy(members, ptr, members.size)
-
-        # 1 pointer field in LOCALGROUP_MEMBERS_INFO_0, offset 0 is lgrmi0_sid
-        nread.times do |i|
-          sid_address = members[i * PTR_SIZE, PTR_SIZE].unpack('L')[0]
-          sid_ptr = FFI::Pointer.new(sid_address)
-          member_sid = Chef::ReservedNames::Win32::Security::SID.new(sid_ptr)
-          group_members << member_sid.to_s
-        end
-        NetApiBufferFree(ptr)
-      else
-        raise ArgumentError, get_last_error(rc)
-      end
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_get_members(nil, groupname)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
-    group_members
   end
 
   def local_add
-    rc = NetLocalGroupAdd.call(nil, 0, pack_str(@name), nil)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_add(nil, groupname)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
   def local_set_members(members)
-    modify_members(members, NetLocalGroupSetMembers)
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_set_members(nil, groupname, members)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
+    end
   end
 
   def local_add_members(members)
-    modify_members(members, NetLocalGroupAddMembers)
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_add_members(nil, groupname, members)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
+    end
   end
 
   def local_delete_members(members)
-    modify_members(members, NetLocalGroupDelMembers)
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_del_members(nil, groupname, members)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
+    end
   end
 
   def local_delete
-    rc = NetLocalGroupDel.call(nil, @name)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      Chef::ReservedNames::Win32::NetUser::net_local_group_del(nil, groupname)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 end
diff --git a/lib/chef/util/windows/net_use.rb b/lib/chef/util/windows/net_use.rb
index 62d7e16..b9c3ecc 100644
--- a/lib/chef/util/windows/net_use.rb
+++ b/lib/chef/util/windows/net_use.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,62 +20,19 @@
 #see also: WNetAddConnection2 and WNetAddConnection3
 #see also cmd.exe: net use /?
 
-require 'chef/util/windows'
+require "chef/util/windows"
+require "chef/win32/net"
 
 class Chef::Util::Windows::NetUse < Chef::Util::Windows
-
-  private
-
-  USE_NOFORCE = 0
-  USE_FORCE = 1
-  USE_LOTS_OF_FORCE = 2 #every windows API should support this flag
-
-  USE_INFO_2 = [
-    [:local, nil],
-    [:remote, nil],
-    [:password, nil],
-    [:status, 0],
-    [:asg_type, 0],
-    [:refcount, 0],
-    [:usecount, 0],
-    [:username, nil],
-    [:domainname, nil]
-  ]
-
-  USE_INFO_2_TEMPLATE =
-    USE_INFO_2.collect { |field| field[1].class == Fixnum ? 'i' : 'L' }.join
-
-  SIZEOF_USE_INFO_2 = #sizeof(USE_INFO_2)
-    USE_INFO_2.inject(0) do |sum, item|
-      sum + (item[1].class == Fixnum ? 4 : PTR_SIZE)
-    end
-
-  def use_info_2(args)
-    USE_INFO_2.collect { |field|
-      args.include?(field[0]) ? args[field[0]] : field[1]
-    }
-  end
-
-  def use_info_2_pack(use)
-    use.collect { |v|
-      v.class == Fixnum ? v : str_to_ptr(multi_to_wide(v))
-    }.pack(USE_INFO_2_TEMPLATE)
+  def initialize(localname)
+    @use_name = localname
   end
 
-  def use_info_2_unpack(buffer)
-    use = Hash.new
-    USE_INFO_2.each_with_index do |field,offset|
-      use[field[0]] = field[1].class == Fixnum ?
-      dword_to_i(buffer, offset) : lpwstr_to_s(buffer, offset)
+  def to_ui2_struct(use_info)
+    use_info.inject({}) do |memo, (k, v)|
+      memo["ui2_#{k}".to_sym] = v
+      memo
     end
-    use
-  end
-
-  public
-
-  def initialize(localname)
-    @localname = localname
-    @name = multi_to_wide(localname)
   end
 
   def add(args)
@@ -84,38 +41,45 @@ class Chef::Util::Windows::NetUse < Chef::Util::Windows
       args = Hash.new
       args[:remote] = remote
     end
-    args[:local] ||= @localname
-    use = use_info_2(args)
-    buffer = use_info_2_pack(use)
-    rc = NetUseAdd.call(nil, 2, buffer, nil)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    args[:local] ||= use_name
+    ui2_hash = to_ui2_struct(args)
+
+    begin
+      Chef::ReservedNames::Win32::Net.net_use_add_l2(nil, ui2_hash)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
-  def get_info
-    ptr  = 0.chr * PTR_SIZE
-    rc = NetUseGetInfo.call(nil, @name, 2, ptr)
-
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+  def from_use_info_struct(ui2_hash)
+    ui2_hash.inject({}) do |memo, (k, v)|
+      memo[k.to_s.sub("ui2_", "").to_sym] = v
+      memo
     end
+  end
 
-    ptr = ptr.unpack('L')[0]
-    buffer = 0.chr * SIZEOF_USE_INFO_2
-    memcpy(buffer, ptr, buffer.size)
-    NetApiBufferFree(ptr)
-    use_info_2_unpack(buffer)
+  def get_info
+    begin
+      ui2 = Chef::ReservedNames::Win32::Net.net_use_get_info_l2(nil, use_name)
+      from_use_info_struct(ui2)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
+    end
   end
 
   def device
     get_info()[:remote]
   end
-  #XXX should we use some FORCE here?
+
   def delete
-    rc = NetUseDel.call(nil, @name, USE_NOFORCE)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      Chef::ReservedNames::Win32::Net.net_use_del(nil, use_name, :use_noforce)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
+
+  def use_name
+    @use_name
+  end
 end
diff --git a/lib/chef/util/windows/net_user.rb b/lib/chef/util/windows/net_user.rb
index 5df1a8a..f2edeac 100644
--- a/lib/chef/util/windows/net_user.rb
+++ b/lib/chef/util/windows/net_user.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/util/windows'
-require 'chef/exceptions'
+require "chef/util/windows"
+require "chef/exceptions"
+require "chef/win32/net"
+require "chef/win32/security"
 
 #wrapper around a subset of the NetUser* APIs.
 #nothing Chef specific, but not complete enough to be its own gem, so util for now.
@@ -25,91 +27,61 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
 
   private
 
-  LogonUser = Windows::API.new('LogonUser', 'SSSLLP', 'I', 'advapi32')
-
-  DOMAIN_GROUP_RID_USERS = 0x00000201
-
-  UF_SCRIPT              = 0x000001
-  UF_ACCOUNTDISABLE      = 0x000002
-  UF_PASSWD_CANT_CHANGE  = 0x000040
-  UF_NORMAL_ACCOUNT      = 0x000200
-  UF_DONT_EXPIRE_PASSWD  = 0x010000
-
-  #[:symbol_name, default_val]
-  #default_val duals as field type
-  #array index duals as structure offset
-
-  #OC-8391
-  #Changing [:password, nil], to [:password, ""],
-  #if :password is set to nil, windows user creation api ignores the password policy applied
-  #thus initializing it with empty string value.
-  USER_INFO_3 = [
-    [:name, nil],
-    [:password, ""],
-    [:password_age, 0],
-    [:priv, 0], #"The NetUserAdd and NetUserSetInfo functions ignore this member"
-    [:home_dir, nil],
-    [:comment, nil],
-    [:flags, UF_SCRIPT|UF_DONT_EXPIRE_PASSWD|UF_NORMAL_ACCOUNT],
-    [:script_path, nil],
-    [:auth_flags, 0],
-    [:full_name, nil],
-    [:user_comment, nil],
-    [:parms, nil],
-    [:workstations, nil],
-    [:last_logon, 0],
-    [:last_logoff, 0],
-    [:acct_expires, -1],
-    [:max_storage, -1],
-    [:units_per_week, 0],
-    [:logon_hours, nil],
-    [:bad_pw_count, 0],
-    [:num_logons, 0],
-    [:logon_server, nil],
-    [:country_code, 0],
-    [:code_page, 0],
-    [:user_id, 0],
-    [:primary_group_id, DOMAIN_GROUP_RID_USERS],
-    [:profile, nil],
-    [:home_dir_drive, nil],
-    [:password_expired, 0]
-  ]
-
-  USER_INFO_3_TEMPLATE =
-    USER_INFO_3.collect { |field| field[1].class == Fixnum ? 'i' : 'L' }.join
-
-  SIZEOF_USER_INFO_3 = #sizeof(USER_INFO_3)
-    USER_INFO_3.inject(0){|sum,item|
-      sum + (item[1].class == Fixnum ? 4 : PTR_SIZE)
-    }
-
-  def user_info_3(args)
-    USER_INFO_3.collect { |field|
-      args.include?(field[0]) ? args[field[0]] : field[1]
-    }
-  end
-
-  def user_info_3_pack(user)
-    user.collect { |v|
-      v.class == Fixnum ? v : str_to_ptr(multi_to_wide(v))
-    }.pack(USER_INFO_3_TEMPLATE)
+  NetUser = Chef::ReservedNames::Win32::NetUser
+  Security = Chef::ReservedNames::Win32::Security
+
+  USER_INFO_3_TRANSFORM = {
+    name: :usri3_name,
+    password: :usri3_password,
+    password_age: :usri3_password_age,
+    priv: :usri3_priv,
+    home_dir: :usri3_home_dir,
+    comment: :usri3_comment,
+    flags: :usri3_flags,
+    script_path: :usri3_script_path,
+    auth_flags: :usri3_auth_flags,
+    full_name: :usri3_full_name,
+    user_comment: :usri3_usr_comment,
+    parms: :usri3_parms,
+    workstations: :usri3_workstations,
+    last_logon: :usri3_last_logon,
+    last_logoff: :usri3_last_logoff,
+    acct_expires: :usri3_acct_expires,
+    max_storage: :usri3_max_storage,
+    units_per_week: :usri3_units_per_week,
+    logon_hours: :usri3_logon_hours,
+    bad_pw_count: :usri3_bad_pw_count,
+    num_logons: :usri3_num_logons,
+    logon_server: :usri3_logon_server,
+    country_code: :usri3_country_code,
+    code_page: :usri3_code_page,
+    user_id: :usri3_user_id,
+    primary_group_id: :usri3_primary_group_id,
+    profile: :usri3_profile,
+    home_dir_drive: :usri3_home_dir_drive,
+    password_expired: :usri3_password_expired,
+  }
+
+  def transform_usri3(args)
+    args.inject({}) do |memo, (k, v)|
+      memo[USER_INFO_3_TRANSFORM[k]] = v
+      memo
+    end
   end
 
-  def user_info_3_unpack(buffer)
-    user = Hash.new
-    USER_INFO_3.each_with_index do |field,offset|
-      user[field[0]] = field[1].class == Fixnum ?
-        dword_to_i(buffer, offset) : lpwstr_to_s(buffer, offset)
+  def usri3_to_hash(usri3)
+    t = USER_INFO_3_TRANSFORM.invert
+    usri3.inject({}) do |memo, (k, v)|
+      memo[t[k]] = v
+      memo
     end
-    user
   end
 
   def set_info(args)
-    user = user_info_3(args)
-    buffer = user_info_3_pack(user)
-    rc = NetUserSetInfo.call(nil, @name, 3, buffer, nil)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      rc = NetUser::net_user_set_info_l3(nil, @username, transform_usri3(args))
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
@@ -117,52 +89,34 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
 
   def initialize(username)
     @username = username
-    @name = multi_to_wide(username)
   end
 
-  LOGON32_PROVIDER_DEFAULT = 0
-  LOGON32_LOGON_NETWORK = 3
+  LOGON32_PROVIDER_DEFAULT = Security::LOGON32_PROVIDER_DEFAULT
+  LOGON32_LOGON_NETWORK = Security::LOGON32_LOGON_NETWORK
   #XXX for an extra painful alternative, see: http://support.microsoft.com/kb/180548
   def validate_credentials(passwd)
-    token = 0.chr * PTR_SIZE
-    res = LogonUser.call(@username, nil, passwd,
-                         LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, token)
-    if res == 0
+    begin
+      token = Security::logon_user(@username, nil, passwd,
+                 LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT)
+      return true
+    rescue Chef::Exceptions::Win32APIError
       return false
     end
-    ::Windows::Handle::CloseHandle.call(token.unpack('L')[0])
-    return true
   end
 
   def get_info
-    ptr  = 0.chr * PTR_SIZE
-    rc = NetUserGetInfo.call(nil, @name, 3, ptr)
-
-    if rc == NERR_UserNotFound
-      raise Chef::Exceptions::UserIDNotFound, get_last_error(rc)
-    elsif rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      ui3 = NetUser::net_user_get_info_l3(nil, @username)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
-
-    ptr = ptr.unpack('L')[0]
-    buffer = 0.chr * SIZEOF_USER_INFO_3
-    memcpy(buffer, ptr, buffer.size)
-    NetApiBufferFree(ptr)
-    user_info_3_unpack(buffer)
+    usri3_to_hash(ui3)
   end
 
   def add(args)
-    user = user_info_3(args)
-    buffer = user_info_3_pack(user)
-
-    rc = NetUserAdd.call(nil, 3, buffer, rc)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
-    end
-
-    #usri3_primary_group_id:
-    #"When you call the NetUserAdd function, this member must be DOMAIN_GROUP_RID_USERS"
-    NetLocalGroupAddMembers(nil, multi_to_wide("Users"), 3, buffer[0,PTR_SIZE], 1)
+    transformed_args = transform_usri3(args)
+    NetUser::net_user_add_l3(nil, transformed_args)
+    NetUser::net_local_group_add_member(nil, "Users", args[:name])
   end
 
   def user_modify(&proc)
@@ -175,22 +129,23 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
 
   def update(args)
     user_modify do |user|
-      args.each do |key,val|
+      args.each do |key, val|
         user[key] = val
       end
     end
   end
 
   def delete
-    rc = NetUserDel.call(nil, @name)
-    if rc != NERR_Success
-      raise ArgumentError, get_last_error(rc)
+    begin
+      NetUser::net_user_del(nil, @username)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
   def disable_account
     user_modify do |user|
-      user[:flags] |= UF_ACCOUNTDISABLE
+      user[:flags] |= NetUser::UF_ACCOUNTDISABLE
       #This does not set the password to nil. It (for some reason) means to ignore updating the field.
       #See similar behavior for the logon_hours field documented at
       #http://msdn.microsoft.com/en-us/library/windows/desktop/aa371338%28v=vs.85%29.aspx
@@ -200,7 +155,7 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
 
   def enable_account
     user_modify do |user|
-      user[:flags] &= ~UF_ACCOUNTDISABLE
+      user[:flags] &= ~NetUser::UF_ACCOUNTDISABLE
       #This does not set the password to nil. It (for some reason) means to ignore updating the field.
       #See similar behavior for the logon_hours field documented at
       #http://msdn.microsoft.com/en-us/library/windows/desktop/aa371338%28v=vs.85%29.aspx
@@ -209,6 +164,6 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
   end
 
   def check_enabled
-    (get_info()[:flags] & UF_ACCOUNTDISABLE) != 0
+    (get_info()[:flags] & NetUser::UF_ACCOUNTDISABLE) != 0
   end
 end
diff --git a/lib/chef/util/windows/volume.rb b/lib/chef/util/windows/volume.rb
index 08c3a53..a18644c 100644
--- a/lib/chef/util/windows/volume.rb
+++ b/lib/chef/util/windows/volume.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,42 +18,42 @@
 
 #simple wrapper around Volume APIs. might be possible with WMI, but possibly more complex.
 
-require 'chef/util/windows'
-require 'windows/volume'
+require "chef/win32/api/file"
+require "chef/util/windows"
 
 class Chef::Util::Windows::Volume < Chef::Util::Windows
-
-  private
-  include Windows::Volume
-  #XXX not defined in the current windows-pr release
-  DeleteVolumeMountPoint =
-    Windows::API.new('DeleteVolumeMountPoint', 'S', 'B') unless defined? DeleteVolumeMountPoint
-
-  public
+  attr_reader :mount_point
 
   def initialize(name)
     name += "\\" unless name =~ /\\$/ #trailing slash required
-    @name = name
+    @mount_point = name
   end
 
   def device
-    buffer = 0.chr * 256
-    if GetVolumeNameForVolumeMountPoint(@name, buffer, buffer.size)
-      return buffer[0,buffer.size].unpack("Z*")[0]
-    else
-      raise ArgumentError, get_last_error
+    begin
+      Chef::ReservedNames::Win32::File.get_volume_name_for_volume_mount_point(mount_point)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
   def delete
-    unless DeleteVolumeMountPoint.call(@name)
-      raise ArgumentError, get_last_error
+    begin
+      Chef::ReservedNames::Win32::File.delete_volume_mount_point(mount_point)
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
 
   def add(args)
-    unless SetVolumeMountPoint(@name, args[:remote])
-      raise ArgumentError, get_last_error
+    begin
+      Chef::ReservedNames::Win32::File.set_volume_mount_point(mount_point, args[:remote])
+    rescue Chef::Exceptions::Win32APIError => e
+      raise ArgumentError, e
     end
   end
+
+  def mount_point
+    @mount_point
+  end
 end
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index c2f287c..ed80b18 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -1,6 +1,4 @@
-
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,9 +13,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# NOTE: This file is generated by running `rake version` in the top level of
+# this repo. Do not edit this manually. Edit the VERSION file and run the rake
+# task instead.
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
 class Chef
   CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
-  VERSION = '12.3.0'
+  VERSION = "12.7.2"
 end
 
 #
@@ -25,6 +29,6 @@ end
 #
 # NOTE: DO NOT Use the Chef::Version class on Chef::VERSIONs.  The
 #       Chef::Version class is for _cookbooks_ only, and cannot handle
-#       pre-release chef-client versions like "10.14.0.rc.2".  Please
-#       use Rubygem's Gem::Version class instead.
+#       pre-release versions like "10.14.0.rc.2".  Please use Rubygem's
+#       Gem::Version class instead.
 #
diff --git a/lib/chef/version/platform.rb b/lib/chef/version/platform.rb
index 81e7614..07b1a17 100644
--- a/lib/chef/version/platform.rb
+++ b/lib/chef/version/platform.rb
@@ -1,5 +1,5 @@
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/version_class'
+require "chef/version_class"
 
 class Chef
   class Version
@@ -22,7 +22,7 @@ class Chef
 
       protected
 
-      def parse(str="")
+      def parse(str = "")
         @major, @minor, @patch =
           case str.to_s
           when /^(\d+)\.(\d+)\.(\d+)$/
@@ -31,10 +31,10 @@ class Chef
             [ $1.to_i, $2.to_i, 0 ]
           when /^(\d+)$/
             [ $1.to_i, 0, 0 ]
-          when /^(\d+).(\d+)-[a-z]+\d?(-p(\d+))?$/i   # Match FreeBSD
+          when /^(\d+).(\d+)-[a-z]+\d?(-p(\d+))?$/i # Match FreeBSD
             [ $1.to_i, $2.to_i, ($4 ? $4.to_i : 0)]
           else
-            msg = "'#{str.to_s}' does not match 'x.y.z', 'x.y' or 'x'"
+            msg = "'#{str}' does not match 'x.y.z', 'x.y' or 'x'"
             raise Chef::Exceptions::InvalidPlatformVersion.new( msg )
           end
       end
diff --git a/lib/chef/version_class.rb b/lib/chef/version_class.rb
index 01af6f1..35a9f32 100644
--- a/lib/chef/version_class.rb
+++ b/lib/chef/version_class.rb
@@ -1,6 +1,6 @@
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ class Chef
     include Comparable
     attr_reader :major, :minor, :patch
 
-    def initialize(str="")
+    def initialize(str = "")
       parse(str)
     end
 
@@ -53,7 +53,7 @@ class Chef
 
     protected
 
-    def parse(str="")
+    def parse(str = "")
       @major, @minor, @patch =
         case str.to_s
         when /^(\d+)\.(\d+)\.(\d+)$/
@@ -61,7 +61,7 @@ class Chef
         when /^(\d+)\.(\d+)$/
           [ $1.to_i, $2.to_i, 0 ]
         else
-          msg = "'#{str.to_s}' does not match 'x.y.z' or 'x.y'"
+          msg = "'#{str}' does not match 'x.y.z' or 'x.y'"
           raise Chef::Exceptions::InvalidCookbookVersion.new( msg )
         end
     end
diff --git a/lib/chef/version_constraint.rb b/lib/chef/version_constraint.rb
index a78e32e..d4fa5df 100644
--- a/lib/chef/version_constraint.rb
+++ b/lib/chef/version_constraint.rb
@@ -1,6 +1,6 @@
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,19 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-require 'chef/version_class'
+require "chef/version_class"
 
 class Chef
   class VersionConstraint
     DEFAULT_CONSTRAINT = ">= 0.0.0"
-    STANDARD_OPS = %w(< > <= >=)
-    OPS = %w(< > = <= >= ~>)
+    STANDARD_OPS = %w{< > <= >=}
+    OPS = %w{< > = <= >= ~>}
     PATTERN = /^(#{OPS.join('|')}) *([0-9].*)$/
     VERSION_CLASS = Chef::Version
 
     attr_reader :op, :version
 
-    def initialize(constraint_spec=DEFAULT_CONSTRAINT)
+    def initialize(constraint_spec = DEFAULT_CONSTRAINT)
       case constraint_spec
       when nil
         parse(DEFAULT_CONSTRAINT)
@@ -46,11 +46,11 @@ class Chef
                 else
                   self.class::VERSION_CLASS.new(v.to_s)
                 end
-     do_op(version)
+      do_op(version)
     end
 
     def inspect
-      "(#{to_s})"
+      "(#{self})"
     end
 
     def to_s
@@ -67,9 +67,9 @@ class Chef
     def do_op(other_version)
       if STANDARD_OPS.include? @op
         other_version.send(@op.to_sym, @version)
-      elsif @op == '='
+      elsif @op == "="
         other_version == @version
-      elsif @op == '~>'
+      elsif @op == "~>"
         if @missing_patch_level
           (other_version.major == @version.major &&
            other_version.minor >= @version.minor)
@@ -78,7 +78,7 @@ class Chef
            other_version.minor == @version.minor &&
            other_version.patch >= @version.patch)
         end
-      else                      # should never happen
+      else # should never happen
         raise "bad op #{@op}"
       end
     end
@@ -106,7 +106,7 @@ class Chef
         @op = $1
         @raw_version = $2
         @version = self.class::VERSION_CLASS.new(@raw_version)
-        if @raw_version.split('.').size <= 2
+        if @raw_version.split(".").size <= 2
           @missing_patch_level = true
         end
       else
diff --git a/lib/chef/version_constraint/platform.rb b/lib/chef/version_constraint/platform.rb
index ada4f29..29f4678 100644
--- a/lib/chef/version_constraint/platform.rb
+++ b/lib/chef/version_constraint/platform.rb
@@ -1,5 +1,5 @@
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +13,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-require 'chef/version_constraint'
-require 'chef/version/platform'
+require "chef/version_constraint"
+require "chef/version/platform"
 
 class Chef
   class VersionConstraint
diff --git a/lib/chef/whitelist.rb b/lib/chef/whitelist.rb
index 3682f71..58d0bd7 100644
--- a/lib/chef/whitelist.rb
+++ b/lib/chef/whitelist.rb
@@ -1,5 +1,5 @@
 
-require 'chef/exceptions'
+require "chef/exceptions"
 
 class Chef
   class Whitelist
@@ -27,7 +27,7 @@ class Chef
     #   },
     #   ["network/interfaces/eth0", ["filesystem", "/dev/disk"]])
     # will capture the eth0 and /dev/disk subtrees.
-    def self.filter(data, whitelist=nil)
+    def self.filter(data, whitelist = nil)
       return data if whitelist.nil?
 
       new_data = {}
diff --git a/lib/chef/win32/api.rb b/lib/chef/win32/api.rb
index efa632f..ad65b08 100644
--- a/lib/chef/win32/api.rb
+++ b/lib/chef/win32/api.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'ffi'
-require 'chef/reserved_names'
-require 'chef/exceptions'
+require "ffi"
+require "chef/reserved_names"
+require "chef/exceptions"
 
 class Chef
   module ReservedNames::Win32
@@ -67,7 +67,7 @@ class Chef
         # BaseTsd.h: #ifdef (_WIN64) host.typedef int HALF_PTR; #else host.typedef short HALF_PTR;
         host.typedef :ulong,   :HACCEL # (L) Handle to an accelerator table. WinDef.h: #host.typedef HANDLE HACCEL;
         # See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx
-        host.typedef :ulong,   :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE;
+        host.typedef :size_t,   :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE;
         # todo: Platform-dependent! Need to change to :uint64 for Win64
         host.typedef :ulong,   :HBITMAP # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx
         host.typedef :ulong,   :HBRUSH # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx
@@ -117,6 +117,7 @@ class Chef
         host.typedef :uint32,  :LCID # Locale identifier. For more information, see Locales.
         host.typedef :uint32,  :LCTYPE # Locale information type. For a list, see Locale Information Constants.
         host.typedef :uint32,  :LGRPID # Language group identifier. For a list, see EnumLanguageGroupLocales.
+        host.typedef :pointer, :LMSTR # Pointer to null termiated string of unicode characters
         host.typedef :long,    :LONG # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
         host.typedef :int32,   :LONG32 # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
         host.typedef :int64,   :LONG64 # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
@@ -146,6 +147,8 @@ class Chef
         host.typedef :long,    :LRESULT # Signed result of message processing. WinDef.h: host.typedef LONG_PTR LRESULT;
         host.typedef :pointer, :LPWIN32_FIND_DATA # Pointer to WIN32_FIND_DATA struct
         host.typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION # Point to a BY_HANDLE_FILE_INFORMATION struct
+        host.typedef :pointer, :LSA_HANDLE # A handle to a Policy object
+        host.typedef :ulong,   :NTSTATUS # An NTSTATUS code returned by an LSA function call.
         host.typedef :pointer, :PBOOL # Pointer to a BOOL.
         host.typedef :pointer, :PBOOLEAN # Pointer to a BOOL.
         host.typedef :pointer, :PBYTE # Pointer to a BYTE.
@@ -173,12 +176,16 @@ class Chef
         host.typedef :pointer, :PLONG_PTR # Pointer to a LONG_PTR.
         host.typedef :pointer, :PLONG32 # Pointer to a LONG32.
         host.typedef :pointer, :PLONG64 # Pointer to a LONG64.
+        host.typedef :pointer, :PLSA_HANDLE # Pointer to an LSA_HANDLE
+        host.typedef :pointer, :PLSA_OBJECT_ATTRIBUTES # Pointer to an LSA_OBJECT_ATTRIBUTES
+        host.typedef :pointer, :PLSA_UNICODE_STRING # Pointer to LSA_UNICODE_STRING
         host.typedef :pointer, :PLUID # Pointer to a LUID.
         host.typedef :pointer, :POINTER_32 # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
         host.typedef :pointer, :POINTER_64 # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer.
         host.typedef :pointer, :POINTER_SIGNED # A signed pointer.
         host.typedef :pointer, :POINTER_UNSIGNED # An unsigned pointer.
         host.typedef :pointer, :PSHORT # Pointer to a SHORT.
+        host.typedef :pointer, :PSID # Pointer to an account SID
         host.typedef :pointer, :PSIZE_T # Pointer to a SIZE_T.
         host.typedef :pointer, :PSSIZE_T # Pointer to a SSIZE_T.
         host.typedef :pointer, :PSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
@@ -232,7 +239,7 @@ class Chef
         # In WinNT.h: host.typedef wchar_t WCHAR;
         #WINAPI: K,      # Calling convention for system functions. WinDef.h: define WINAPI __stdcall
         host.typedef :ushort,  :WORD # 16-bit unsigned integer. The range is 0 through 65535 decimal.
-        host.typedef :uint,    :WPARAM    # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM;
+        host.typedef :uint,    :WPARAM # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM;
       end
 
       module Macros
diff --git a/lib/chef/win32/api/crypto.rb b/lib/chef/win32/api/crypto.rb
index 1837a57..0abb908 100644
--- a/lib/chef/win32/api/crypto.rb
+++ b/lib/chef/win32/api/crypto.rb
@@ -1,63 +1,63 @@
-#
-# Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/win32/api'
-
-class Chef
-  module ReservedNames::Win32
-    module API
-      module Crypto
-        extend Chef::ReservedNames::Win32::API
-
-        ###############################################
-        # Win32 API Bindings
-        ###############################################
-
-        ffi_lib 'Crypt32'
-
-        CRYPTPROTECT_UI_FORBIDDEN  = 0x1
-        CRYPTPROTECT_LOCAL_MACHINE = 0x4
-        CRYPTPROTECT_AUDIT         = 0x10
-
-        class CRYPT_INTEGER_BLOB < FFI::Struct
-          layout :cbData, :DWORD,   # Count, in bytes, of data 
-                 :pbData, :pointer  # Pointer to data buffer
-          def initialize(str=nil)
-            super(nil)
-            if str
-              self[:pbData] = FFI::MemoryPointer.from_string(str)
-              self[:cbData] = str.bytesize
-            end
-          end
-
-        end
-
-        safe_attach_function :CryptProtectData, [
-          :PDATA_BLOB, 
-          :LPCWSTR,
-          :PDATA_BLOB,
-          :pointer,
-          :PCRYPTPROTECT_PROMPTSTRUCT,
-          :DWORD,
-          :PDATA_BLOB
-        ], :BOOL
-
-      end
-    end
-  end
-end
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api"
+
+class Chef
+  module ReservedNames::Win32
+    module API
+      module Crypto
+        extend Chef::ReservedNames::Win32::API
+
+        ###############################################
+        # Win32 API Bindings
+        ###############################################
+
+        ffi_lib "Crypt32"
+
+        CRYPTPROTECT_UI_FORBIDDEN  = 0x1
+        CRYPTPROTECT_LOCAL_MACHINE = 0x4
+        CRYPTPROTECT_AUDIT         = 0x10
+
+        class CRYPT_INTEGER_BLOB < FFI::Struct
+          layout :cbData, :DWORD,   # Count, in bytes, of data
+                 :pbData, :pointer  # Pointer to data buffer
+          def initialize(str = nil)
+            super(nil)
+            if str
+              self[:pbData] = FFI::MemoryPointer.from_string(str)
+              self[:cbData] = str.bytesize
+            end
+          end
+
+        end
+
+        safe_attach_function :CryptProtectData, [
+          :PDATA_BLOB,
+          :LPCWSTR,
+          :PDATA_BLOB,
+          :pointer,
+          :PCRYPTPROTECT_PROMPTSTRUCT,
+          :DWORD,
+          :PDATA_BLOB,
+        ], :BOOL
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/win32/api/error.rb b/lib/chef/win32/api/error.rb
index d1f9a30..aa80f89 100644
--- a/lib/chef/win32/api/error.rb
+++ b/lib/chef/win32/api/error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -178,7 +178,7 @@ class Chef
         ERROR_LOCK_FAILED               = 167
         ERROR_BUSY                      = 170
         ERROR_CANCEL_VIOLATION          = 173
-        ERROR_ATOMIC_LOCKS_NOT_SUPPORTED= 174
+        ERROR_ATOMIC_LOCKS_NOT_SUPPORTED = 174
 
         ERROR_INVALID_SEGMENT_NUMBER    = 180
         ERROR_INVALID_CALLGATE          = 181
@@ -446,7 +446,7 @@ class Chef
         ERROR_DOWNGRADE_DETECTED              = 1265
         ERROR_MACHINE_LOCKED                  = 1271
         ERROR_CALLBACK_SUPPLIED_INVALID_DATA  = 1273
-        ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED= 1274
+        ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED = 1274
         ERROR_DRIVER_BLOCKED                  = 1275
         ERROR_INVALID_IMPORT_OF_NON_DLL       = 1276
         ERROR_NOT_ALL_ASSIGNED                = 1300
@@ -750,7 +750,7 @@ class Chef
         ERROR_NETLOGON_NOT_STARTED            = 1792
         ERROR_ACCOUNT_EXPIRED                 = 1793
         ERROR_REDIRECTOR_HAS_OPEN_HANDLES     = 1794
-        ERROR_PRINTER_DRIVER_ALREADY_INSTALLED= 1795
+        ERROR_PRINTER_DRIVER_ALREADY_INSTALLED = 1795
         ERROR_UNKNOWN_PORT                    = 1796
         ERROR_UNKNOWN_PRINTER_DRIVER          = 1797
         ERROR_UNKNOWN_PRINTPROCESSOR          = 1798
@@ -824,9 +824,9 @@ class Chef
         ERROR_CONTEXT_EXPIRED                 = 1931
         ERROR_PER_USER_TRUST_QUOTA_EXCEEDED   = 1932
         ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED   = 1933
-        ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED= 1934
-        ERROR_AUTHENTICATION_FIREWALL_FAILED  = 1935
-        ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED= 1936
+        ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934
+        ERROR_AUTHENTICATION_FIREWALL_FAILED = 1935
+        ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936
         ERROR_INVALID_PIXEL_FORMAT            = 2000
         ERROR_BAD_DRIVER                      = 2001
         ERROR_INVALID_WINDOW_STYLE            = 2002
@@ -848,6 +848,7 @@ class Chef
         ERROR_INVALID_COLORINDEX              = 2022
         ERROR_CONNECTED_OTHER_PASSWORD        = 2108
         ERROR_BAD_USERNAME                    = 2202
+        ERROR_USER_NOT_FOUND                  = 2221
         ERROR_NOT_CONNECTED                   = 2250
         ERROR_OPEN_FILES                      = 2401
         ERROR_ACTIVE_CONNECTIONS              = 2402
@@ -877,7 +878,7 @@ class Chef
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32', 'user32'
+        ffi_lib "kernel32", "user32"
 
 =begin
 DWORD WINAPI FormatMessage(
diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb
index 86b2b94..52ac486 100644
--- a/lib/chef/win32/api/file.rb
+++ b/lib/chef/win32/api/file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
 # Author:: Mark Mzyk (<mmzyk at ospcode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,10 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
-require 'chef/win32/api/security'
-require 'chef/win32/api/system'
+require "chef/win32/api"
+require "chef/win32/api/security"
+require "chef/win32/api/system"
+require "chef/win32/unicode"
 
 class Chef
   module ReservedNames::Win32
@@ -162,7 +163,7 @@ class Chef
           (device_type << 16) | (access << 14) | (function << 2) | method
         end
 
-        FSCTL_GET_REPARSE_POINT         = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
+        FSCTL_GET_REPARSE_POINT = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
         # Reparse point tags
         IO_REPARSE_TAG_MOUNT_POINT              = 0xA0000003
@@ -175,13 +176,20 @@ class Chef
         IO_REPARSE_TAG_SYMLINK                  = 0xA000000C
         IO_REPARSE_TAG_DFSR                     = 0x80000012
 
-        MAXIMUM_REPARSE_DATA_BUFFER_SIZE        = 16*1024
+        MAXIMUM_REPARSE_DATA_BUFFER_SIZE        = 16 * 1024
 
         ###############################################
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32'
+        ffi_lib "kernel32", "version"
+
+        # Does not map directly to a win32 struct
+        # see https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
+        class Translation < FFI::Struct
+          layout :w_lang, :WORD,
+          :w_code_page, :WORD
+        end
 
 =begin
 typedef struct _FILETIME {
@@ -230,7 +238,7 @@ typedef struct _WIN32_FIND_DATA {
           :n_file_size_low, :DWORD,
           :dw_reserved_0, :DWORD,
           :dw_reserved_1, :DWORD,
-          :c_file_name, [:BYTE, MAX_PATH*2],
+          :c_file_name, [:BYTE, MAX_PATH * 2],
           :c_alternate_file_name, [:BYTE, 14]
         end
 
@@ -299,11 +307,12 @@ typedef struct _REPARSE_DATA_BUFFER {
 
           def substitute_name
             string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset]
-            string_pointer.read_wstring(self[:SubstituteNameLength]/2)
+            string_pointer.read_wstring(self[:SubstituteNameLength] / 2)
           end
+
           def print_name
             string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset]
-            string_pointer.read_wstring(self[:PrintNameLength]/2)
+            string_pointer.read_wstring(self[:PrintNameLength] / 2)
           end
         end
         class REPARSE_DATA_BUFFER_MOUNT_POINT < FFI::Struct
@@ -315,11 +324,12 @@ typedef struct _REPARSE_DATA_BUFFER {
 
           def substitute_name
             string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset]
-            string_pointer.read_wstring(self[:SubstituteNameLength]/2)
+            string_pointer.read_wstring(self[:SubstituteNameLength] / 2)
           end
+
           def print_name
             string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset]
-            string_pointer.read_wstring(self[:PrintNameLength]/2)
+            string_pointer.read_wstring(self[:PrintNameLength] / 2)
           end
         end
         class REPARSE_DATA_BUFFER_GENERIC < FFI::Struct
@@ -450,6 +460,52 @@ BOOL WINAPI DeviceIoControl(
 =end
         safe_attach_function :DeviceIoControl, [:HANDLE, :DWORD, :LPVOID, :DWORD, :LPVOID, :DWORD, :LPDWORD, :pointer], :BOOL
 
+#BOOL WINAPI DeleteVolumeMountPoint(
+  #_In_ LPCTSTR lpszVolumeMountPoint
+#);
+        safe_attach_function :DeleteVolumeMountPointW, [:LPCTSTR], :BOOL
+
+#BOOL WINAPI SetVolumeMountPoint(
+  #_In_ LPCTSTR lpszVolumeMountPoint,
+  #_In_ LPCTSTR lpszVolumeName
+#);
+        safe_attach_function :SetVolumeMountPointW, [:LPCTSTR, :LPCTSTR], :BOOL
+
+#BOOL WINAPI GetVolumeNameForVolumeMountPoint(
+  #_In_  LPCTSTR lpszVolumeMountPoint,
+  #_Out_ LPTSTR  lpszVolumeName,
+  #_In_  DWORD   cchBufferLength
+#);
+        safe_attach_function :GetVolumeNameForVolumeMountPointW, [:LPCTSTR, :LPTSTR, :DWORD], :BOOL
+
+=begin
+BOOL WINAPI GetFileVersionInfo(
+  _In_       LPCTSTR lptstrFilename,
+  _Reserved_ DWORD   dwHandle,
+  _In_       DWORD   dwLen,
+  _Out_      LPVOID  lpData
+);
+=end
+        safe_attach_function :GetFileVersionInfoW, [:LPCTSTR, :DWORD, :DWORD, :LPVOID], :BOOL
+
+=begin
+DWORD WINAPI GetFileVersionInfoSize(
+  _In_      LPCTSTR lptstrFilename,
+  _Out_opt_ LPDWORD lpdwHandle
+);
+=end
+        safe_attach_function :GetFileVersionInfoSizeW, [:LPCTSTR, :LPDWORD], :DWORD
+
+=begin
+BOOL WINAPI VerQueryValue(
+  _In_  LPCVOID pBlock,
+  _In_  LPCTSTR lpSubBlock,
+  _Out_ LPVOID  *lplpBuffer,
+  _Out_ PUINT   puLen
+);
+=end
+        safe_attach_function :VerQueryValueW, [:LPCVOID, :LPCTSTR, :LPVOID, :PUINT], :BOOL
+
         ###############################################
         # Helpers
         ###############################################
@@ -545,6 +601,21 @@ BOOL WINAPI DeviceIoControl(
           file_information
         end
 
+        def retrieve_file_version_info(file_name)
+          file_name = encode_path(file_name)
+          file_size = GetFileVersionInfoSizeW(file_name, nil)
+          if file_size == 0
+            Chef::ReservedNames::Win32::Error.raise!
+          end
+
+          version_info = FFI::MemoryPointer.new(file_size)
+          unless GetFileVersionInfoW(file_name, 0, file_size, version_info)
+            Chef::ReservedNames::Win32::Error.raise!
+          end
+
+          version_info
+        end
+
       end
     end
   end
diff --git a/lib/chef/win32/api/installer.rb b/lib/chef/win32/api/installer.rb
index 6864a26..caf7b23 100644
--- a/lib/chef/win32/api/installer.rb
+++ b/lib/chef/win32/api/installer.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/exceptions'
-require 'chef/win32/api'
-require 'chef/win32/error'
-require 'pathname'
+require "chef/exceptions"
+require "chef/win32/api"
+require "chef/win32/error"
+require "pathname"
 
 class Chef
   module ReservedNames::Win32
@@ -32,12 +32,11 @@ class Chef
         # Win32 API Constants
         ###############################################
 
-
         ###############################################
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'msi'
+        ffi_lib "msi"
 
 =begin
 UINT MsiOpenPackage(
@@ -94,7 +93,7 @@ UINT MsiCloseHandle(
             msg << Chef::ReservedNames::Win32::Error.format_message(status)
             raise Chef::Exceptions::Package, msg
           end
-         
+
           buffer_length = FFI::Buffer.new(:long).write_long(buffer_length.read_long + 1)
           buffer = 0.chr * buffer_length.read_long
 
@@ -114,18 +113,18 @@ UINT MsiCloseHandle(
         # Opens a Microsoft Installer (MSI) file from an absolute path and returns a pointer to a handle
         # Remember to close the handle with msi_close_handle()
         def open_package(package_path)
-          # MsiOpenPackage expects a perfect absolute Windows path to the MSI 
+          # MsiOpenPackage expects a perfect absolute Windows path to the MSI
           raise ArgumentError, "Provided path '#{package_path}' must be an absolute path" unless Pathname.new(package_path).absolute?
 
           pkg_ptr = FFI::MemoryPointer.new(:pointer, 4)
           status = msi_open_package(package_path, 1, pkg_ptr)
           case status
-          when 0 
+          when 0
             # success
           else
             raise Chef::Exceptions::Package, "msi_open_package: unexpected status #{status}: #{Chef::ReservedNames::Win32::Error.format_message(status)}"
           end
-          return pkg_ptr        
+          return pkg_ptr
         end
 
         # All installed product_codes should have a VersionString
@@ -133,11 +132,11 @@ UINT MsiCloseHandle(
         def get_installed_version(product_code)
           version = 0.chr
           version_length = FFI::Buffer.new(:long).write_long(0)
-         
+
           status = msi_get_product_info(product_code, "VersionString", version, version_length)
-          
+
           return nil if status == 1605 # ERROR_UNKNOWN_PRODUCT (0x645)
-         
+
           # We expect error ERROR_MORE_DATA (234) here because we passed a buffer length of 0
           if status != 234
             msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
@@ -149,16 +148,16 @@ UINT MsiCloseHandle(
 
           version_length = FFI::Buffer.new(:long).write_long(version_length.read_long + 1)
           version = 0.chr * version_length.read_long
-           
+
           status = msi_get_product_info(product_code, "VersionString", version, version_length)
-           
+
           if status != 0
             msg = "msi_get_product_info: product code '#{product_code}' returned unknown error #{status} when retrieving VersionString: "
             msg << Chef::ReservedNames::Win32::Error.format_message(status)
             raise Chef::Exceptions::Package, msg
           end
 
-          version
+          version.chomp(0.chr)
         end
       end
     end
diff --git a/lib/chef/win32/api/memory.rb b/lib/chef/win32/api/memory.rb
index abd1191..a00ac5f 100644
--- a/lib/chef/win32/api/memory.rb
+++ b/lib/chef/win32/api/memory.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -48,7 +48,7 @@ class Chef
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32'
+        ffi_lib "kernel32"
 
 =begin
 HLOCAL WINAPI LocalAlloc(
diff --git a/lib/chef/win32/api/net.rb b/lib/chef/win32/api/net.rb
index eeb2b07..bec00f6 100644
--- a/lib/chef/win32/api/net.rb
+++ b/lib/chef/win32/api/net.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
+require "chef/win32/unicode"
 
 class Chef
   module ReservedNames::Win32
@@ -32,12 +33,65 @@ class Chef
 
         MAX_PREFERRED_LENGTH                = 0xFFFF
 
-        NERR_Success                        = 0
-        NERR_UserNotFound                   = 2221
+        DOMAIN_GROUP_RID_USERS = 0x00000201
+
+        UF_SCRIPT              = 0x000001
+        UF_ACCOUNTDISABLE      = 0x000002
+        UF_PASSWD_CANT_CHANGE  = 0x000040
+        UF_NORMAL_ACCOUNT      = 0x000200
+        UF_DONT_EXPIRE_PASSWD  = 0x010000
+
+        USE_NOFORCE = 0
+        USE_FORCE = 1
+        USE_LOTS_OF_FORCE = 2 #every windows API should support this flag
+
+        NERR_Success = 0
+        ERROR_MORE_DATA = 234
 
         ffi_lib "netapi32"
 
+        module StructHelpers
+          def set(key, val)
+            val = if val.is_a? String
+                    encoded = if val.encoding == Encoding::UTF_16LE
+                                val
+                              else
+                                val.to_wstring
+                              end
+                    FFI::MemoryPointer.from_string(encoded)
+                  else
+                    val
+                  end
+            self[key] = val
+          end
+
+          def get(key)
+            if respond_to? key
+              send(key)
+            else
+              val = self[key]
+              if val.is_a? FFI::Pointer
+                if val.null?
+                  nil
+                else
+                  val.read_wstring
+                end
+              else
+                val
+              end
+            end
+          end
+
+          def as_ruby
+            members.inject({}) do |memo, key|
+              memo[key] = get(key)
+              memo
+            end
+          end
+        end
+
         class USER_INFO_3 < FFI::Struct
+          include StructHelpers
           layout :usri3_name, :LPWSTR,
             :usri3_password, :LPWSTR,
             :usri3_password_age, :DWORD,
@@ -67,24 +121,191 @@ class Chef
             :usri3_profile, :LPWSTR,
             :usri3_home_dir_drive, :LPWSTR,
             :usri3_password_expired, :DWORD
+
+          def usri3_logon_hours
+            val = self[:usri3_logon_hours]
+            if !val.nil? && !val.null?
+              val.read_bytes(21)
+            else
+              nil
+            end
+          end
+        end
+
+        class LOCALGROUP_MEMBERS_INFO_0 < FFI::Struct
+          layout :lgrmi0_sid, :PSID
+        end
+
+        class LOCALGROUP_MEMBERS_INFO_3 < FFI::Struct
+          layout :lgrmi3_domainandname, :LPWSTR
+        end
+
+        class LOCALGROUP_INFO_0 < FFI::Struct
+          layout :lgrpi0_name, :LPWSTR
+        end
+
+        class USE_INFO_2 < FFI::Struct
+          include StructHelpers
+
+          layout :ui2_local, :LMSTR,
+            :ui2_remote, :LMSTR,
+            :ui2_password, :LMSTR,
+            :ui2_status, :DWORD,
+            :ui2_asg_type, :DWORD,
+            :ui2_refcount, :DWORD,
+            :ui2_usecount, :DWORD,
+            :ui2_username, :LPWSTR,
+            :ui2_domainname, :LMSTR
         end
 
-# NET_API_STATUS NetUserEnum(
-#   _In_     LPCWSTR servername,
-#   _In_     DWORD level,
-#   _In_     DWORD filter,
-#   _Out_    LPBYTE *bufptr,
-#   _In_     DWORD prefmaxlen,
-#   _Out_    LPDWORD entriesread,
-#   _Out_    LPDWORD totalentries,
-#   _Inout_  LPDWORD resume_handle
-# );
-        safe_attach_function :NetUserEnum, [ :LPCWSTR, :DWORD, :DWORD, :LPBYTE, :DWORD, :LPDWORD, :LPDWORD, :LPDWORD ], :DWORD
-
-# NET_API_STATUS NetApiBufferFree(
-#   _In_  LPVOID Buffer
-# );
-        safe_attach_function :NetApiBufferFree, [ :LPVOID ], :DWORD
+        #NET_API_STATUS NetLocalGroupAdd(
+        #_In_  LPCWSTR servername,
+        #_In_  DWORD   level,
+        #_In_  LPBYTE  buf,
+        #_Out_ LPDWORD parm_err
+        #);
+        safe_attach_function :NetLocalGroupAdd, [
+          :LPCWSTR, :DWORD, :LPBYTE, :LPDWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetLocalGroupDel(
+        #_In_ LPCWSTR servername,
+        #_In_ LPCWSTR groupname
+        #);
+        safe_attach_function :NetLocalGroupDel, [:LPCWSTR, :LPCWSTR], :DWORD
+
+        #NET_API_STATUS NetLocalGroupGetMembers(
+        #_In_    LPCWSTR    servername,
+        #_In_    LPCWSTR    localgroupname,
+        #_In_    DWORD      level,
+        #_Out_   LPBYTE     *bufptr,
+        #_In_    DWORD      prefmaxlen,
+        #_Out_   LPDWORD    entriesread,
+        #_Out_   LPDWORD    totalentries,
+        #_Inout_ PDWORD_PTR resumehandle
+        #);
+        safe_attach_function :NetLocalGroupGetMembers, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD,
+          :LPDWORD, :LPDWORD, :PDWORD_PTR
+        ], :DWORD
+
+        # NET_API_STATUS NetUserEnum(
+        #   _In_     LPCWSTR servername,
+        #   _In_     DWORD level,
+        #   _In_     DWORD filter,
+        #   _Out_    LPBYTE *bufptr,
+        #   _In_     DWORD prefmaxlen,
+        #   _Out_    LPDWORD entriesread,
+        #   _Out_    LPDWORD totalentries,
+        #   _Inout_  LPDWORD resume_handle
+        # );
+        safe_attach_function :NetUserEnum, [
+          :LPCWSTR, :DWORD, :DWORD, :LPBYTE,
+          :DWORD, :LPDWORD, :LPDWORD, :LPDWORD
+        ], :DWORD
+
+        # NET_API_STATUS NetApiBufferFree(
+        #   _In_  LPVOID Buffer
+        # );
+        safe_attach_function :NetApiBufferFree, [:LPVOID], :DWORD
+
+        #NET_API_STATUS NetUserAdd(
+        #_In_  LMSTR   servername,
+        #_In_  DWORD   level,
+        #_In_  LPBYTE  buf,
+        #_Out_ LPDWORD parm_err
+        #);
+        safe_attach_function :NetUserAdd, [
+          :LMSTR, :DWORD, :LPBYTE, :LPDWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetLocalGroupAddMembers(
+        #  _In_ LPCWSTR servername,
+        #  _In_ LPCWSTR groupname,
+        #  _In_ DWORD   level,
+        #  _In_ LPBYTE  buf,
+        #  _In_ DWORD   totalentries
+        #);
+        safe_attach_function :NetLocalGroupAddMembers, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetLocalGroupSetMembers(
+        #  _In_ LPCWSTR servername,
+        #  _In_ LPCWSTR groupname,
+        #  _In_ DWORD   level,
+        #  _In_ LPBYTE  buf,
+        #  _In_ DWORD   totalentries
+        #);
+        safe_attach_function :NetLocalGroupSetMembers, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetLocalGroupDelMembers(
+        #  _In_ LPCWSTR servername,
+        #  _In_ LPCWSTR groupname,
+        #  _In_ DWORD   level,
+        #  _In_ LPBYTE  buf,
+        #  _In_ DWORD   totalentries
+        #);
+        safe_attach_function :NetLocalGroupDelMembers, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :DWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetUserGetInfo(
+        #  _In_  LPCWSTR servername,
+        #  _In_  LPCWSTR username,
+        #  _In_  DWORD   level,
+        #  _Out_ LPBYTE  *bufptr
+        #);
+        safe_attach_function :NetUserGetInfo, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE
+        ], :DWORD
+
+        #NET_API_STATUS NetApiBufferFree(
+        #  _In_ LPVOID Buffer
+        #);
+        safe_attach_function :NetApiBufferFree, [:LPVOID], :DWORD
+
+        #NET_API_STATUS NetUserSetInfo(
+        #  _In_  LPCWSTR servername,
+        #  _In_  LPCWSTR username,
+        #  _In_  DWORD   level,
+        #  _In_  LPBYTE  buf,
+        #  _Out_ LPDWORD parm_err
+        #);
+        safe_attach_function :NetUserSetInfo, [
+          :LPCWSTR, :LPCWSTR, :DWORD, :LPBYTE, :LPDWORD
+        ], :DWORD
+
+        #NET_API_STATUS NetUserDel(
+        #  _In_ LPCWSTR servername,
+        #  _In_ LPCWSTR username
+        #);
+        safe_attach_function :NetUserDel, [:LPCWSTR, :LPCWSTR], :DWORD
+
+        #NET_API_STATUS NetUseDel(
+        #_In_ LMSTR UncServerName,
+        #_In_ LMSTR UseName,
+        #_In_ DWORD ForceCond
+        #);
+        safe_attach_function :NetUseDel, [:LMSTR, :LMSTR, :DWORD], :DWORD
+
+        #NET_API_STATUS NetUseGetInfo(
+        #_In_  LMSTR  UncServerName,
+        #_In_  LMSTR  UseName,
+        #_In_  DWORD  Level,
+        #_Out_ LPBYTE *BufPtr
+        #);
+        safe_attach_function :NetUseGetInfo, [:LMSTR, :LMSTR, :DWORD, :pointer], :DWORD
+
+        #NET_API_STATUS NetUseAdd(
+        #_In_  LMSTR   UncServerName,
+        #_In_  DWORD   Level,
+        #_In_  LPBYTE  Buf,
+        #_Out_ LPDWORD ParmError
+        #);
+        safe_attach_function :NetUseAdd, [:LMSTR, :DWORD, :LPBYTE, :LPDWORD], :DWORD
       end
     end
   end
diff --git a/lib/chef/win32/api/process.rb b/lib/chef/win32/api/process.rb
index 217880b..3568b7e 100644
--- a/lib/chef/win32/api/process.rb
+++ b/lib/chef/win32/api/process.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -28,7 +28,7 @@ class Chef
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32'
+        ffi_lib "kernel32"
 
         safe_attach_function :GetCurrentProcess, [], :HANDLE
         safe_attach_function :GetProcessHandleCount, [ :HANDLE, :LPDWORD ], :BOOL
diff --git a/lib/chef/win32/api/psapi.rb b/lib/chef/win32/api/psapi.rb
index 3a5df3f..9deb68d 100644
--- a/lib/chef/win32/api/psapi.rb
+++ b/lib/chef/win32/api/psapi.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -41,7 +41,7 @@ class Chef
             :PeakPagefileUsage, :SIZE_T
         end
 
-        ffi_lib 'psapi'
+        ffi_lib "psapi"
 
         safe_attach_function :GetProcessMemoryInfo, [ :HANDLE, :pointer, :DWORD ], :BOOL
 
diff --git a/lib/chef/win32/api/registry.rb b/lib/chef/win32/api/registry.rb
new file mode 100644
index 0000000..dec2511
--- /dev/null
+++ b/lib/chef/win32/api/registry.rb
@@ -0,0 +1,51 @@
+#
+# Author:: Salim Alam (<salam at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api"
+
+class Chef
+  module ReservedNames::Win32
+    module API
+      module Registry
+        extend Chef::ReservedNames::Win32::API
+
+        ###############################################
+        # Win32 API Bindings
+        ###############################################
+
+        ffi_lib "advapi32"
+
+        # LONG WINAPI RegDeleteKeyEx(
+        #   _In_       HKEY    hKey,
+        #   _In_       LPCTSTR lpSubKey,
+        #   _In_       REGSAM  samDesired,
+        #   _Reserved_ DWORD   Reserved
+        # );
+        safe_attach_function :RegDeleteKeyExW, [ :HKEY, :LPCTSTR, :LONG, :DWORD ], :LONG
+        safe_attach_function :RegDeleteKeyExA, [ :HKEY, :LPCTSTR, :LONG, :DWORD ], :LONG
+
+        # LONG WINAPI RegDeleteValue(
+        #   _In_     HKEY    hKey,
+        #   _In_opt_ LPCTSTR lpValueName
+        # );
+        safe_attach_function :RegDeleteValueW, [ :HKEY, :LPCTSTR ], :LONG
+
+      end
+    end
+  end
+end
diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb
index 229f2ac..4496837 100644
--- a/lib/chef/win32/api/security.rb
+++ b/lib/chef/win32/api/security.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -136,20 +136,10 @@ class Chef
                                      SYNCHRONIZE |
                                      0x1FF
         FILE_GENERIC_READ          = STANDARD_RIGHTS_READ |
-                                     FILE_READ_DATA       |
-                                     FILE_READ_ATTRIBUTES |
-                                     FILE_READ_EA         |
-                                     SYNCHRONIZE
-        FILE_GENERIC_WRITE         = STANDARD_RIGHTS_WRITE    |
-                                     FILE_WRITE_DATA          |
-                                     FILE_WRITE_ATTRIBUTES    |
-                                     FILE_WRITE_EA            |
-                                     FILE_APPEND_DATA         |
-                                     SYNCHRONIZE
-        FILE_GENERIC_EXECUTE       = STANDARD_RIGHTS_EXECUTE  |
-                                     FILE_READ_ATTRIBUTES     |
-                                     FILE_EXECUTE             |
-                                     SYNCHRONIZE
+                                     FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+                                     FILE_READ_EA | SYNCHRONIZE
+        FILE_GENERIC_WRITE         = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE
+        FILE_GENERIC_EXECUTE       = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE
         # Access Token Rights (for OpenProcessToken)
         # Access Rights for Access-Token Objects (used in OpenProcessToken)
         TOKEN_ASSIGN_PRIMARY = 0x0001
@@ -173,9 +163,7 @@ class Chef
         SE_PRIVILEGE_REMOVED = 0X00000004
         SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
         SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT |
-                                         SE_PRIVILEGE_ENABLED            |
-                                         SE_PRIVILEGE_REMOVED            |
-                                         SE_PRIVILEGE_USED_FOR_ACCESS
+                                        SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS
 
         # Minimum size of a SECURITY_DESCRIPTOR.  TODO: this is probably platform dependent.
         # Make it work on 64 bit.
@@ -193,6 +181,35 @@ class Chef
 
         MAXDWORD = 0xffffffff
 
+        # LOGON32 constants for LogonUser
+        LOGON32_LOGON_INTERACTIVE = 2;
+        LOGON32_LOGON_NETWORK = 3;
+        LOGON32_LOGON_BATCH = 4;
+        LOGON32_LOGON_SERVICE = 5;
+        LOGON32_LOGON_UNLOCK = 7;
+        LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
+        LOGON32_LOGON_NEW_CREDENTIALS = 9;
+
+        LOGON32_PROVIDER_DEFAULT = 0;
+        LOGON32_PROVIDER_WINNT35 = 1;
+        LOGON32_PROVIDER_WINNT40 = 2;
+        LOGON32_PROVIDER_WINNT50 = 3;
+
+        # LSA access policy
+        POLICY_VIEW_LOCAL_INFORMATION = 0x00000001
+        POLICY_VIEW_AUDIT_INFORMATION = 0x00000002
+        POLICY_GET_PRIVATE_INFORMATION = 0x00000004
+        POLICY_TRUST_ADMIN = 0x00000008
+        POLICY_CREATE_ACCOUNT = 0x00000010
+        POLICY_CREATE_SECRET = 0x00000020
+        POLICY_CREATE_PRIVILEGE = 0x00000040
+        POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080
+        POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100
+        POLICY_AUDIT_LOG_ADMIN = 0x00000200
+        POLICY_SERVER_ADMIN = 0x00000400
+        POLICY_LOOKUP_NAMES = 0x00000800
+        POLICY_NOTIFICATION = 0x00001000
+
         ###############################################
         # Win32 API Bindings
         ###############################################
@@ -210,7 +227,7 @@ class Chef
              :SE_DS_OBJECT_ALL,
              :SE_PROVIDER_DEFINED_OBJECT,
              :SE_WMIGUID_OBJECT,
-             :SE_REGISTRY_WOW64_32KEY
+             :SE_REGISTRY_WOW64_32KEY,
         ]
 
         SID_NAME_USE = enum :SID_NAME_USE, [
@@ -270,15 +287,22 @@ class Chef
              :MaxTokenInfoClass
         ]
 
+        class TOKEN_OWNER < FFI::Struct
+          layout :Owner, :pointer
+        end
+
+        class TOKEN_PRIMARY_GROUP < FFI::Struct
+          layout :PrimaryGroup, :pointer
+        end
+
         # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572%28v=vs.85%29.aspx
         SECURITY_IMPERSONATION_LEVEL = enum :SECURITY_IMPERSONATION_LEVEL, [
              :SecurityAnonymous,
              :SecurityIdentification,
              :SecurityImpersonation,
-             :SecurityDelegation
+             :SecurityDelegation,
         ]
 
-
         # SECURITY_DESCRIPTOR is an opaque structure whose contents can vary.  Pass the
         # pointer around and free it with LocalFree.
         # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx
@@ -314,7 +338,7 @@ class Chef
               ACCESS_ALLOWED_ACE_TYPE,
               ACCESS_DENIED_ACE_TYPE,
               SYSTEM_AUDIT_ACE_TYPE,
-              SYSTEM_ALARM_ACE_TYPE
+              SYSTEM_ALARM_ACE_TYPE,
             ].include?(ace_type)
           end
         end
@@ -347,7 +371,7 @@ class Chef
                  :Privileges, LUID_AND_ATTRIBUTES
 
           def self.size_with_privileges(num_privileges)
-            offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size*num_privileges
+            offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size * num_privileges
           end
 
           def size_with_privileges
@@ -359,6 +383,23 @@ class Chef
           end
         end
 
+        # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721829(v=vs.85).aspx
+        class LSA_OBJECT_ATTRIBUTES < FFI::Struct
+          layout :Length, :ULONG,
+                 :RootDirectory, :HANDLE,
+                 :ObjectName, :pointer,
+                 :Attributes, :ULONG,
+                 :SecurityDescriptor, :PVOID,
+                 :SecurityQualityOfService, :PVOID
+        end
+
+        # https://msdn.microsoft.com/en-us/library/windows/desktop/ms721841(v=vs.85).aspx
+        class LSA_UNICODE_STRING < FFI::Struct
+          layout :Length, :USHORT,
+                 :MaximumLength, :USHORT,
+                 :Buffer, :PWSTR
+        end
+
         ffi_lib "advapi32"
 
         safe_attach_function :AccessCheck, [:pointer, :HANDLE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer], :BOOL
@@ -377,7 +418,7 @@ class Chef
         safe_attach_function :GetAce, [ :pointer, :DWORD, :pointer ], :BOOL
         safe_attach_function :GetFileSecurityW, [:LPCWSTR, :DWORD, :pointer, :DWORD, :pointer], :BOOL
         safe_attach_function :GetLengthSid, [ :pointer ], :DWORD
-        safe_attach_function :GetNamedSecurityInfoW,  [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD
+        safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD
         safe_attach_function :GetSecurityDescriptorControl, [ :pointer, :PWORD, :LPDWORD], :BOOL
         safe_attach_function :GetSecurityDescriptorDacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL
         safe_attach_function :GetSecurityDescriptorGroup, [ :pointer, :pointer, :LPBOOL], :BOOL
@@ -393,6 +434,12 @@ class Chef
         safe_attach_function :LookupPrivilegeNameW, [ :LPCWSTR, :PLUID, :LPWSTR, :LPDWORD ], :BOOL
         safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL
         safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL
+        safe_attach_function :LsaAddAccountRights, [ :pointer, :pointer, :pointer, :ULONG ], :NTSTATUS
+        safe_attach_function :LsaClose, [ :LSA_HANDLE ], :NTSTATUS
+        safe_attach_function :LsaEnumerateAccountRights, [ :LSA_HANDLE, :PSID, :PLSA_UNICODE_STRING, :PULONG ], :NTSTATUS
+        safe_attach_function :LsaFreeMemory, [ :PVOID ], :NTSTATUS
+        safe_attach_function :LsaNtStatusToWinError, [ :NTSTATUS ], :ULONG
+        safe_attach_function :LsaOpenPolicy, [ :PLSA_UNICODE_STRING, :PLSA_OBJECT_ATTRIBUTES, :DWORD, :PLSA_HANDLE ], :NTSTATUS
         safe_attach_function :MakeAbsoluteSD, [ :pointer, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD], :BOOL
         safe_attach_function :MapGenericMask, [ :PDWORD, :PGENERICMAPPING ], :void
         safe_attach_function :OpenProcessToken, [ :HANDLE, :DWORD, :PHANDLE ], :BOOL
@@ -405,6 +452,8 @@ class Chef
         safe_attach_function :SetSecurityDescriptorOwner, [ :pointer, :pointer, :BOOL ], :BOOL
         safe_attach_function :SetSecurityDescriptorSacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL
         safe_attach_function :GetTokenInformation, [ :HANDLE, :TOKEN_INFORMATION_CLASS, :pointer, :DWORD, :PDWORD ], :BOOL
+        safe_attach_function :LogonUserW, [:LPTSTR, :LPTSTR, :LPTSTR, :DWORD, :DWORD, :PHANDLE], :BOOL
+
       end
     end
   end
diff --git a/lib/chef/win32/api/synchronization.rb b/lib/chef/win32/api/synchronization.rb
index 9c148d7..9b5d5c6 100644
--- a/lib/chef/win32/api/synchronization.rb
+++ b/lib/chef/win32/api/synchronization.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -24,7 +24,7 @@ class Chef
       module Synchronization
         extend Chef::ReservedNames::Win32::API
 
-        ffi_lib 'kernel32'
+        ffi_lib "kernel32"
 
         # Constant synchronization functions use to indicate wait
         # forever.
diff --git a/lib/chef/win32/api/system.rb b/lib/chef/win32/api/system.rb
index d57699a..732ed07 100644
--- a/lib/chef/win32/api/system.rb
+++ b/lib/chef/win32/api/system.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -132,7 +132,7 @@ class Chef
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32', 'user32'
+        ffi_lib "kernel32", "user32"
 
         class OSVERSIONINFOEX < FFI::Struct
           layout :dw_os_version_info_size, :DWORD,
@@ -187,6 +187,29 @@ int WINAPI GetSystemMetrics(
         safe_attach_function :GetSystemMetrics, [:int], :int
 
 =begin
+UINT WINAPI GetSystemWow64Directory(
+  _Out_ LPTSTR lpBuffer,
+  _In_  UINT   uSize
+);
+=end
+        safe_attach_function :GetSystemWow64DirectoryW, [:LPTSTR, :UINT], :UINT
+        safe_attach_function :GetSystemWow64DirectoryA, [:LPTSTR, :UINT], :UINT
+
+=begin
+BOOL WINAPI Wow64DisableWow64FsRedirection(
+  _Out_ PVOID *OldValue
+);
+=end
+        safe_attach_function :Wow64DisableWow64FsRedirection, [:PVOID], :BOOL
+
+=begin
+BOOL WINAPI Wow64RevertWow64FsRedirection(
+  _In_ PVOID OldValue
+);
+=end
+        safe_attach_function :Wow64RevertWow64FsRedirection, [:PVOID], :BOOL
+
+=begin
 LRESULT WINAPI SendMessageTimeout(
   _In_       HWND hWnd,
   _In_       UINT Msg,
diff --git a/lib/chef/win32/api/unicode.rb b/lib/chef/win32/api/unicode.rb
index 0b2cb09..21ddde2 100644
--- a/lib/chef/win32/api/unicode.rb
+++ b/lib/chef/win32/api/unicode.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
+require "chef/win32/api"
 
 class Chef
   module ReservedNames::Win32
@@ -92,7 +92,7 @@ class Chef
         # Win32 API Bindings
         ###############################################
 
-        ffi_lib 'kernel32', 'advapi32'
+        ffi_lib "kernel32", "advapi32"
 
 =begin
 BOOL IsTextUnicode(
@@ -129,49 +129,6 @@ int WideCharToMultiByte(
 =end
         safe_attach_function :WideCharToMultiByte, [:UINT, :DWORD, :LPCWSTR, :int, :LPSTR, :int, :LPCSTR, :LPBOOL], :int
 
-        ###############################################
-        # Helpers
-        ###############################################
-
-        def utf8_to_wide(ustring)
-          # ensure it is actually UTF-8
-          # Ruby likes to mark binary data as ASCII-8BIT
-          ustring = (ustring + "").force_encoding('UTF-8') if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8"
-
-          # ensure we have the double-null termination Windows Wide likes
-          ustring = ustring + "\000\000" if ustring[-1].chr != "\000"
-
-          # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode
-          ustring = begin
-            if ustring.respond_to?(:encode)
-              ustring.encode('UTF-16LE')
-            else
-              require 'iconv'
-              Iconv.conv("UTF-16LE", "UTF-8", ustring)
-            end
-          end
-          ustring
-        end
-
-        def wide_to_utf8(wstring)
-          # ensure it is actually UTF-16LE
-          # Ruby likes to mark binary data as ASCII-8BIT
-          wstring = wstring.force_encoding('UTF-16LE') if wstring.respond_to?(:force_encoding)
-
-          # encode it all as UTF-8
-          wstring = begin
-            if wstring.respond_to?(:encode)
-              wstring.encode('UTF-8')
-            else
-              require 'iconv'
-              Iconv.conv("UTF-8", "UTF-16LE", wstring)
-            end
-          end
-          # remove trailing CRLF and NULL characters
-          wstring.strip!
-          wstring
-        end
-
       end
     end
   end
diff --git a/lib/chef/win32/crypto.rb b/lib/chef/win32/crypto.rb
index 79cf51b..9832f9e 100644
--- a/lib/chef/win32/crypto.rb
+++ b/lib/chef/win32/crypto.rb
@@ -1,49 +1,50 @@
-#
-# Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright 2015 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/win32/error'
-require 'chef/win32/api/memory'
-require 'chef/win32/api/crypto'
-require 'digest'
-
-class Chef
-  module ReservedNames::Win32
-    class Crypto
-      include Chef::ReservedNames::Win32::API::Crypto
-      extend Chef::ReservedNames::Win32::API::Crypto
-
-      def self.encrypt(str, &block)
-        data_blob = CRYPT_INTEGER_BLOB.new
-        unless CryptProtectData(CRYPT_INTEGER_BLOB.new(str.to_wstring), nil, nil, nil, nil, 0, data_blob)
-          Chef::ReservedNames::Win32::Error.raise!
-        end
-        bytes = data_blob[:pbData].get_bytes(0, data_blob[:cbData])
-        if block
-          block.call(bytes)
-        else
-          Digest.hexencode(bytes)
-        end
-      ensure
-        unless data_blob[:pbData].null?
-          Chef::ReservedNames::Win32::Memory.local_free(data_blob[:pbData])
-        end
-      end
-
-    end
-  end
-end
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/error"
+require "chef/win32/api/memory"
+require "chef/win32/api/crypto"
+require "chef/win32/unicode"
+require "digest"
+
+class Chef
+  module ReservedNames::Win32
+    class Crypto
+      include Chef::ReservedNames::Win32::API::Crypto
+      extend Chef::ReservedNames::Win32::API::Crypto
+
+      def self.encrypt(str, &block)
+        data_blob = CRYPT_INTEGER_BLOB.new
+        unless CryptProtectData(CRYPT_INTEGER_BLOB.new(str.to_wstring), nil, nil, nil, nil, CRYPTPROTECT_LOCAL_MACHINE, data_blob)
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        bytes = data_blob[:pbData].get_bytes(0, data_blob[:cbData])
+        if block
+          block.call(bytes)
+        else
+          Digest.hexencode(bytes)
+        end
+      ensure
+        unless data_blob[:pbData].null?
+          Chef::ReservedNames::Win32::Memory.local_free(data_blob[:pbData])
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/win32/error.rb b/lib/chef/win32/error.rb
index 2175608..8c3ff2f 100644
--- a/lib/chef/win32/error.rb
+++ b/lib/chef/win32/error.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/error'
-require 'chef/win32/memory'
-require 'chef/win32/unicode'
-require 'chef/exceptions'
+require "chef/win32/api/error"
+require "chef/win32/memory"
+require "chef/win32/unicode"
+require "chef/exceptions"
 
 class Chef
   module ReservedNames::Win32
@@ -57,16 +57,19 @@ class Chef
       # nil::: always returns nil when it does not raise
       # === Raises
       # Chef::Exceptions::Win32APIError:::
-      def self.raise!(message = nil)
-        code = get_last_error
+      def self.raise!(message = nil, code = get_last_error)
         msg = format_message(code).strip
-        formatted_message = ""
-        formatted_message << message if message
-        formatted_message << "---- Begin Win32 API output ----\n"
-        formatted_message << "System Error Code: #{code}\n"
-        formatted_message << "System Error Message: #{msg}\n"
-        formatted_message << "---- End Win32 API output ----\n"
-        raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message
+        if code == ERROR_USER_NOT_FOUND
+          raise Chef::Exceptions::UserIDNotFound, msg
+        else
+          formatted_message = ""
+          formatted_message << message if message
+          formatted_message << "---- Begin Win32 API output ----\n"
+          formatted_message << "System Error Code: #{code}\n"
+          formatted_message << "System Error Message: #{msg}\n"
+          formatted_message << "---- End Win32 API output ----\n"
+          raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message
+        end
       end
     end
   end
diff --git a/lib/chef/win32/eventlog.rb b/lib/chef/win32/eventlog.rb
new file mode 100644
index 0000000..0562f0c
--- /dev/null
+++ b/lib/chef/win32/eventlog.rb
@@ -0,0 +1,31 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+if Chef::Platform::windows? and not Chef::Platform::windows_server_2003?
+  if !defined? Chef::Win32EventLogLoaded
+    if defined? Windows::Constants
+      [:INFINITE, :WAIT_FAILED, :FORMAT_MESSAGE_IGNORE_INSERTS, :ERROR_INSUFFICIENT_BUFFER].each do |c|
+        # These are redefined in 'win32/eventlog'
+        Windows::Constants.send(:remove_const, c) if Windows::Constants.const_defined? c
+      end
+    end
+
+    require "win32/eventlog"
+    Chef::Win32EventLogLoaded = true
+  end
+end
diff --git a/lib/chef/win32/file.rb b/lib/chef/win32/file.rb
index e6640ca..19b17b7 100644
--- a/lib/chef/win32/file.rb
+++ b/lib/chef/win32/file.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
 # Author:: Mark Mzyk (<mmzyk at ospcode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,11 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/file'
-require 'chef/win32/api/security'
-require 'chef/win32/error'
+require "chef/mixin/wide_string"
+require "chef/win32/api/file"
+require "chef/win32/api/security"
+require "chef/win32/error"
+require "chef/win32/unicode"
 
 class Chef
   module ReservedNames::Win32
@@ -27,6 +29,9 @@ class Chef
       include Chef::ReservedNames::Win32::API::File
       extend Chef::ReservedNames::Win32::API::File
 
+      include Chef::Mixin::WideString
+      extend Chef::Mixin::WideString
+
       # Creates a symbolic link called +new_name+ for the file or directory
       # +old_name+.
       #
@@ -120,8 +125,8 @@ class Chef
         if size == 0
           Chef::ReservedNames::Win32::Error.raise!
         end
-        result = FFI::MemoryPointer.new :char, (size+1)*2
-        if GetShortPathNameW(path, result, size+1) == 0
+        result = FFI::MemoryPointer.new :char, (size + 1) * 2
+        if GetShortPathNameW(path, result, size + 1) == 0
           Chef::ReservedNames::Win32::Error.raise!
         end
         result.read_wstring(size)
@@ -134,8 +139,8 @@ class Chef
         if size == 0
           Chef::ReservedNames::Win32::Error.raise!
         end
-        result = FFI::MemoryPointer.new :char, (size+1)*2
-        if GetLongPathNameW(path, result, size+1) == 0
+        result = FFI::MemoryPointer.new :char, (size + 1) * 2
+        if GetLongPathNameW(path, result, size + 1) == 0
           Chef::ReservedNames::Win32::Error.raise!
         end
         result.read_wstring(size)
@@ -145,6 +150,10 @@ class Chef
         Info.new(file_name)
       end
 
+      def self.version_info(file_name)
+        VersionInfo.new(file_name)
+      end
+
       def self.verify_links_supported!
         begin
           CreateSymbolicLinkW(nil)
@@ -157,9 +166,9 @@ class Chef
 
       def self.file_access_check(path, desired_access)
         security_descriptor = Chef::ReservedNames::Win32::Security.get_file_security(path)
-        token_rights = Chef::ReservedNames::Win32::Security::TOKEN_IMPERSONATE | 
+        token_rights = Chef::ReservedNames::Win32::Security::TOKEN_IMPERSONATE |
                        Chef::ReservedNames::Win32::Security::TOKEN_QUERY |
-                       Chef::ReservedNames::Win32::Security::TOKEN_DUPLICATE | 
+                       Chef::ReservedNames::Win32::Security::TOKEN_DUPLICATE |
                        Chef::ReservedNames::Win32::Security::STANDARD_RIGHTS_READ
         token = Chef::ReservedNames::Win32::Security.open_process_token(
           Chef::ReservedNames::Win32::Process.get_current_process,
@@ -172,10 +181,30 @@ class Chef
         mapping[:GenericExecute] = Chef::ReservedNames::Win32::Security::FILE_GENERIC_EXECUTE
         mapping[:GenericAll] = Chef::ReservedNames::Win32::Security::FILE_ALL_ACCESS
 
-        Chef::ReservedNames::Win32::Security.access_check(security_descriptor, duplicate_token, 
+        Chef::ReservedNames::Win32::Security.access_check(security_descriptor, duplicate_token,
                                                           desired_access, mapping)
       end
 
+      def self.delete_volume_mount_point(mount_point)
+        unless DeleteVolumeMountPointW(wstring(mount_point))
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+      end
+
+      def self.set_volume_mount_point(mount_point, name)
+        unless SetVolumeMountPointW(wstring(mount_point), wstring(name))
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+      end
+
+      def self.get_volume_name_for_volume_mount_point(mount_point)
+        buffer = FFI::MemoryPointer.new(2, 128)
+        unless GetVolumeNameForVolumeMountPointW(wstring(mount_point), buffer, buffer.size / buffer.type_size)
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        buffer.read_wstring
+      end
+
       # ::File compat
       class << self
         alias :stat :info
@@ -185,4 +214,5 @@ class Chef
   end
 end
 
-require 'chef/win32/file/info'
+require "chef/win32/file/info"
+require "chef/win32/file/version_info"
diff --git a/lib/chef/win32/file/info.rb b/lib/chef/win32/file/info.rb
index 0f07428..55873f8 100644
--- a/lib/chef/win32/file/info.rb
+++ b/lib/chef/win32/file/info.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/file'
+require "chef/win32/file"
 
 class Chef
   module ReservedNames::Win32
@@ -93,7 +93,6 @@ class Chef
             file_time_struct[:dw_high_date_time]))
         end
 
-
       end
     end
   end
diff --git a/lib/chef/win32/file/version_info.rb b/lib/chef/win32/file/version_info.rb
new file mode 100644
index 0000000..fa04096
--- /dev/null
+++ b/lib/chef/win32/file/version_info.rb
@@ -0,0 +1,93 @@
+#
+# Author:: Matt Wrock (<matt at mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/file"
+
+class Chef
+  module ReservedNames::Win32
+    class File
+
+      class VersionInfo
+
+        include Chef::ReservedNames::Win32::API::File
+
+        def initialize(file_name)
+          raise Errno::ENOENT, file_name unless ::File.exist?(file_name)
+          @file_version_info = retrieve_file_version_info(file_name)
+        end
+
+        # defining method for each predefined version resource string
+        # see https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx
+        [
+          :Comments,
+          :CompanyName,
+          :FileDescription,
+          :FileVersion,
+          :InternalName,
+          :LegalCopyright,
+          :LegalTrademarks,
+          :OriginalFilename,
+          :ProductName,
+          :ProductVersion,
+          :PrivateBuild,
+          :SpecialBuild,
+        ].each do |method|
+          define_method method do
+            begin
+              get_version_info_string(method.to_s)
+            rescue Chef::Exceptions::Win32APIError
+              return nil
+            end
+          end
+        end
+
+        private
+
+        def translation
+          @translation ||= begin
+            info_ptr = FFI::MemoryPointer.new(:pointer)
+            unless VerQueryValueW(@file_version_info, "\\VarFileInfo\\Translation".to_wstring, info_ptr, FFI::MemoryPointer.new(:int))
+              Chef::ReservedNames::Win32::Error.raise!
+            end
+
+            # there can potentially be multiple translations but most installers just have one
+            # we use the first because we use this for the version strings which are language
+            # agnostic. If/when we need other fields, we should we should add logic to find
+            # the "best" translation
+            trans = Translation.new(info_ptr.read_pointer)
+            to_hex(trans[:w_lang]) + to_hex(trans[:w_code_page])
+          end
+        end
+
+        def to_hex(integer)
+          integer.to_s(16).rjust(4, "0")
+        end
+
+        def get_version_info_string(string_key)
+          info_ptr = FFI::MemoryPointer.new(:pointer)
+          size_ptr = FFI::MemoryPointer.new(:int)
+          unless VerQueryValueW(@file_version_info, "\\StringFileInfo\\#{translation}\\#{string_key}".to_wstring, info_ptr, size_ptr)
+            Chef::ReservedNames::Win32::Error.raise!
+          end
+
+          info_ptr.read_pointer.read_wstring(size_ptr.read_uint)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/chef/win32/handle.rb b/lib/chef/win32/handle.rb
index 21a8fdf..3ebb698 100644
--- a/lib/chef/win32/handle.rb
+++ b/lib/chef/win32/handle.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/process'
-require 'chef/win32/api/psapi'
-require 'chef/win32/api/system'
-require 'chef/win32/error'
+require "chef/win32/api/process"
+require "chef/win32/api/psapi"
+require "chef/win32/api/system"
+require "chef/win32/error"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/memory.rb b/lib/chef/win32/memory.rb
index 8a61d27..49dcdfb 100644
--- a/lib/chef/win32/memory.rb
+++ b/lib/chef/win32/memory.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/win32/error'
-require 'chef/win32/api/memory'
+require "chef/win32/error"
+require "chef/win32/api/memory"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/mutex.rb b/lib/chef/win32/mutex.rb
index 0b7d99f..a14a160 100644
--- a/lib/chef/win32/mutex.rb
+++ b/lib/chef/win32/mutex.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/synchronization'
+require "chef/win32/api/synchronization"
+require "chef/win32/unicode"
 
 class Chef
   module ReservedNames::Win32
@@ -78,7 +79,7 @@ class Chef
           # of the process goes away and this class is only being used
           # to synchronize chef-clients runs on a node.
           Chef::Log.error("Can not release mutex '#{name}'. This might cause issues \
-if the mutex is attempted to be acquired by other threads.")
+if other threads attempt to acquire the mutex.")
           Chef::ReservedNames::Win32::Error.raise!
         end
       end
@@ -113,5 +114,3 @@ if the mutex is attempted to be acquired by other threads.")
     end
   end
 end
-
-
diff --git a/lib/chef/win32/net.rb b/lib/chef/win32/net.rb
new file mode 100644
index 0000000..0454b17
--- /dev/null
+++ b/lib/chef/win32/net.rb
@@ -0,0 +1,311 @@
+#
+# Author:: Jay Mundrawala(<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api/net"
+require "chef/win32/error"
+require "chef/mixin/wide_string"
+
+class Chef
+  module ReservedNames::Win32
+    class Net
+      include Chef::ReservedNames::Win32::API::Error
+      extend Chef::ReservedNames::Win32::API::Error
+
+      include Chef::ReservedNames::Win32::API::Net
+      extend Chef::ReservedNames::Win32::API::Net
+
+      include Chef::Mixin::WideString
+      extend Chef::Mixin::WideString
+
+      def self.default_user_info_3
+        ui3 = USER_INFO_3.new.tap do |s|
+          { usri3_name: nil,
+            usri3_password: nil,
+            usri3_password_age: 0,
+            usri3_priv: 0,
+            usri3_home_dir: nil,
+            usri3_comment: nil,
+            usri3_flags: UF_SCRIPT | UF_DONT_EXPIRE_PASSWD | UF_NORMAL_ACCOUNT,
+            usri3_script_path: nil,
+            usri3_auth_flags: 0,
+            usri3_full_name: nil,
+            usri3_usr_comment: nil,
+            usri3_parms: nil,
+            usri3_workstations: nil,
+            usri3_last_logon: 0,
+            usri3_last_logoff: 0,
+            usri3_acct_expires: -1,
+            usri3_max_storage: -1,
+            usri3_units_per_week: 0,
+            usri3_logon_hours: nil,
+            usri3_bad_pw_count: 0,
+            usri3_num_logons: 0,
+            usri3_logon_server: nil,
+            usri3_country_code: 0,
+            usri3_code_page: 0,
+            usri3_user_id: 0,
+            usri3_primary_group_id: DOMAIN_GROUP_RID_USERS,
+            usri3_profile: nil,
+            usri3_home_dir_drive: nil,
+            usri3_password_expired: 0,
+          }.each do |(k, v)|
+            s.set(k, v)
+          end
+        end
+      end
+
+      def self.net_local_group_add(server_name, group_name)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        buf = LOCALGROUP_INFO_0.new
+        buf[:lgrpi0_name] = FFI::MemoryPointer.from_string(group_name)
+
+        rc = NetLocalGroupAdd(server_name, 0, buf, nil)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_local_group_del(server_name, group_name)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        rc = NetLocalGroupDel(server_name, group_name)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_local_group_get_members(server_name, group_name)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        buf = FFI::MemoryPointer.new(:pointer)
+        entries_read_ptr = FFI::MemoryPointer.new(:long)
+        total_read_ptr = FFI::MemoryPointer.new(:long)
+        resume_handle_ptr = FFI::MemoryPointer.new(:pointer)
+
+        rc = ERROR_MORE_DATA
+        group_members = []
+        while rc == ERROR_MORE_DATA
+          rc = NetLocalGroupGetMembers(
+            server_name, group_name, 0, buf, -1,
+            entries_read_ptr, total_read_ptr, resume_handle_ptr
+          )
+
+          nread = entries_read_ptr.read_long
+          nread.times do |i|
+            member = LOCALGROUP_MEMBERS_INFO_0.new(buf.read_pointer +
+                                                   (i * LOCALGROUP_MEMBERS_INFO_0.size))
+            member_sid = Chef::ReservedNames::Win32::Security::SID.new(member[:lgrmi0_sid])
+            group_members << member_sid.to_s
+          end
+          NetApiBufferFree(buf.read_pointer)
+        end
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+
+        group_members
+      end
+
+      def self.net_user_add_l3(server_name, args)
+        buf = default_user_info_3
+
+        args.each do |k, v|
+          buf.set(k, v)
+        end
+
+        server_name = wstring(server_name)
+
+        rc = NetUserAdd(server_name, 3, buf, nil)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_user_get_info_l3(server_name, user_name)
+        server_name = wstring(server_name)
+        user_name = wstring(user_name)
+
+        ui3_p = FFI::MemoryPointer.new(:pointer)
+
+        rc = NetUserGetInfo(server_name, user_name, 3, ui3_p)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+
+        ui3 = USER_INFO_3.new(ui3_p.read_pointer).as_ruby
+
+        rc = NetApiBufferFree(ui3_p.read_pointer)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+
+        ui3
+      end
+
+      def self.net_user_set_info_l3(server_name, user_name, info)
+        buf = default_user_info_3
+
+        info.each do |k, v|
+          buf.set(k, v)
+        end
+
+        server_name = wstring(server_name)
+        user_name = wstring(user_name)
+
+        rc = NetUserSetInfo(server_name, user_name, 3, buf, nil)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_user_del(server_name, user_name)
+        server_name = wstring(server_name)
+        user_name = wstring(user_name)
+
+        rc = NetUserDel(server_name, user_name)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_local_group_add_member(server_name, group_name, domain_user)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+        domain_user = wstring(domain_user)
+
+        buf = LOCALGROUP_MEMBERS_INFO_3.new
+        buf[:lgrmi3_domainandname] = FFI::MemoryPointer.from_string(domain_user)
+
+        rc = NetLocalGroupAddMembers(server_name, group_name, 3, buf, 1)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.members_to_lgrmi3(members)
+        buf = FFI::MemoryPointer.new(LOCALGROUP_MEMBERS_INFO_3, members.size)
+        members.size.times.collect do |i|
+          member_info = LOCALGROUP_MEMBERS_INFO_3.new(
+            buf + i * LOCALGROUP_MEMBERS_INFO_3.size)
+          member_info[:lgrmi3_domainandname] = FFI::MemoryPointer.from_string(wstring(members[i]))
+          member_info
+        end
+      end
+
+      def self.net_local_group_add_members(server_name, group_name, members)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        lgrmi3s = members_to_lgrmi3(members)
+        rc = NetLocalGroupAddMembers(
+          server_name, group_name, 3, lgrmi3s[0], members.size)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_local_group_set_members(server_name, group_name, members)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        lgrmi3s = members_to_lgrmi3(members)
+        rc = NetLocalGroupSetMembers(
+          server_name, group_name, 3, lgrmi3s[0], members.size)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_local_group_del_members(server_name, group_name, members)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        lgrmi3s = members_to_lgrmi3(members)
+        rc = NetLocalGroupDelMembers(
+          server_name, group_name, 3, lgrmi3s[0], members.size)
+
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_use_del(server_name, use_name, force = :use_noforce)
+        server_name = wstring(server_name)
+        use_name = wstring(use_name)
+        force_const = case force
+                      when :use_noforce
+                        USE_NOFORCE
+                      when :use_force
+                        USE_FORCE
+                      when :use_lots_of_force
+                        USE_LOTS_OF_FORCE
+                      else
+                        raise ArgumentError, "force must be one of [:use_noforce, :use_force, or :use_lots_of_force]"
+                      end
+
+        rc = NetUseDel(server_name, use_name, force_const)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+
+      def self.net_use_get_info_l2(server_name, use_name)
+        server_name = wstring(server_name)
+        use_name = wstring(use_name)
+        ui2_p = FFI::MemoryPointer.new(:pointer)
+
+        rc = NetUseGetInfo(server_name, use_name, 2, ui2_p)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+
+        ui2 = USE_INFO_2.new(ui2_p.read_pointer).as_ruby
+        NetApiBufferFree(ui2_p.read_pointer)
+
+        ui2
+      end
+
+      def self.net_use_add_l2(server_name, ui2_hash)
+        server_name = wstring(server_name)
+        group_name = wstring(group_name)
+
+        buf = USE_INFO_2.new
+
+        ui2_hash.each do |(k, v)|
+          buf.set(k, v)
+        end
+
+        rc = NetUseAdd(server_name, 2, buf, nil)
+        if rc != NERR_Success
+          Chef::ReservedNames::Win32::Error.raise!(nil, rc)
+        end
+      end
+    end
+    NetUser = Net # For backwards compatibility
+  end
+end
diff --git a/lib/chef/win32/process.rb b/lib/chef/win32/process.rb
index 2df39bb..76e5263 100644
--- a/lib/chef/win32/process.rb
+++ b/lib/chef/win32/process.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/process'
-require 'chef/win32/api/psapi'
-require 'chef/win32/error'
-require 'chef/win32/handle'
-require 'ffi'
+require "chef/win32/api/process"
+require "chef/win32/api/psapi"
+require "chef/win32/error"
+require "chef/win32/handle"
+require "ffi"
 
 class Chef
   module ReservedNames::Win32
@@ -69,6 +69,19 @@ class Chef
         result
       end
 
+      def self.is_wow64_process
+        is_64_bit_process_result = FFI::MemoryPointer.new(:int)
+
+        # The return value of IsWow64Process is nonzero value if the API call succeeds.
+        # The result data are returned in the last parameter, not the return value.
+        call_succeeded = IsWow64Process(GetCurrentProcess(), is_64_bit_process_result)
+
+        # The result is nonzero if IsWow64Process's calling process, in the case here
+        # this process, is running under WOW64, i.e. the result is nonzero if this
+        # process is 32-bit (aka :i386).
+        (call_succeeded != 0) && (is_64_bit_process_result.get_int(0) != 0)
+      end
+
         # Must have PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION rights,
         # AND the PROCESS_VM_READ right
       def self.get_process_memory_info(handle)
diff --git a/lib/chef/win32/registry.rb b/lib/chef/win32/registry.rb
index 18f12d2..5f8d23b 100644
--- a/lib/chef/win32/registry.rb
+++ b/lib/chef/win32/registry.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
 #
-# Copyright:: 2012, Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,21 +16,33 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'chef/reserved_names'
+require "chef/reserved_names"
+require "chef/win32/api"
+require "chef/mixin/wide_string"
 
 if RUBY_PLATFORM =~ /mswin|mingw32|windows/
-  require 'win32/registry'
-  require 'win32/api'
+  require "chef/monkey_patches/win32/registry"
+  require "chef/win32/api/registry"
+  require "win32/registry"
+  require "win32/api"
 end
 
 class Chef
   class Win32
     class Registry
 
+      if RUBY_PLATFORM =~ /mswin|mingw32|windows/
+        include Chef::ReservedNames::Win32::API::Registry
+        extend Chef::ReservedNames::Win32::API::Registry
+      end
+
+      include Chef::Mixin::WideString
+      extend Chef::Mixin::WideString
+
       attr_accessor :run_context
       attr_accessor :architecture
 
-      def initialize(run_context=nil, user_architecture=:machine)
+      def initialize(run_context = nil, user_architecture = :machine)
         @run_context = run_context
         self.architecture = user_architecture
       end
@@ -44,7 +56,7 @@ class Chef
         hive, key = get_hive_and_key(key_path)
         key_exists!(key_path)
         values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
-          reg.map { |name, type, data| {:name=>name, :type=>get_name_from_type(type), :data=>data} }
+          reg.map { |name, type, data| { :name => name, :type => get_name_from_type(type), :data => data } }
         end
       end
 
@@ -115,38 +127,23 @@ class Chef
           Chef::Log.debug("Registry key #{key_path}, does not exist, not deleting")
           return true
         end
-        #key_path is in the form "HKLM\Software\Opscode" for example, extracting
-        #hive = HKLM,
-        #hive_namespace = ::Win32::Registry::HKEY_LOCAL_MACHINE
-        hive = key_path.split("\\").shift
-        hive_namespace, key_including_parent = get_hive_and_key(key_path)
-        if has_subkeys?(key_path)
-          if recursive == true
-            subkeys = get_subkeys(key_path)
-            subkeys.each do |key|
-              keypath_to_check = hive+"\\"+key_including_parent+"\\"+key
-              Chef::Log.debug("Deleting registry key #{key_path} recursively")
-              delete_key(keypath_to_check, true)
-            end
-            delete_key_ex(hive_namespace, key_including_parent)
-          else
-            raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has subkeys, and recursive not specified"
-          end
-        else
-          delete_key_ex(hive_namespace, key_including_parent)
-          return true
+        if has_subkeys?(key_path) && !recursive
+          raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has subkeys, and recursive not specified"
         end
+        hive, key_including_parent = get_hive_and_key(key_path)
+        # key_including_parent: Software\\Root\\Branch\\Fruit
+        # key => Fruit
+        # key_parent => Software\\Root\\Branch
+        key_parts = key_including_parent.split("\\")
+        key = key_parts.pop
+        key_parent = key_parts.join("\\")
+        hive.open(key_parent, ::Win32::Registry::KEY_WRITE | registry_system_architecture) do |reg|
+          reg.delete_key(key, recursive)
+        end
+        Chef::Log.debug("Registry key #{key_path} deleted")
         true
       end
 
-      #Using the 'RegDeleteKeyEx' Windows API that correctly supports WOW64 systems (Win2003)
-      #instead of the 'RegDeleteKey'
-      def delete_key_ex(hive, key)
-        regDeleteKeyEx = ::Win32::API.new('RegDeleteKeyEx', 'LPLL', 'L', 'advapi32')
-        hive_num = hive.hkey - (1 << 32)
-        regDeleteKeyEx.call(hive_num, key, ::Win32::Registry::KEY_WRITE | registry_system_architecture, 0)
-      end
-
       def key_exists?(key_path)
         hive, key = get_hive_and_key(key_path)
         begin
@@ -178,7 +175,7 @@ class Chef
         key_exists!(key_path)
         hive, key = get_hive_and_key(key_path)
         hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
-          reg.each_key{ |key| return true }
+          reg.each_key { |key| return true }
         end
         return false
       end
@@ -188,7 +185,7 @@ class Chef
         key_exists!(key_path)
         hive, key = get_hive_and_key(key_path)
         hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
-          reg.each_key{ |current_key| subkeys << current_key }
+          reg.each_key { |current_key| subkeys << current_key }
         end
         return subkeys
       end
@@ -203,7 +200,7 @@ class Chef
         key_exists!(key_path)
         hive, key = get_hive_and_key(key_path)
         hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
-          return true if reg.any? {|val| val == value[:name] }
+          return true if reg.any? { |val| safely_downcase(val) == safely_downcase(value[:name]) }
         end
         return false
       end
@@ -213,9 +210,9 @@ class Chef
         hive, key = get_hive_and_key(key_path)
         hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg|
           reg.each do |val_name, val_type, val_data|
-            if val_name == value[:name] &&
-              val_type == get_type_from_name(value[:type]) &&
-              val_data == value[:data]
+            if safely_downcase(val_name) == safely_downcase(value[:name]) &&
+               val_type == get_type_from_name(value[:type]) &&
+               val_data == value[:data]
               return true
             end
           end
@@ -259,19 +256,6 @@ class Chef
         end
       end
 
-      def get_type_from_name(val_type)
-        value = {
-          :binary => ::Win32::Registry::REG_BINARY,
-          :string => ::Win32::Registry::REG_SZ,
-          :multi_string => ::Win32::Registry::REG_MULTI_SZ,
-          :expand_string => ::Win32::Registry::REG_EXPAND_SZ,
-          :dword => ::Win32::Registry::REG_DWORD,
-          :dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
-          :qword => ::Win32::Registry::REG_QWORD
-        }[val_type]
-        return value
-      end
-
       def keys_missing?(key_path)
         missing_key_arr = key_path.split("\\")
         missing_key_arr.pop
@@ -289,6 +273,13 @@ class Chef
 
       private
 
+      def safely_downcase(val)
+        if val.is_a? String
+          return val.downcase
+        end
+        return val
+      end
+
       def node
         run_context && run_context.node
       end
@@ -334,7 +325,7 @@ class Chef
           :expand_string => ::Win32::Registry::REG_EXPAND_SZ,
           :dword => ::Win32::Registry::REG_DWORD,
           :dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
-          :qword => ::Win32::Registry::REG_QWORD
+          :qword => ::Win32::Registry::REG_QWORD,
         }
       end
 
@@ -350,7 +341,7 @@ class Chef
           2 => ::Win32::Registry::REG_EXPAND_SZ,
           4 => ::Win32::Registry::REG_DWORD,
           5 => ::Win32::Registry::REG_DWORD_BIG_ENDIAN,
-          11 => ::Win32::Registry::REG_QWORD
+          11 => ::Win32::Registry::REG_QWORD,
         }[val_type]
         return value
       end
diff --git a/lib/chef/win32/security.rb b/lib/chef/win32/security.rb
index 3902d8c..7fc3215 100644
--- a/lib/chef/win32/security.rb
+++ b/lib/chef/win32/security.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/security'
-require 'chef/win32/error'
-require 'chef/win32/memory'
-require 'chef/win32/process'
-require 'chef/win32/unicode'
-require 'chef/win32/security/token'
+require "chef/win32/api/security"
+require "chef/win32/error"
+require "chef/win32/memory"
+require "chef/win32/process"
+require "chef/win32/unicode"
+require "chef/win32/security/token"
+require "chef/mixin/wide_string"
 
 class Chef
   module ReservedNames::Win32
@@ -31,6 +32,8 @@ class Chef
       include Chef::ReservedNames::Win32::API::Security
       extend Chef::ReservedNames::Win32::API::Security
       extend Chef::ReservedNames::Win32::API::Macros
+      include Chef::Mixin::WideString
+      extend Chef::Mixin::WideString
 
       def self.access_check(security_descriptor, token, desired_access, generic_mapping)
         token_handle = token.handle.handle
@@ -101,6 +104,22 @@ class Chef
         end
       end
 
+      def self.add_account_right(name, privilege)
+        privilege_pointer = FFI::MemoryPointer.new LSA_UNICODE_STRING, 1
+        privilege_lsa_string = LSA_UNICODE_STRING.new(privilege_pointer)
+        privilege_lsa_string[:Buffer] = FFI::MemoryPointer.from_string(privilege.to_wstring)
+        privilege_lsa_string[:Length] = privilege.length * 2
+        privilege_lsa_string[:MaximumLength] = (privilege.length + 1) * 2
+
+        with_lsa_policy(name) do |policy_handle, sid|
+          result = LsaAddAccountRights(policy_handle.read_pointer, sid, privilege_pointer, 1)
+          win32_error = LsaNtStatusToWinError(result)
+          if win32_error != 0
+            Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+          end
+        end
+      end
+
       def self.adjust_token_privileges(token, privileges)
         token = token.handle if token.respond_to?(:handle)
         old_privileges_size = FFI::Buffer.new(:long).write_long(privileges.size_with_privileges)
@@ -162,6 +181,29 @@ class Chef
         end
       end
 
+      def self.get_account_right(name)
+        privileges = []
+        privilege_pointer = FFI::MemoryPointer.new(:pointer)
+        privilege_length = FFI::MemoryPointer.new(:ulong)
+
+        with_lsa_policy(name) do |policy_handle, sid|
+          result = LsaEnumerateAccountRights(policy_handle.read_pointer, sid, privilege_pointer, privilege_length)
+          win32_error = LsaNtStatusToWinError(result)
+          return [] if win32_error == 2 # FILE_NOT_FOUND - No rights assigned
+          if win32_error != 0
+            Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+          end
+
+          privilege_length.read_ulong.times do |i|
+            privilege = LSA_UNICODE_STRING.new(privilege_pointer.read_pointer + i * LSA_UNICODE_STRING.size)
+            privileges << privilege[:Buffer].read_wstring
+          end
+          LsaFreeMemory(privilege_pointer)
+        end
+
+        privileges
+      end
+
       def self.get_ace(acl, index)
         acl = acl.pointer if acl.respond_to?(:pointer)
         ace = FFI::Buffer.new :pointer
@@ -193,7 +235,6 @@ class Chef
         SecurityDescriptor.new(security_descriptor_ptr)
       end
 
-
       def self.get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION)
         security_descriptor = FFI::MemoryPointer.new :pointer
         hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor)
@@ -270,6 +311,36 @@ class Chef
         [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ]
       end
 
+      def self.get_token_information_owner(token)
+        owner_result_size = FFI::MemoryPointer.new(:ulong)
+        if GetTokenInformation(token.handle.handle, :TokenOwner, nil, 0, owner_result_size)
+          raise "Expected ERROR_INSUFFICIENT_BUFFER from GetTokenInformation, and got no error!"
+        elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        owner_result_storage = FFI::MemoryPointer.new owner_result_size.read_ulong
+        unless GetTokenInformation(token.handle.handle, :TokenOwner, owner_result_storage, owner_result_size.read_ulong, owner_result_size)
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        owner_result = TOKEN_OWNER.new owner_result_storage
+        SID.new(owner_result[:Owner], owner_result_storage)
+      end
+
+      def self.get_token_information_primary_group(token)
+        group_result_size = FFI::MemoryPointer.new(:ulong)
+        if GetTokenInformation(token.handle.handle, :TokenPrimaryGroup, nil, 0, group_result_size)
+          raise "Expected ERROR_INSUFFICIENT_BUFFER from GetTokenInformation, and got no error!"
+        elsif FFI::LastError.error != ERROR_INSUFFICIENT_BUFFER
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        group_result_storage = FFI::MemoryPointer.new group_result_size.read_ulong
+        unless GetTokenInformation(token.handle.handle, :TokenPrimaryGroup, group_result_storage, group_result_size.read_ulong, group_result_size)
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        group_result = TOKEN_PRIMARY_GROUP.new group_result_storage
+        SID.new(group_result[:PrimaryGroup], group_result_storage)
+      end
+
       def self.initialize_acl(acl_size)
         acl = FFI::MemoryPointer.new acl_size
         unless InitializeAcl(acl, acl_size, ACL_REVISION)
@@ -313,7 +384,7 @@ class Chef
         end
 
         sid = FFI::MemoryPointer.new :char, sid_size.read_long
-        referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2)
+        referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
         use = FFI::Buffer.new(:long).write_long(0)
         unless LookupAccountNameW(system_name, name.to_wstring, sid, sid_size, referenced_domain_name, referenced_domain_name_size, use)
           Chef::ReservedNames::Win32::Error.raise!
@@ -334,8 +405,8 @@ class Chef
           Chef::ReservedNames::Win32::Error.raise!
         end
 
-        name = FFI::MemoryPointer.new :char, (name_size.read_long*2)
-        referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2)
+        name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
+        referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long * 2)
         use = FFI::Buffer.new(:long).write_long(0)
         unless LookupAccountSidW(system_name, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use)
           Chef::ReservedNames::Win32::Error.raise!
@@ -353,7 +424,7 @@ class Chef
           Chef::ReservedNames::Win32::Error.raise!
         end
 
-        name = FFI::MemoryPointer.new :char, (name_size.read_long*2)
+        name = FFI::MemoryPointer.new :char, (name_size.read_long * 2)
         unless LookupPrivilegeNameW(system_name, luid, name, name_size)
           Chef::ReservedNames::Win32::Error.raise!
         end
@@ -371,7 +442,7 @@ class Chef
           Chef::ReservedNames::Win32::Error.raise!
         end
 
-        display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long*2)
+        display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long * 2)
         unless LookupPrivilegeDisplayNameW(system_name, name.to_wstring, display_name, display_name_size, language_id)
           Chef::ReservedNames::Win32::Error.raise!
         end
@@ -415,6 +486,10 @@ class Chef
         [ SecurityDescriptor.new(absolute_sd), SID.new(owner), SID.new(group), ACL.new(dacl), ACL.new(sacl) ]
       end
 
+      def self.open_current_process_token(desired_access = TOKEN_READ)
+        open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, desired_access)
+      end
+
       def self.open_process_token(process, desired_access)
         process = process.handle if process.respond_to?(:handle)
         process = process.handle if process.respond_to?(:handle)
@@ -511,9 +586,33 @@ class Chef
         end
       end
 
+      def self.with_lsa_policy(username)
+        sid = lookup_account_name(username)[1]
+
+        access = 0
+        access |= POLICY_CREATE_ACCOUNT
+        access |= POLICY_LOOKUP_NAMES
+
+        policy_handle = FFI::MemoryPointer.new(:pointer)
+        result = LsaOpenPolicy(nil, LSA_OBJECT_ATTRIBUTES.new, access, policy_handle)
+        win32_error = LsaNtStatusToWinError(result)
+        if win32_error != 0
+          Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+        end
+
+        begin
+          yield policy_handle, sid.pointer
+        ensure
+          win32_error = LsaNtStatusToWinError(LsaClose(policy_handle.read_pointer))
+          if win32_error != 0
+            Chef::ReservedNames::Win32::Error.raise!(nil, win32_error)
+          end
+        end
+      end
+
       def self.with_privileges(*privilege_names)
         # Set privileges
-        token = open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, TOKEN_READ | TOKEN_ADJUST_PRIVILEGES)
+        token = open_current_process_token(TOKEN_READ | TOKEN_ADJUST_PRIVILEGES)
         old_privileges = token.enable_privileges(*privilege_names)
 
         # Let the caller do their privileged stuff
@@ -533,7 +632,7 @@ class Chef
 
           true
         else
-          process_token = open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, TOKEN_READ)
+          process_token = open_current_process_token(TOKEN_READ)
           elevation_result = FFI::Buffer.new(:ulong)
           elevation_result_size = FFI::MemoryPointer.new(:uint32)
           success = GetTokenInformation(process_token.handle.handle, :TokenElevation, elevation_result, 4, elevation_result_size)
@@ -543,12 +642,24 @@ class Chef
           success && (elevation_result.read_ulong != 0)
         end
       end
+
+      def self.logon_user(username, domain, password, logon_type, logon_provider)
+        username = wstring(username)
+        domain = wstring(domain)
+        password = wstring(password)
+
+        token = FFI::Buffer.new(:pointer)
+        unless LogonUserW(username, domain, password, logon_type, logon_provider, token)
+          Chef::ReservedNames::Win32::Error.raise!
+        end
+        Token.new(Handle.new(token.read_pointer))
+      end
     end
   end
 end
 
-require 'chef/win32/security/ace'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/securable_object'
-require 'chef/win32/security/security_descriptor'
-require 'chef/win32/security/sid'
+require "chef/win32/security/ace"
+require "chef/win32/security/acl"
+require "chef/win32/security/securable_object"
+require "chef/win32/security/security_descriptor"
+require "chef/win32/security/sid"
diff --git a/lib/chef/win32/security/ace.rb b/lib/chef/win32/security/ace.rb
index 1f54b1c..d593513 100644
--- a/lib/chef/win32/security/ace.rb
+++ b/lib/chef/win32/security/ace.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/security/sid'
-require 'chef/win32/memory'
+require "chef/win32/security"
+require "chef/win32/security/sid"
+require "chef/win32/memory"
 
-require 'ffi'
+require "ffi"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/security/acl.rb b/lib/chef/win32/security/acl.rb
index e129d5c..8a04987 100644
--- a/lib/chef/win32/security/acl.rb
+++ b/lib/chef/win32/security/acl.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/security/ace'
-require 'ffi'
+require "chef/win32/security"
+require "chef/win32/security/ace"
+require "ffi"
 
 class Chef
   module ReservedNames::Win32
@@ -34,7 +34,7 @@ class Chef
         end
 
         def self.create(aces)
-          aces_size = aces.inject(0) { |sum,ace| sum + ace.size }
+          aces_size = aces.inject(0) { |sum, ace| sum + ace.size }
           acl_size = align_dword(Chef::ReservedNames::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94???
           acl = Chef::ReservedNames::Win32::Security.initialize_acl(acl_size)
           aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(acl, ace) }
@@ -45,7 +45,7 @@ class Chef
 
         def ==(other)
           return false if length != other.length
-          0.upto(length-1) do |i|
+          0.upto(length - 1) do |i|
             return false if self[i] != other[i]
           end
           return true
@@ -64,7 +64,7 @@ class Chef
         end
 
         def each
-          0.upto(length-1) { |i| yield self[i] }
+          0.upto(length - 1) { |i| yield self[i] }
         end
 
         def insert(index, *aces)
diff --git a/lib/chef/win32/security/securable_object.rb b/lib/chef/win32/security/securable_object.rb
index 00655c9..aef1a72 100644
--- a/lib/chef/win32/security/securable_object.rb
+++ b/lib/chef/win32/security/securable_object.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/sid'
+require "chef/win32/security"
+require "chef/win32/security/acl"
+require "chef/win32/security/sid"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/security/security_descriptor.rb b/lib/chef/win32/security/security_descriptor.rb
index 658e910..8bfd8b8 100644
--- a/lib/chef/win32/security/security_descriptor.rb
+++ b/lib/chef/win32/security/security_descriptor.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/security/acl'
-require 'chef/win32/security/sid'
+require "chef/win32/security"
+require "chef/win32/security/acl"
+require "chef/win32/security/sid"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb
index 8e9407d..4d2d252 100644
--- a/lib/chef/win32/security/sid.rb
+++ b/lib/chef/win32/security/sid.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/api/net'
-require 'chef/win32/api/error'
+require "chef/win32/security"
+require "chef/win32/api/net"
+require "chef/win32/api/error"
 
-require 'wmi-lite/wmi'
+require "wmi-lite/wmi"
 
 class Chef
   module ReservedNames::Win32
@@ -78,123 +78,161 @@ class Chef
 
         # Well-known SIDs
         def self.Null
-          SID.from_string_sid('S-1-0')
+          SID.from_string_sid("S-1-0")
         end
+
         def self.Nobody
-          SID.from_string_sid('S-1-0-0')
+          SID.from_string_sid("S-1-0-0")
         end
+
         def self.World
-          SID.from_string_sid('S-1-1')
+          SID.from_string_sid("S-1-1")
         end
+
         def self.Everyone
-          SID.from_string_sid('S-1-1-0')
+          SID.from_string_sid("S-1-1-0")
         end
+
         def self.Local
-          SID.from_string_sid('S-1-2')
+          SID.from_string_sid("S-1-2")
         end
+
         def self.Creator
-          SID.from_string_sid('S-1-3')
+          SID.from_string_sid("S-1-3")
         end
+
         def self.CreatorOwner
-          SID.from_string_sid('S-1-3-0')
+          SID.from_string_sid("S-1-3-0")
         end
+
         def self.CreatorGroup
-          SID.from_string_sid('S-1-3-1')
+          SID.from_string_sid("S-1-3-1")
         end
+
         def self.CreatorOwnerServer
-          SID.from_string_sid('S-1-3-2')
+          SID.from_string_sid("S-1-3-2")
         end
+
         def self.CreatorGroupServer
-          SID.from_string_sid('S-1-3-3')
+          SID.from_string_sid("S-1-3-3")
         end
+
         def self.NonUnique
-          SID.from_string_sid('S-1-4')
+          SID.from_string_sid("S-1-4")
         end
+
         def self.Nt
-          SID.from_string_sid('S-1-5')
+          SID.from_string_sid("S-1-5")
         end
+
         def self.Dialup
-          SID.from_string_sid('S-1-5-1')
+          SID.from_string_sid("S-1-5-1")
         end
+
         def self.Network
-          SID.from_string_sid('S-1-5-2')
+          SID.from_string_sid("S-1-5-2")
         end
+
         def self.Batch
-          SID.from_string_sid('S-1-5-3')
+          SID.from_string_sid("S-1-5-3")
         end
+
         def self.Interactive
-          SID.from_string_sid('S-1-5-4')
+          SID.from_string_sid("S-1-5-4")
         end
+
         def self.Service
-          SID.from_string_sid('S-1-5-6')
+          SID.from_string_sid("S-1-5-6")
         end
+
         def self.Anonymous
-          SID.from_string_sid('S-1-5-7')
+          SID.from_string_sid("S-1-5-7")
         end
+
         def self.Proxy
-          SID.from_string_sid('S-1-5-8')
+          SID.from_string_sid("S-1-5-8")
         end
+
         def self.EnterpriseDomainControllers
-          SID.from_string_sid('S-1-5-9')
+          SID.from_string_sid("S-1-5-9")
         end
+
         def self.PrincipalSelf
-          SID.from_string_sid('S-1-5-10')
+          SID.from_string_sid("S-1-5-10")
         end
+
         def self.AuthenticatedUsers
-          SID.from_string_sid('S-1-5-11')
+          SID.from_string_sid("S-1-5-11")
         end
+
         def self.RestrictedCode
-          SID.from_string_sid('S-1-5-12')
+          SID.from_string_sid("S-1-5-12")
         end
+
         def self.TerminalServerUsers
-          SID.from_string_sid('S-1-5-13')
+          SID.from_string_sid("S-1-5-13")
         end
+
         def self.LocalSystem
-          SID.from_string_sid('S-1-5-18')
+          SID.from_string_sid("S-1-5-18")
         end
+
         def self.NtLocal
-          SID.from_string_sid('S-1-5-19')
+          SID.from_string_sid("S-1-5-19")
         end
+
         def self.NtNetwork
-          SID.from_string_sid('S-1-5-20')
+          SID.from_string_sid("S-1-5-20")
         end
+
         def self.BuiltinAdministrators
-          SID.from_string_sid('S-1-5-32-544')
+          SID.from_string_sid("S-1-5-32-544")
         end
+
         def self.BuiltinUsers
-          SID.from_string_sid('S-1-5-32-545')
+          SID.from_string_sid("S-1-5-32-545")
         end
+
         def self.Guests
-          SID.from_string_sid('S-1-5-32-546')
+          SID.from_string_sid("S-1-5-32-546")
         end
+
         def self.PowerUsers
-          SID.from_string_sid('S-1-5-32-547')
+          SID.from_string_sid("S-1-5-32-547")
         end
+
         def self.AccountOperators
-          SID.from_string_sid('S-1-5-32-548')
+          SID.from_string_sid("S-1-5-32-548")
         end
+
         def self.ServerOperators
-          SID.from_string_sid('S-1-5-32-549')
+          SID.from_string_sid("S-1-5-32-549")
         end
+
         def self.PrintOperators
-          SID.from_string_sid('S-1-5-32-550')
+          SID.from_string_sid("S-1-5-32-550")
         end
+
         def self.BackupOperators
-          SID.from_string_sid('S-1-5-32-551')
+          SID.from_string_sid("S-1-5-32-551")
         end
+
         def self.Replicators
-          SID.from_string_sid('S-1-5-32-552')
+          SID.from_string_sid("S-1-5-32-552")
         end
+
         def self.Administrators
-          SID.from_string_sid('S-1-5-32-544')
+          SID.from_string_sid("S-1-5-32-544")
         end
 
         def self.None
           SID.from_account("#{::ENV['COMPUTERNAME']}\\None")
         end
+
         def self.Administrator
           SID.from_account("#{::ENV['COMPUTERNAME']}\\#{SID.admin_account_name}")
         end
+
         def self.Guest
           SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest")
         end
@@ -203,6 +241,23 @@ class Chef
           SID.from_account("#{::ENV['USERDOMAIN']}\\#{::ENV['USERNAME']}")
         end
 
+        # See https://technet.microsoft.com/en-us/library/cc961992.aspx
+        # In practice, this is SID.Administrators if the current_user is an admin (even if not
+        # running elevated), and is current_user otherwise. On win2k3, it technically can be
+        # current_user in all cases if a certain group policy is set.
+        def self.default_security_object_owner
+          token = Chef::ReservedNames::Win32::Security.open_current_process_token
+          Chef::ReservedNames::Win32::Security.get_token_information_owner(token)
+        end
+
+        # See https://technet.microsoft.com/en-us/library/cc961996.aspx
+        # In practice, this seems to be SID.current_user for Microsoft Accounts, the current
+        # user's Domain Users group for domain accounts, and SID.None otherwise.
+        def self.default_security_object_group
+          token = Chef::ReservedNames::Win32::Security.open_current_process_token
+          Chef::ReservedNames::Win32::Security.get_token_information_primary_group(token)
+        end
+
         def self.admin_account_name
           @admin_account_name ||= begin
             admin_account_name = nil
diff --git a/lib/chef/win32/security/token.rb b/lib/chef/win32/security/token.rb
index 9e494a7..f8b6790 100644
--- a/lib/chef/win32/security/token.rb
+++ b/lib/chef/win32/security/token.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'chef/win32/security'
-require 'chef/win32/api/security'
-
-require 'ffi'
+require "chef/win32/security"
+require "chef/win32/api/security"
+require "chef/win32/unicode"
+require "ffi"
 
 class Chef
   module ReservedNames::Win32
diff --git a/lib/chef/win32/system.rb b/lib/chef/win32/system.rb
new file mode 100755
index 0000000..ec2e5d3
--- /dev/null
+++ b/lib/chef/win32/system.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Salim Alam (<salam at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/win32/api/system"
+require "chef/win32/error"
+require "ffi"
+
+class Chef
+  module ReservedNames::Win32
+    class System
+      include Chef::ReservedNames::Win32::API::System
+      extend Chef::ReservedNames::Win32::API::System
+
+      def self.get_system_wow64_directory
+        ptr = FFI::MemoryPointer.new(:char, 255, true)
+        succeeded = GetSystemWow64DirectoryA(ptr, 255)
+
+        if succeeded == 0
+          raise Win32APIError, "Failed to get Wow64 system directory"
+        end
+
+        ptr.read_string.strip
+      end
+
+      def self.wow64_disable_wow64_fs_redirection
+        original_redirection_state = FFI::MemoryPointer.new(:pointer)
+
+        succeeded = Wow64DisableWow64FsRedirection(original_redirection_state)
+
+        if succeeded == 0
+          raise Win32APIError, "Failed to disable Wow64 file redirection"
+        end
+
+        original_redirection_state
+      end
+
+      def self.wow64_revert_wow64_fs_redirection(original_redirection_state)
+        succeeded = Wow64RevertWow64FsRedirection(original_redirection_state)
+
+        if succeeded == 0
+          raise Win32APIError, "Failed to revert Wow64 file redirection"
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/chef/win32/unicode.rb b/lib/chef/win32/unicode.rb
index e7399d5..b0fcf64 100644
--- a/lib/chef/win32/unicode.rb
+++ b/lib/chef/win32/unicode.rb
@@ -1,7 +1,7 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,8 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api/unicode'
+require "chef/mixin/wide_string"
+require "chef/win32/api/unicode"
 
 class Chef
   module ReservedNames::Win32
@@ -30,6 +31,8 @@ end
 
 module FFI
   class Pointer
+    include Chef::Mixin::WideString
+
     def read_wstring(num_wchars = nil)
       if num_wchars.nil?
         # Find the length of the string
@@ -37,19 +40,21 @@ module FFI
         last_char = nil
         while last_char != "\000\000" do
           length += 1
-          last_char = self.get_bytes(0,length * 2)[-2..-1]
+          last_char = self.get_bytes(0, length * 2)[-2..-1]
         end
 
         num_wchars = length
       end
 
-      Chef::ReservedNames::Win32::Unicode.wide_to_utf8(self.get_bytes(0, num_wchars*2))
+      wide_to_utf8(self.get_bytes(0, num_wchars * 2))
     end
   end
 end
 
 class String
+  include Chef::Mixin::WideString
+
   def to_wstring
-    Chef::ReservedNames::Win32::Unicode.utf8_to_wide(self)
+    utf8_to_wide(self)
   end
 end
diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb
index 17c27e4..a18211b 100644
--- a/lib/chef/win32/version.rb
+++ b/lib/chef/win32/version.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'chef/win32/api'
-require 'chef/win32/api/system'
-require 'wmi-lite/wmi'
+require "chef/win32/api"
+require "chef/win32/api/system"
+require "wmi-lite/wmi"
 
 class Chef
   module ReservedNames::Win32
@@ -48,21 +48,21 @@ class Chef
       private_class_method :method_name_from_marketing_name
 
       WIN_VERSIONS = {
-        "Windows 10" => {:major => 6, :minor => 4, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
-        "Windows Server 10" => {:major => 6, :minor => 4, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
-        "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
-        "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
-        "Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
-        "Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
-        "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
-        "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
-        "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
-        "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
-        "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 }},
-        "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }},
-        "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 }},
-        "Windows XP" => {:major => 5, :minor => 1},
-        "Windows 2000" => {:major => 5, :minor => 0}
+        "Windows 10" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+        "Windows Server 2016" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+        "Windows 8.1" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+        "Windows Server 2012 R2" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+        "Windows 8" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+        "Windows Server 2012" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+        "Windows 7" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+        "Windows Server 2008 R2" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+        "Windows Server 2008" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
+        "Windows Vista" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
+        "Windows Server 2003 R2" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 } },
+        "Windows Home Server" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER } },
+        "Windows Server 2003" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 } },
+        "Windows XP" => { :major => 5, :minor => 1 },
+        "Windows 2000" => { :major => 5, :minor => 0 },
       }
 
       def initialize
@@ -88,12 +88,12 @@ class Chef
       marketing_names = Array.new
 
       # General Windows checks
-      WIN_VERSIONS.each do |k,v|
+      WIN_VERSIONS.each do |k, v|
         method_name = method_name_from_marketing_name(k)
         define_method(method_name) do
           (@major_version == v[:major]) &&
-          (@minor_version == v[:minor]) &&
-          (v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
+            (@minor_version == v[:minor]) &&
+            (v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
         end
         marketing_names << [k, method_name]
       end
@@ -122,18 +122,14 @@ class Chef
         # WMI always returns the truth. See article at
         # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
 
-        # CHEF-4888: Work around ruby #2618, expected to be fixed in Ruby 2.1.0
-        # https://github.com/ruby/ruby/commit/588504b20f5cc880ad51827b93e571e32446e5db
-        # https://github.com/ruby/ruby/commit/27ed294c7134c0de582007af3c915a635a6506cd
-
         wmi = WmiLite::Wmi.new
-        os_info = wmi.first_of('Win32_OperatingSystem')
-        os_version = os_info['version']
+        os_info = wmi.first_of("Win32_OperatingSystem")
+        os_version = os_info["version"]
 
         # The operating system version is a string in the following form
         # that can be split into components based on the '.' delimiter:
         # MajorVersionNumber.MinorVersionNumber.BuildNumber
-        os_version.split('.').collect { | version_string | version_string.to_i }
+        os_version.split(".").collect { |version_string| version_string.to_i }
       end
 
       def get_version_ex
diff --git a/lib/chef/workstation_config_loader.rb b/lib/chef/workstation_config_loader.rb
index 2454c9c..97f4124 100644
--- a/lib/chef/workstation_config_loader.rb
+++ b/lib/chef/workstation_config_loader.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Claire McQuin (<claire at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,163 +16,8 @@
 # limitations under the License.
 #
 
-require 'chef/config_fetcher'
-require 'chef/config'
-require 'chef/null_logger'
-require 'chef/util/path_helper'
+require "chef-config/workstation_config_loader"
 
 class Chef
-
-  class WorkstationConfigLoader
-
-    # Path to a config file requested by user, (e.g., via command line option). Can be nil
-    attr_accessor :explicit_config_file
-
-    # TODO: initialize this with a logger for Chef and Knife
-    def initialize(explicit_config_file, logger=nil)
-      @explicit_config_file = explicit_config_file
-      @config_location = nil
-      @logger = logger || NullLogger.new
-    end
-
-    def no_config_found?
-      config_location.nil?
-    end
-
-    def config_location
-      @config_location ||= (explicit_config_file || locate_local_config)
-    end
-
-    def chef_config_dir
-      if @chef_config_dir.nil?
-        @chef_config_dir = false
-        full_path = working_directory.split(File::SEPARATOR)
-        (full_path.length - 1).downto(0) do |i|
-          candidate_directory = File.join(full_path[0..i] + [".chef" ])
-          if File.exist?(candidate_directory) && File.directory?(candidate_directory)
-            @chef_config_dir = candidate_directory
-            break
-          end
-        end
-      end
-      @chef_config_dir
-    end
-
-    def load
-      # Ignore it if there's no explicit_config_file and can't find one at a
-      # default path.
-      return false if config_location.nil?
-
-      if explicit_config_file && !path_exists?(config_location)
-        raise Exceptions::ConfigurationError, "Specified config file #{config_location} does not exist"
-      end
-
-      # Have to set Chef::Config.config_file b/c other config is derived from it.
-      Chef::Config.config_file = config_location
-      read_config(IO.read(config_location), config_location)
-    end
-
-    # (Private API, public for test purposes)
-    def env
-      ENV
-    end
-
-    # (Private API, public for test purposes)
-    def path_exists?(path)
-      Pathname.new(path).expand_path.exist?
-    end
-
-    private
-
-    def have_config?(path)
-      if path_exists?(path)
-        logger.info("Using config at #{path}")
-        true
-      else
-        logger.debug("Config not found at #{path}, trying next option")
-        false
-      end
-    end
-
-    def locate_local_config
-      candidate_configs = []
-
-      # Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine)
-      if env['KNIFE_HOME']
-        candidate_configs << File.join(env['KNIFE_HOME'], 'config.rb')
-        candidate_configs << File.join(env['KNIFE_HOME'], 'knife.rb')
-      end
-      # Look for $PWD/knife.rb
-      if Dir.pwd
-        candidate_configs << File.join(Dir.pwd, 'config.rb')
-        candidate_configs << File.join(Dir.pwd, 'knife.rb')
-      end
-      # Look for $UPWARD/.chef/knife.rb
-      if chef_config_dir
-        candidate_configs << File.join(chef_config_dir, 'config.rb')
-        candidate_configs << File.join(chef_config_dir, 'knife.rb')
-      end
-      # Look for $HOME/.chef/knife.rb
-      Chef::Util::PathHelper.home('.chef') do |dot_chef_dir|
-        candidate_configs << File.join(dot_chef_dir, 'config.rb')
-        candidate_configs << File.join(dot_chef_dir, 'knife.rb')
-      end
-
-      candidate_configs.find do | candidate_config |
-        have_config?(candidate_config)
-      end
-    end
-
-    def working_directory
-      a = if Chef::Platform.windows?
-            env['CD']
-          else
-            env['PWD']
-          end || Dir.pwd
-
-      a
-    end
-
-    def read_config(config_content, config_file_path)
-      Chef::Config.from_string(config_content, config_file_path)
-    rescue SignalException
-      raise
-    rescue SyntaxError => e
-      message = ""
-      message << "You have invalid ruby syntax in your config file #{config_file_path}\n\n"
-      message << "#{e.class.name}: #{e.message}\n"
-      if file_line = e.message[/#{Regexp.escape(config_file_path)}:[\d]+/]
-        line = file_line[/:([\d]+)$/, 1].to_i
-        message << highlight_config_error(config_file_path, line)
-      end
-      raise Exceptions::ConfigurationError, message
-    rescue Exception => e
-      message = "You have an error in your config file #{config_file_path}\n\n"
-      message << "#{e.class.name}: #{e.message}\n"
-      filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
-      filtered_trace.each {|bt_line| message << "  " << bt_line << "\n" }
-      if !filtered_trace.empty?
-        line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1]
-        message << highlight_config_error(config_file_path, line_nr.to_i)
-      end
-      raise Exceptions::ConfigurationError, message
-    end
-
-
-    def highlight_config_error(file, line)
-      config_file_lines = []
-      IO.readlines(file).each_with_index {|l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}"}
-      if line == 1
-        lines = config_file_lines[0..3]
-      else
-        lines = config_file_lines[Range.new(line - 2, line)]
-      end
-      "Relevant file content:\n" + lines.join("\n") + "\n"
-    end
-
-    def logger
-      @logger
-    end
-
-  end
+  WorkstationConfigLoader = ChefConfig::WorkstationConfigLoader
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index 4bb3d01..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,2053 +0,0 @@
---- !ruby/object:Gem::Specification
-name: chef
-version: !ruby/object:Gem::Version
-  version: 12.3.0
-platform: ruby
-authors:
-- Adam Jacob
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2015-04-28 00:00:00.000000000 Z
-dependencies:
-- !ruby/object:Gem::Dependency
-  name: mixlib-config
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.0'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.0'
-- !ruby/object:Gem::Dependency
-  name: mixlib-cli
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.4'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.4'
-- !ruby/object:Gem::Dependency
-  name: mixlib-log
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.3'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.3'
-- !ruby/object:Gem::Dependency
-  name: mixlib-authentication
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.3'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.3'
-- !ruby/object:Gem::Dependency
-  name: mixlib-shellout
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 2.0.0.rc.0
-    - - "<"
-      - !ruby/object:Gem::Version
-        version: '3.0'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 2.0.0.rc.0
-    - - "<"
-      - !ruby/object:Gem::Version
-        version: '3.0'
-- !ruby/object:Gem::Dependency
-  name: ohai
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '8.0'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '8.0'
-- !ruby/object:Gem::Dependency
-  name: ffi-yajl
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '1.2'
-    - - "<"
-      - !ruby/object:Gem::Version
-        version: '3.0'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '1.2'
-    - - "<"
-      - !ruby/object:Gem::Version
-        version: '3.0'
-- !ruby/object:Gem::Dependency
-  name: net-ssh
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.6'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.6'
-- !ruby/object:Gem::Dependency
-  name: net-ssh-multi
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.1'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.1'
-- !ruby/object:Gem::Dependency
-  name: highline
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.6'
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 1.6.9
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.6'
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 1.6.9
-- !ruby/object:Gem::Dependency
-  name: erubis
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.7'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.7'
-- !ruby/object:Gem::Dependency
-  name: diff-lcs
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.2'
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 1.2.4
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.2'
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: 1.2.4
-- !ruby/object:Gem::Dependency
-  name: chef-zero
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '4.1'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '4.1'
-- !ruby/object:Gem::Dependency
-  name: pry
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.9'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.9'
-- !ruby/object:Gem::Dependency
-  name: plist
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 3.1.0
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 3.1.0
-- !ruby/object:Gem::Dependency
-  name: rspec-core
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-- !ruby/object:Gem::Dependency
-  name: rspec-expectations
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-- !ruby/object:Gem::Dependency
-  name: rspec-mocks
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '3.2'
-- !ruby/object:Gem::Dependency
-  name: rspec_junit_formatter
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 0.2.0
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 0.2.0
-- !ruby/object:Gem::Dependency
-  name: serverspec
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.7'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.7'
-- !ruby/object:Gem::Dependency
-  name: specinfra
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.10'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.10'
-- !ruby/object:Gem::Dependency
-  name: rack
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: rake
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 10.1.0
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: 10.1.0
-description: A systems integration framework, built to bring the benefits of configuration
-  management to your entire infrastructure.
-email: adam at getchef.com
-executables:
-- chef-client
-- chef-solo
-- knife
-- chef-shell
-- chef-apply
-extensions: []
-extra_rdoc_files:
-- README.md
-- CONTRIBUTING.md
-- LICENSE
-files:
-- CONTRIBUTING.md
-- LICENSE
-- README.md
-- Rakefile
-- bin/chef-apply
-- bin/chef-client
-- bin/chef-shell
-- bin/chef-solo
-- bin/knife
-- distro/common/html/_sources/ctl_chef_client.txt
-- distro/common/html/_sources/ctl_chef_server.txt
-- distro/common/html/_sources/ctl_chef_shell.txt
-- distro/common/html/_sources/ctl_chef_solo.txt
-- distro/common/html/_sources/index.txt
-- distro/common/html/_sources/knife.txt
-- distro/common/html/_sources/knife_bootstrap.txt
-- distro/common/html/_sources/knife_client.txt
-- distro/common/html/_sources/knife_common_options.txt
-- distro/common/html/_sources/knife_configure.txt
-- distro/common/html/_sources/knife_cookbook.txt
-- distro/common/html/_sources/knife_cookbook_site.txt
-- distro/common/html/_sources/knife_data_bag.txt
-- distro/common/html/_sources/knife_delete.txt
-- distro/common/html/_sources/knife_deps.txt
-- distro/common/html/_sources/knife_diff.txt
-- distro/common/html/_sources/knife_download.txt
-- distro/common/html/_sources/knife_edit.txt
-- distro/common/html/_sources/knife_environment.txt
-- distro/common/html/_sources/knife_exec.txt
-- distro/common/html/_sources/knife_index_rebuild.txt
-- distro/common/html/_sources/knife_list.txt
-- distro/common/html/_sources/knife_node.txt
-- distro/common/html/_sources/knife_raw.txt
-- distro/common/html/_sources/knife_recipe_list.txt
-- distro/common/html/_sources/knife_role.txt
-- distro/common/html/_sources/knife_search.txt
-- distro/common/html/_sources/knife_serve.txt
-- distro/common/html/_sources/knife_show.txt
-- distro/common/html/_sources/knife_ssh.txt
-- distro/common/html/_sources/knife_ssl_check.txt
-- distro/common/html/_sources/knife_ssl_fetch.txt
-- distro/common/html/_sources/knife_status.txt
-- distro/common/html/_sources/knife_tag.txt
-- distro/common/html/_sources/knife_upload.txt
-- distro/common/html/_sources/knife_user.txt
-- distro/common/html/_sources/knife_using.txt
-- distro/common/html/_sources/knife_xargs.txt
-- distro/common/html/_static/ajax-loader.gif
-- distro/common/html/_static/basic.css
-- distro/common/html/_static/chef.ico
-- distro/common/html/_static/chef_html_logo.png
-- distro/common/html/_static/comment-bright.png
-- distro/common/html/_static/comment-close.png
-- distro/common/html/_static/comment.png
-- distro/common/html/_static/contents.png
-- distro/common/html/_static/doctools.js
-- distro/common/html/_static/down-pressed.png
-- distro/common/html/_static/down.png
-- distro/common/html/_static/file.png
-- distro/common/html/_static/guide.css
-- distro/common/html/_static/jquery.js
-- distro/common/html/_static/minus.png
-- distro/common/html/_static/navigation.png
-- distro/common/html/_static/plus.png
-- distro/common/html/_static/pygments.css
-- distro/common/html/_static/searchtools.js
-- distro/common/html/_static/underscore.js
-- distro/common/html/_static/up-pressed.png
-- distro/common/html/_static/up.png
-- distro/common/html/_static/websupport.js
-- distro/common/html/ctl_chef_client.html
-- distro/common/html/ctl_chef_server.html
-- distro/common/html/ctl_chef_shell.html
-- distro/common/html/ctl_chef_solo.html
-- distro/common/html/index.html
-- distro/common/html/knife.html
-- distro/common/html/knife_bootstrap.html
-- distro/common/html/knife_client.html
-- distro/common/html/knife_common_options.html
-- distro/common/html/knife_configure.html
-- distro/common/html/knife_cookbook.html
-- distro/common/html/knife_cookbook_site.html
-- distro/common/html/knife_data_bag.html
-- distro/common/html/knife_delete.html
-- distro/common/html/knife_deps.html
-- distro/common/html/knife_diff.html
-- distro/common/html/knife_download.html
-- distro/common/html/knife_edit.html
-- distro/common/html/knife_environment.html
-- distro/common/html/knife_exec.html
-- distro/common/html/knife_index_rebuild.html
-- distro/common/html/knife_list.html
-- distro/common/html/knife_node.html
-- distro/common/html/knife_raw.html
-- distro/common/html/knife_recipe_list.html
-- distro/common/html/knife_role.html
-- distro/common/html/knife_search.html
-- distro/common/html/knife_serve.html
-- distro/common/html/knife_show.html
-- distro/common/html/knife_ssh.html
-- distro/common/html/knife_ssl_check.html
-- distro/common/html/knife_ssl_fetch.html
-- distro/common/html/knife_status.html
-- distro/common/html/knife_tag.html
-- distro/common/html/knife_upload.html
-- distro/common/html/knife_user.html
-- distro/common/html/knife_using.html
-- distro/common/html/knife_xargs.html
-- distro/common/html/objects.inv
-- distro/common/html/search.html
-- distro/common/html/searchindex.js
-- distro/common/man/man1/README.md
-- distro/common/man/man1/chef-shell.1
-- distro/common/man/man1/knife-bootstrap.1
-- distro/common/man/man1/knife-client.1
-- distro/common/man/man1/knife-configure.1
-- distro/common/man/man1/knife-cookbook-site.1
-- distro/common/man/man1/knife-cookbook.1
-- distro/common/man/man1/knife-data-bag.1
-- distro/common/man/man1/knife-delete.1
-- distro/common/man/man1/knife-deps.1
-- distro/common/man/man1/knife-diff.1
-- distro/common/man/man1/knife-download.1
-- distro/common/man/man1/knife-edit.1
-- distro/common/man/man1/knife-environment.1
-- distro/common/man/man1/knife-exec.1
-- distro/common/man/man1/knife-index-rebuild.1
-- distro/common/man/man1/knife-list.1
-- distro/common/man/man1/knife-node.1
-- distro/common/man/man1/knife-raw.1
-- distro/common/man/man1/knife-recipe-list.1
-- distro/common/man/man1/knife-role.1
-- distro/common/man/man1/knife-search.1
-- distro/common/man/man1/knife-serve.1
-- distro/common/man/man1/knife-show.1
-- distro/common/man/man1/knife-ssh.1
-- distro/common/man/man1/knife-ssl-check.1
-- distro/common/man/man1/knife-ssl-fetch.1
-- distro/common/man/man1/knife-status.1
-- distro/common/man/man1/knife-tag.1
-- distro/common/man/man1/knife-upload.1
-- distro/common/man/man1/knife-user.1
-- distro/common/man/man1/knife-xargs.1
-- distro/common/man/man1/knife.1
-- distro/common/man/man8/chef-apply.8
-- distro/common/man/man8/chef-client.8
-- distro/common/man/man8/chef-solo.8
-- distro/common/markdown/README
-- distro/common/markdown/man1/chef-shell.mkd
-- distro/common/markdown/man1/knife-bootstrap.mkd
-- distro/common/markdown/man1/knife-client.mkd
-- distro/common/markdown/man1/knife-configure.mkd
-- distro/common/markdown/man1/knife-cookbook-site.mkd
-- distro/common/markdown/man1/knife-cookbook.mkd
-- distro/common/markdown/man1/knife-data-bag.mkd
-- distro/common/markdown/man1/knife-environment.mkd
-- distro/common/markdown/man1/knife-exec.mkd
-- distro/common/markdown/man1/knife-index.mkd
-- distro/common/markdown/man1/knife-node.mkd
-- distro/common/markdown/man1/knife-role.mkd
-- distro/common/markdown/man1/knife-search.mkd
-- distro/common/markdown/man1/knife-ssh.mkd
-- distro/common/markdown/man1/knife-status.mkd
-- distro/common/markdown/man1/knife-tag.mkd
-- distro/common/markdown/man1/knife.mkd
-- distro/common/markdown/man8/chef-client.mkd
-- distro/common/markdown/man8/chef-expander.mkd
-- distro/common/markdown/man8/chef-expanderctl.mkd
-- distro/common/markdown/man8/chef-server-webui.mkd
-- distro/common/markdown/man8/chef-server.mkd
-- distro/common/markdown/man8/chef-solo.mkd
-- distro/common/markdown/man8/chef-solr.mkd
-- lib/chef.rb
-- lib/chef/api_client.rb
-- lib/chef/api_client/registration.rb
-- lib/chef/application.rb
-- lib/chef/application/apply.rb
-- lib/chef/application/client.rb
-- lib/chef/application/knife.rb
-- lib/chef/application/solo.rb
-- lib/chef/application/windows_service.rb
-- lib/chef/application/windows_service_manager.rb
-- lib/chef/applications.rb
-- lib/chef/audit/audit_event_proxy.rb
-- lib/chef/audit/audit_reporter.rb
-- lib/chef/audit/control_group_data.rb
-- lib/chef/audit/rspec_formatter.rb
-- lib/chef/audit/runner.rb
-- lib/chef/chef_class.rb
-- lib/chef/chef_fs.rb
-- lib/chef/chef_fs/chef_fs_data_store.rb
-- lib/chef/chef_fs/command_line.rb
-- lib/chef/chef_fs/config.rb
-- lib/chef/chef_fs/data_handler/acl_data_handler.rb
-- lib/chef/chef_fs/data_handler/client_data_handler.rb
-- lib/chef/chef_fs/data_handler/container_data_handler.rb
-- lib/chef/chef_fs/data_handler/cookbook_data_handler.rb
-- lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb
-- lib/chef/chef_fs/data_handler/data_handler_base.rb
-- lib/chef/chef_fs/data_handler/environment_data_handler.rb
-- lib/chef/chef_fs/data_handler/group_data_handler.rb
-- lib/chef/chef_fs/data_handler/node_data_handler.rb
-- lib/chef/chef_fs/data_handler/organization_data_handler.rb
-- lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
-- lib/chef/chef_fs/data_handler/organization_members_data_handler.rb
-- lib/chef/chef_fs/data_handler/policy_data_handler.rb
-- lib/chef/chef_fs/data_handler/role_data_handler.rb
-- lib/chef/chef_fs/data_handler/user_data_handler.rb
-- lib/chef/chef_fs/file_pattern.rb
-- lib/chef/chef_fs/file_system.rb
-- lib/chef/chef_fs/file_system/acl_dir.rb
-- lib/chef/chef_fs/file_system/acl_entry.rb
-- lib/chef/chef_fs/file_system/acls_dir.rb
-- lib/chef/chef_fs/file_system/already_exists_error.rb
-- lib/chef/chef_fs/file_system/base_fs_dir.rb
-- lib/chef/chef_fs/file_system/base_fs_object.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_policies_dir.rb
-- lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
-- lib/chef/chef_fs/file_system/chef_server_root_dir.rb
-- lib/chef/chef_fs/file_system/cookbook_dir.rb
-- lib/chef/chef_fs/file_system/cookbook_file.rb
-- lib/chef/chef_fs/file_system/cookbook_frozen_error.rb
-- lib/chef/chef_fs/file_system/cookbook_subdir.rb
-- lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb
-- lib/chef/chef_fs/file_system/cookbooks_dir.rb
-- lib/chef/chef_fs/file_system/data_bag_dir.rb
-- lib/chef/chef_fs/file_system/data_bags_dir.rb
-- lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb
-- lib/chef/chef_fs/file_system/environments_dir.rb
-- lib/chef/chef_fs/file_system/file_system_entry.rb
-- lib/chef/chef_fs/file_system/file_system_error.rb
-- lib/chef/chef_fs/file_system/file_system_root_dir.rb
-- lib/chef/chef_fs/file_system/memory_dir.rb
-- lib/chef/chef_fs/file_system/memory_file.rb
-- lib/chef/chef_fs/file_system/memory_root.rb
-- lib/chef/chef_fs/file_system/multiplexed_dir.rb
-- lib/chef/chef_fs/file_system/must_delete_recursively_error.rb
-- lib/chef/chef_fs/file_system/nodes_dir.rb
-- lib/chef/chef_fs/file_system/nonexistent_fs_object.rb
-- lib/chef/chef_fs/file_system/not_found_error.rb
-- lib/chef/chef_fs/file_system/operation_failed_error.rb
-- lib/chef/chef_fs/file_system/operation_not_allowed_error.rb
-- lib/chef/chef_fs/file_system/org_entry.rb
-- lib/chef/chef_fs/file_system/organization_invites_entry.rb
-- lib/chef/chef_fs/file_system/organization_members_entry.rb
-- lib/chef/chef_fs/file_system/rest_list_dir.rb
-- lib/chef/chef_fs/file_system/rest_list_entry.rb
-- lib/chef/chef_fs/knife.rb
-- lib/chef/chef_fs/parallelizer.rb
-- lib/chef/chef_fs/parallelizer/flatten_enumerable.rb
-- lib/chef/chef_fs/parallelizer/parallel_enumerable.rb
-- lib/chef/chef_fs/path_utils.rb
-- lib/chef/client.rb
-- lib/chef/config.rb
-- lib/chef/config_fetcher.rb
-- lib/chef/cookbook/chefignore.rb
-- lib/chef/cookbook/cookbook_collection.rb
-- lib/chef/cookbook/cookbook_version_loader.rb
-- lib/chef/cookbook/file_system_file_vendor.rb
-- lib/chef/cookbook/file_vendor.rb
-- lib/chef/cookbook/metadata.rb
-- lib/chef/cookbook/remote_file_vendor.rb
-- lib/chef/cookbook/synchronizer.rb
-- lib/chef/cookbook/syntax_check.rb
-- lib/chef/cookbook_loader.rb
-- lib/chef/cookbook_manifest.rb
-- lib/chef/cookbook_site_streaming_uploader.rb
-- lib/chef/cookbook_uploader.rb
-- lib/chef/cookbook_version.rb
-- lib/chef/daemon.rb
-- lib/chef/data_bag.rb
-- lib/chef/data_bag_item.rb
-- lib/chef/deprecation/mixin/template.rb
-- lib/chef/deprecation/provider/cookbook_file.rb
-- lib/chef/deprecation/provider/file.rb
-- lib/chef/deprecation/provider/remote_file.rb
-- lib/chef/deprecation/provider/template.rb
-- lib/chef/deprecation/warnings.rb
-- lib/chef/digester.rb
-- lib/chef/dsl.rb
-- lib/chef/dsl/audit.rb
-- lib/chef/dsl/data_query.rb
-- lib/chef/dsl/include_attribute.rb
-- lib/chef/dsl/include_recipe.rb
-- lib/chef/dsl/platform_introspection.rb
-- lib/chef/dsl/powershell.rb
-- lib/chef/dsl/reboot_pending.rb
-- lib/chef/dsl/recipe.rb
-- lib/chef/dsl/registry_helper.rb
-- lib/chef/encrypted_data_bag_item.rb
-- lib/chef/encrypted_data_bag_item/assertions.rb
-- lib/chef/encrypted_data_bag_item/check_encrypted.rb
-- lib/chef/encrypted_data_bag_item/decryption_failure.rb
-- lib/chef/encrypted_data_bag_item/decryptor.rb
-- lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb
-- lib/chef/encrypted_data_bag_item/encryption_failure.rb
-- lib/chef/encrypted_data_bag_item/encryptor.rb
-- lib/chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format.rb
-- lib/chef/encrypted_data_bag_item/unsupported_cipher.rb
-- lib/chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format.rb
-- lib/chef/environment.rb
-- lib/chef/event_dispatch/base.rb
-- lib/chef/event_dispatch/dispatcher.rb
-- lib/chef/event_dispatch/events_output_stream.rb
-- lib/chef/event_loggers/base.rb
-- lib/chef/event_loggers/windows_eventlog.rb
-- lib/chef/exceptions.rb
-- lib/chef/file_access_control.rb
-- lib/chef/file_access_control/unix.rb
-- lib/chef/file_access_control/windows.rb
-- lib/chef/file_cache.rb
-- lib/chef/file_content_management/content_base.rb
-- lib/chef/file_content_management/deploy.rb
-- lib/chef/file_content_management/deploy/cp.rb
-- lib/chef/file_content_management/deploy/mv_unix.rb
-- lib/chef/file_content_management/deploy/mv_windows.rb
-- lib/chef/file_content_management/tempfile.rb
-- lib/chef/formatters/base.rb
-- lib/chef/formatters/doc.rb
-- lib/chef/formatters/error_descriptor.rb
-- lib/chef/formatters/error_inspectors.rb
-- lib/chef/formatters/error_inspectors/api_error_formatting.rb
-- lib/chef/formatters/error_inspectors/compile_error_inspector.rb
-- lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb
-- lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
-- lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
-- lib/chef/formatters/error_inspectors/registration_error_inspector.rb
-- lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
-- lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb
-- lib/chef/formatters/error_mapper.rb
-- lib/chef/formatters/indentable_output_stream.rb
-- lib/chef/formatters/minimal.rb
-- lib/chef/guard_interpreter.rb
-- lib/chef/guard_interpreter/default_guard_interpreter.rb
-- lib/chef/guard_interpreter/resource_guard_interpreter.rb
-- lib/chef/handler.rb
-- lib/chef/handler/error_report.rb
-- lib/chef/handler/json_file.rb
-- lib/chef/http.rb
-- lib/chef/http/auth_credentials.rb
-- lib/chef/http/authenticator.rb
-- lib/chef/http/basic_client.rb
-- lib/chef/http/cookie_jar.rb
-- lib/chef/http/cookie_manager.rb
-- lib/chef/http/decompressor.rb
-- lib/chef/http/http_request.rb
-- lib/chef/http/json_input.rb
-- lib/chef/http/json_output.rb
-- lib/chef/http/json_to_model_output.rb
-- lib/chef/http/remote_request_id.rb
-- lib/chef/http/simple.rb
-- lib/chef/http/socketless_chef_zero_client.rb
-- lib/chef/http/ssl_policies.rb
-- lib/chef/http/validate_content_length.rb
-- lib/chef/json_compat.rb
-- lib/chef/knife.rb
-- lib/chef/knife/bootstrap.rb
-- lib/chef/knife/bootstrap/chef_vault_handler.rb
-- lib/chef/knife/bootstrap/client_builder.rb
-- lib/chef/knife/bootstrap/templates/README.md
-- lib/chef/knife/bootstrap/templates/archlinux-gems.erb
-- lib/chef/knife/bootstrap/templates/chef-aix.erb
-- lib/chef/knife/bootstrap/templates/chef-full.erb
-- lib/chef/knife/client_bulk_delete.rb
-- lib/chef/knife/client_create.rb
-- lib/chef/knife/client_delete.rb
-- lib/chef/knife/client_edit.rb
-- lib/chef/knife/client_list.rb
-- lib/chef/knife/client_reregister.rb
-- lib/chef/knife/client_show.rb
-- lib/chef/knife/configure.rb
-- lib/chef/knife/configure_client.rb
-- lib/chef/knife/cookbook_bulk_delete.rb
-- lib/chef/knife/cookbook_create.rb
-- lib/chef/knife/cookbook_delete.rb
-- lib/chef/knife/cookbook_download.rb
-- lib/chef/knife/cookbook_list.rb
-- lib/chef/knife/cookbook_metadata.rb
-- lib/chef/knife/cookbook_metadata_from_file.rb
-- lib/chef/knife/cookbook_show.rb
-- lib/chef/knife/cookbook_site_download.rb
-- lib/chef/knife/cookbook_site_install.rb
-- lib/chef/knife/cookbook_site_list.rb
-- lib/chef/knife/cookbook_site_search.rb
-- lib/chef/knife/cookbook_site_share.rb
-- lib/chef/knife/cookbook_site_show.rb
-- lib/chef/knife/cookbook_site_unshare.rb
-- lib/chef/knife/cookbook_site_vendor.rb
-- lib/chef/knife/cookbook_test.rb
-- lib/chef/knife/cookbook_upload.rb
-- lib/chef/knife/core/bootstrap_context.rb
-- lib/chef/knife/core/cookbook_scm_repo.rb
-- lib/chef/knife/core/generic_presenter.rb
-- lib/chef/knife/core/node_editor.rb
-- lib/chef/knife/core/node_presenter.rb
-- lib/chef/knife/core/object_loader.rb
-- lib/chef/knife/core/status_presenter.rb
-- lib/chef/knife/core/subcommand_loader.rb
-- lib/chef/knife/core/text_formatter.rb
-- lib/chef/knife/core/ui.rb
-- lib/chef/knife/data_bag_create.rb
-- lib/chef/knife/data_bag_delete.rb
-- lib/chef/knife/data_bag_edit.rb
-- lib/chef/knife/data_bag_from_file.rb
-- lib/chef/knife/data_bag_list.rb
-- lib/chef/knife/data_bag_secret_options.rb
-- lib/chef/knife/data_bag_show.rb
-- lib/chef/knife/delete.rb
-- lib/chef/knife/deps.rb
-- lib/chef/knife/diff.rb
-- lib/chef/knife/download.rb
-- lib/chef/knife/edit.rb
-- lib/chef/knife/environment_compare.rb
-- lib/chef/knife/environment_create.rb
-- lib/chef/knife/environment_delete.rb
-- lib/chef/knife/environment_edit.rb
-- lib/chef/knife/environment_from_file.rb
-- lib/chef/knife/environment_list.rb
-- lib/chef/knife/environment_show.rb
-- lib/chef/knife/exec.rb
-- lib/chef/knife/help.rb
-- lib/chef/knife/help_topics.rb
-- lib/chef/knife/index_rebuild.rb
-- lib/chef/knife/list.rb
-- lib/chef/knife/node_bulk_delete.rb
-- lib/chef/knife/node_create.rb
-- lib/chef/knife/node_delete.rb
-- lib/chef/knife/node_edit.rb
-- lib/chef/knife/node_environment_set.rb
-- lib/chef/knife/node_from_file.rb
-- lib/chef/knife/node_list.rb
-- lib/chef/knife/node_run_list_add.rb
-- lib/chef/knife/node_run_list_remove.rb
-- lib/chef/knife/node_run_list_set.rb
-- lib/chef/knife/node_show.rb
-- lib/chef/knife/raw.rb
-- lib/chef/knife/recipe_list.rb
-- lib/chef/knife/role_bulk_delete.rb
-- lib/chef/knife/role_create.rb
-- lib/chef/knife/role_delete.rb
-- lib/chef/knife/role_edit.rb
-- lib/chef/knife/role_env_run_list_add.rb
-- lib/chef/knife/role_env_run_list_clear.rb
-- lib/chef/knife/role_env_run_list_remove.rb
-- lib/chef/knife/role_env_run_list_replace.rb
-- lib/chef/knife/role_env_run_list_set.rb
-- lib/chef/knife/role_from_file.rb
-- lib/chef/knife/role_list.rb
-- lib/chef/knife/role_run_list_add.rb
-- lib/chef/knife/role_run_list_clear.rb
-- lib/chef/knife/role_run_list_remove.rb
-- lib/chef/knife/role_run_list_replace.rb
-- lib/chef/knife/role_run_list_set.rb
-- lib/chef/knife/role_show.rb
-- lib/chef/knife/search.rb
-- lib/chef/knife/serve.rb
-- lib/chef/knife/show.rb
-- lib/chef/knife/ssh.rb
-- lib/chef/knife/ssl_check.rb
-- lib/chef/knife/ssl_fetch.rb
-- lib/chef/knife/status.rb
-- lib/chef/knife/tag_create.rb
-- lib/chef/knife/tag_delete.rb
-- lib/chef/knife/tag_list.rb
-- lib/chef/knife/upload.rb
-- lib/chef/knife/user_create.rb
-- lib/chef/knife/user_delete.rb
-- lib/chef/knife/user_edit.rb
-- lib/chef/knife/user_list.rb
-- lib/chef/knife/user_reregister.rb
-- lib/chef/knife/user_show.rb
-- lib/chef/knife/xargs.rb
-- lib/chef/local_mode.rb
-- lib/chef/log.rb
-- lib/chef/mash.rb
-- lib/chef/mixin/checksum.rb
-- lib/chef/mixin/command.rb
-- lib/chef/mixin/command/unix.rb
-- lib/chef/mixin/command/windows.rb
-- lib/chef/mixin/convert_to_class_name.rb
-- lib/chef/mixin/create_path.rb
-- lib/chef/mixin/deep_merge.rb
-- lib/chef/mixin/deprecation.rb
-- lib/chef/mixin/descendants_tracker.rb
-- lib/chef/mixin/enforce_ownership_and_permissions.rb
-- lib/chef/mixin/file_class.rb
-- lib/chef/mixin/from_file.rb
-- lib/chef/mixin/get_source_from_package.rb
-- lib/chef/mixin/homebrew_user.rb
-- lib/chef/mixin/language.rb
-- lib/chef/mixin/language_include_attribute.rb
-- lib/chef/mixin/language_include_recipe.rb
-- lib/chef/mixin/params_validate.rb
-- lib/chef/mixin/path_sanity.rb
-- lib/chef/mixin/powershell_type_coercions.rb
-- lib/chef/mixin/provides.rb
-- lib/chef/mixin/recipe_definition_dsl_core.rb
-- lib/chef/mixin/securable.rb
-- lib/chef/mixin/shell_out.rb
-- lib/chef/mixin/template.rb
-- lib/chef/mixin/which.rb
-- lib/chef/mixin/why_run.rb
-- lib/chef/mixin/windows_architecture_helper.rb
-- lib/chef/mixin/windows_env_helper.rb
-- lib/chef/mixin/xml_escape.rb
-- lib/chef/mixins.rb
-- lib/chef/monkey_patches/net-ssh-multi.rb
-- lib/chef/monkey_patches/net_http.rb
-- lib/chef/monologger.rb
-- lib/chef/nil_argument.rb
-- lib/chef/node.rb
-- lib/chef/node/attribute.rb
-- lib/chef/node/attribute_collections.rb
-- lib/chef/node/immutable_collections.rb
-- lib/chef/node_map.rb
-- lib/chef/null_logger.rb
-- lib/chef/org.rb
-- lib/chef/platform.rb
-- lib/chef/platform/provider_mapping.rb
-- lib/chef/platform/provider_priority_map.rb
-- lib/chef/platform/query_helpers.rb
-- lib/chef/platform/rebooter.rb
-- lib/chef/platform/resource_priority_map.rb
-- lib/chef/platform/service_helpers.rb
-- lib/chef/policy_builder.rb
-- lib/chef/policy_builder/expand_node_object.rb
-- lib/chef/policy_builder/policyfile.rb
-- lib/chef/provider.rb
-- lib/chef/provider/batch.rb
-- lib/chef/provider/breakpoint.rb
-- lib/chef/provider/cookbook_file.rb
-- lib/chef/provider/cookbook_file/content.rb
-- lib/chef/provider/cron.rb
-- lib/chef/provider/cron/aix.rb
-- lib/chef/provider/cron/solaris.rb
-- lib/chef/provider/cron/unix.rb
-- lib/chef/provider/deploy.rb
-- lib/chef/provider/deploy/revision.rb
-- lib/chef/provider/deploy/timestamped.rb
-- lib/chef/provider/directory.rb
-- lib/chef/provider/dsc_resource.rb
-- lib/chef/provider/dsc_script.rb
-- lib/chef/provider/env.rb
-- lib/chef/provider/env/windows.rb
-- lib/chef/provider/erl_call.rb
-- lib/chef/provider/execute.rb
-- lib/chef/provider/file.rb
-- lib/chef/provider/file/content.rb
-- lib/chef/provider/git.rb
-- lib/chef/provider/group.rb
-- lib/chef/provider/group/aix.rb
-- lib/chef/provider/group/dscl.rb
-- lib/chef/provider/group/gpasswd.rb
-- lib/chef/provider/group/groupadd.rb
-- lib/chef/provider/group/groupmod.rb
-- lib/chef/provider/group/pw.rb
-- lib/chef/provider/group/suse.rb
-- lib/chef/provider/group/usermod.rb
-- lib/chef/provider/group/windows.rb
-- lib/chef/provider/http_request.rb
-- lib/chef/provider/ifconfig.rb
-- lib/chef/provider/ifconfig/aix.rb
-- lib/chef/provider/ifconfig/debian.rb
-- lib/chef/provider/ifconfig/redhat.rb
-- lib/chef/provider/link.rb
-- lib/chef/provider/log.rb
-- lib/chef/provider/lwrp_base.rb
-- lib/chef/provider/mdadm.rb
-- lib/chef/provider/mount.rb
-- lib/chef/provider/mount/aix.rb
-- lib/chef/provider/mount/mount.rb
-- lib/chef/provider/mount/solaris.rb
-- lib/chef/provider/mount/windows.rb
-- lib/chef/provider/ohai.rb
-- lib/chef/provider/package.rb
-- lib/chef/provider/package/aix.rb
-- lib/chef/provider/package/apt.rb
-- lib/chef/provider/package/dpkg.rb
-- lib/chef/provider/package/easy_install.rb
-- lib/chef/provider/package/freebsd/base.rb
-- lib/chef/provider/package/freebsd/pkg.rb
-- lib/chef/provider/package/freebsd/pkgng.rb
-- lib/chef/provider/package/freebsd/port.rb
-- lib/chef/provider/package/homebrew.rb
-- lib/chef/provider/package/ips.rb
-- lib/chef/provider/package/macports.rb
-- lib/chef/provider/package/openbsd.rb
-- lib/chef/provider/package/pacman.rb
-- lib/chef/provider/package/paludis.rb
-- lib/chef/provider/package/portage.rb
-- lib/chef/provider/package/rpm.rb
-- lib/chef/provider/package/rubygems.rb
-- lib/chef/provider/package/smartos.rb
-- lib/chef/provider/package/solaris.rb
-- lib/chef/provider/package/windows.rb
-- lib/chef/provider/package/windows/msi.rb
-- lib/chef/provider/package/yum-dump.py
-- lib/chef/provider/package/yum.rb
-- lib/chef/provider/package/zypper.rb
-- lib/chef/provider/powershell_script.rb
-- lib/chef/provider/reboot.rb
-- lib/chef/provider/registry_key.rb
-- lib/chef/provider/remote_directory.rb
-- lib/chef/provider/remote_file.rb
-- lib/chef/provider/remote_file/cache_control_data.rb
-- lib/chef/provider/remote_file/content.rb
-- lib/chef/provider/remote_file/fetcher.rb
-- lib/chef/provider/remote_file/ftp.rb
-- lib/chef/provider/remote_file/http.rb
-- lib/chef/provider/remote_file/local_file.rb
-- lib/chef/provider/resource_update.rb
-- lib/chef/provider/route.rb
-- lib/chef/provider/ruby_block.rb
-- lib/chef/provider/script.rb
-- lib/chef/provider/service.rb
-- lib/chef/provider/service/aix.rb
-- lib/chef/provider/service/aixinit.rb
-- lib/chef/provider/service/arch.rb
-- lib/chef/provider/service/debian.rb
-- lib/chef/provider/service/freebsd.rb
-- lib/chef/provider/service/gentoo.rb
-- lib/chef/provider/service/init.rb
-- lib/chef/provider/service/insserv.rb
-- lib/chef/provider/service/invokercd.rb
-- lib/chef/provider/service/macosx.rb
-- lib/chef/provider/service/openbsd.rb
-- lib/chef/provider/service/redhat.rb
-- lib/chef/provider/service/simple.rb
-- lib/chef/provider/service/solaris.rb
-- lib/chef/provider/service/systemd.rb
-- lib/chef/provider/service/upstart.rb
-- lib/chef/provider/service/windows.rb
-- lib/chef/provider/subversion.rb
-- lib/chef/provider/template.rb
-- lib/chef/provider/template/content.rb
-- lib/chef/provider/template_finder.rb
-- lib/chef/provider/user.rb
-- lib/chef/provider/user/aix.rb
-- lib/chef/provider/user/dscl.rb
-- lib/chef/provider/user/pw.rb
-- lib/chef/provider/user/solaris.rb
-- lib/chef/provider/user/useradd.rb
-- lib/chef/provider/user/windows.rb
-- lib/chef/provider/whyrun_safe_ruby_block.rb
-- lib/chef/provider/windows_script.rb
-- lib/chef/provider_resolver.rb
-- lib/chef/providers.rb
-- lib/chef/recipe.rb
-- lib/chef/request_id.rb
-- lib/chef/reserved_names.rb
-- lib/chef/resource.rb
-- lib/chef/resource/apt_package.rb
-- lib/chef/resource/bash.rb
-- lib/chef/resource/batch.rb
-- lib/chef/resource/bff_package.rb
-- lib/chef/resource/breakpoint.rb
-- lib/chef/resource/chef_gem.rb
-- lib/chef/resource/conditional.rb
-- lib/chef/resource/conditional_action_not_nothing.rb
-- lib/chef/resource/cookbook_file.rb
-- lib/chef/resource/cron.rb
-- lib/chef/resource/csh.rb
-- lib/chef/resource/deploy.rb
-- lib/chef/resource/deploy_revision.rb
-- lib/chef/resource/directory.rb
-- lib/chef/resource/dpkg_package.rb
-- lib/chef/resource/dsc_resource.rb
-- lib/chef/resource/dsc_script.rb
-- lib/chef/resource/easy_install_package.rb
-- lib/chef/resource/env.rb
-- lib/chef/resource/erl_call.rb
-- lib/chef/resource/execute.rb
-- lib/chef/resource/file.rb
-- lib/chef/resource/file/verification.rb
-- lib/chef/resource/freebsd_package.rb
-- lib/chef/resource/gem_package.rb
-- lib/chef/resource/git.rb
-- lib/chef/resource/group.rb
-- lib/chef/resource/homebrew_package.rb
-- lib/chef/resource/http_request.rb
-- lib/chef/resource/ifconfig.rb
-- lib/chef/resource/ips_package.rb
-- lib/chef/resource/link.rb
-- lib/chef/resource/log.rb
-- lib/chef/resource/lwrp_base.rb
-- lib/chef/resource/macosx_service.rb
-- lib/chef/resource/macports_package.rb
-- lib/chef/resource/mdadm.rb
-- lib/chef/resource/mount.rb
-- lib/chef/resource/ohai.rb
-- lib/chef/resource/openbsd_package.rb
-- lib/chef/resource/package.rb
-- lib/chef/resource/pacman_package.rb
-- lib/chef/resource/paludis_package.rb
-- lib/chef/resource/perl.rb
-- lib/chef/resource/portage_package.rb
-- lib/chef/resource/powershell_script.rb
-- lib/chef/resource/python.rb
-- lib/chef/resource/reboot.rb
-- lib/chef/resource/registry_key.rb
-- lib/chef/resource/remote_directory.rb
-- lib/chef/resource/remote_file.rb
-- lib/chef/resource/resource_notification.rb
-- lib/chef/resource/route.rb
-- lib/chef/resource/rpm_package.rb
-- lib/chef/resource/ruby.rb
-- lib/chef/resource/ruby_block.rb
-- lib/chef/resource/scm.rb
-- lib/chef/resource/script.rb
-- lib/chef/resource/service.rb
-- lib/chef/resource/smartos_package.rb
-- lib/chef/resource/solaris_package.rb
-- lib/chef/resource/subversion.rb
-- lib/chef/resource/template.rb
-- lib/chef/resource/timestamped_deploy.rb
-- lib/chef/resource/user.rb
-- lib/chef/resource/whyrun_safe_ruby_block.rb
-- lib/chef/resource/windows_package.rb
-- lib/chef/resource/windows_script.rb
-- lib/chef/resource/windows_service.rb
-- lib/chef/resource/yum_package.rb
-- lib/chef/resource_builder.rb
-- lib/chef/resource_collection.rb
-- lib/chef/resource_collection/resource_collection_serialization.rb
-- lib/chef/resource_collection/resource_list.rb
-- lib/chef/resource_collection/resource_set.rb
-- lib/chef/resource_collection/stepable_iterator.rb
-- lib/chef/resource_definition.rb
-- lib/chef/resource_definition_list.rb
-- lib/chef/resource_reporter.rb
-- lib/chef/resource_resolver.rb
-- lib/chef/resources.rb
-- lib/chef/rest.rb
-- lib/chef/role.rb
-- lib/chef/run_context.rb
-- lib/chef/run_context/cookbook_compiler.rb
-- lib/chef/run_list.rb
-- lib/chef/run_list/run_list_expansion.rb
-- lib/chef/run_list/run_list_item.rb
-- lib/chef/run_list/versioned_recipe_list.rb
-- lib/chef/run_lock.rb
-- lib/chef/run_status.rb
-- lib/chef/runner.rb
-- lib/chef/sandbox.rb
-- lib/chef/scan_access_control.rb
-- lib/chef/search/query.rb
-- lib/chef/server_api.rb
-- lib/chef/shell.rb
-- lib/chef/shell/ext.rb
-- lib/chef/shell/model_wrapper.rb
-- lib/chef/shell/shell_rest.rb
-- lib/chef/shell/shell_session.rb
-- lib/chef/shell_out.rb
-- lib/chef/tasks/chef_repo.rake
-- lib/chef/user.rb
-- lib/chef/util/backup.rb
-- lib/chef/util/diff.rb
-- lib/chef/util/dsc/configuration_generator.rb
-- lib/chef/util/dsc/lcm_output_parser.rb
-- lib/chef/util/dsc/local_configuration_manager.rb
-- lib/chef/util/dsc/resource_info.rb
-- lib/chef/util/dsc/resource_store.rb
-- lib/chef/util/editor.rb
-- lib/chef/util/file_edit.rb
-- lib/chef/util/path_helper.rb
-- lib/chef/util/powershell/cmdlet.rb
-- lib/chef/util/powershell/cmdlet_result.rb
-- lib/chef/util/powershell/ps_credential.rb
-- lib/chef/util/selinux.rb
-- lib/chef/util/threaded_job_queue.rb
-- lib/chef/util/windows.rb
-- lib/chef/util/windows/net_group.rb
-- lib/chef/util/windows/net_use.rb
-- lib/chef/util/windows/net_user.rb
-- lib/chef/util/windows/volume.rb
-- lib/chef/version.rb
-- lib/chef/version/platform.rb
-- lib/chef/version_class.rb
-- lib/chef/version_constraint.rb
-- lib/chef/version_constraint/platform.rb
-- lib/chef/whitelist.rb
-- lib/chef/win32/api.rb
-- lib/chef/win32/api/crypto.rb
-- lib/chef/win32/api/error.rb
-- lib/chef/win32/api/file.rb
-- lib/chef/win32/api/installer.rb
-- lib/chef/win32/api/memory.rb
-- lib/chef/win32/api/net.rb
-- lib/chef/win32/api/process.rb
-- lib/chef/win32/api/psapi.rb
-- lib/chef/win32/api/security.rb
-- lib/chef/win32/api/synchronization.rb
-- lib/chef/win32/api/system.rb
-- lib/chef/win32/api/unicode.rb
-- lib/chef/win32/crypto.rb
-- lib/chef/win32/error.rb
-- lib/chef/win32/file.rb
-- lib/chef/win32/file/info.rb
-- lib/chef/win32/handle.rb
-- lib/chef/win32/memory.rb
-- lib/chef/win32/mutex.rb
-- lib/chef/win32/process.rb
-- lib/chef/win32/registry.rb
-- lib/chef/win32/security.rb
-- lib/chef/win32/security/ace.rb
-- lib/chef/win32/security/acl.rb
-- lib/chef/win32/security/securable_object.rb
-- lib/chef/win32/security/security_descriptor.rb
-- lib/chef/win32/security/sid.rb
-- lib/chef/win32/security/token.rb
-- lib/chef/win32/unicode.rb
-- lib/chef/win32/version.rb
-- lib/chef/workstation_config_loader.rb
-- spec/data/apt/chef-integration-test-1.0/debian/changelog
-- spec/data/apt/chef-integration-test-1.0/debian/compat
-- spec/data/apt/chef-integration-test-1.0/debian/control
-- spec/data/apt/chef-integration-test-1.0/debian/copyright
-- spec/data/apt/chef-integration-test-1.0/debian/files
-- spec/data/apt/chef-integration-test-1.0/debian/rules
-- spec/data/apt/chef-integration-test-1.0/debian/source/format
-- spec/data/apt/chef-integration-test-1.1/debian/changelog
-- spec/data/apt/chef-integration-test-1.1/debian/compat
-- spec/data/apt/chef-integration-test-1.1/debian/control
-- spec/data/apt/chef-integration-test-1.1/debian/copyright
-- spec/data/apt/chef-integration-test-1.1/debian/files
-- spec/data/apt/chef-integration-test-1.1/debian/rules
-- spec/data/apt/chef-integration-test-1.1/debian/source/format
-- spec/data/apt/chef-integration-test_1.0-1_amd64.changes
-- spec/data/apt/chef-integration-test_1.0-1_amd64.deb
-- spec/data/apt/chef-integration-test_1.0.orig.tar.gz
-- spec/data/apt/chef-integration-test_1.1-1_amd64.changes
-- spec/data/apt/chef-integration-test_1.1-1_amd64.deb
-- spec/data/apt/chef-integration-test_1.1.orig.tar.gz
-- spec/data/apt/var/www/apt/conf/distributions
-- spec/data/apt/var/www/apt/conf/incoming
-- spec/data/apt/var/www/apt/conf/pulls
-- spec/data/apt/var/www/apt/db/checksums.db
-- spec/data/apt/var/www/apt/db/contents.cache.db
-- spec/data/apt/var/www/apt/db/packages.db
-- spec/data/apt/var/www/apt/db/references.db
-- spec/data/apt/var/www/apt/db/release.caches.db
-- spec/data/apt/var/www/apt/db/version
-- spec/data/apt/var/www/apt/dists/sid/Release
-- spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages
-- spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages.gz
-- spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Release
-- spec/data/apt/var/www/apt/dists/sid/main/binary-i386/Packages
-- spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.0-1_amd64.deb
-- spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.deb
-- spec/data/bad-config.rb
-- spec/data/bootstrap/encrypted_data_bag_secret
-- spec/data/bootstrap/no_proxy.erb
-- spec/data/bootstrap/secret.erb
-- spec/data/bootstrap/test-hints.erb
-- spec/data/bootstrap/test.erb
-- spec/data/cb_version_cookbooks/cookbook2/files/test.txt
-- spec/data/cb_version_cookbooks/cookbook2/templates/test.erb
-- spec/data/cb_version_cookbooks/tatft/README.rdoc
-- spec/data/cb_version_cookbooks/tatft/attributes/default.rb
-- spec/data/cb_version_cookbooks/tatft/definitions/runit_service.rb
-- spec/data/cb_version_cookbooks/tatft/files/default/giant_blob.tgz
-- spec/data/cb_version_cookbooks/tatft/libraries/ownage.rb
-- spec/data/cb_version_cookbooks/tatft/providers/lwp.rb
-- spec/data/cb_version_cookbooks/tatft/recipes/default.rb
-- spec/data/cb_version_cookbooks/tatft/resources/lwr.rb
-- spec/data/cb_version_cookbooks/tatft/templates/default/configuration.erb
-- spec/data/checksum/random.txt
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-600hhz-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-6m8zdk-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ahd2gq-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-api8ux-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-b0r1m1-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-bfygsi-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-el14l6-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ivrl3y-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-kkbs85-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ory1ux-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-pgsq76-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ra8uim-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t7k1g-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t8g0sv-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ufy6g3-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-x2d6j9-0
-- spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-xi0l6h-0
-- spec/data/config.rb
-- spec/data/cookbooks/angrybash/metadata.rb
-- spec/data/cookbooks/angrybash/recipes/default.rb
-- spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl
-- spec/data/cookbooks/apache2/metadata.rb
-- spec/data/cookbooks/apache2/recipes/default.rb
-- spec/data/cookbooks/borken/metadata.rb
-- spec/data/cookbooks/borken/recipes/default.rb
-- spec/data/cookbooks/borken/templates/default/borken.erb
-- spec/data/cookbooks/chefignore
-- spec/data/cookbooks/ignorken/files/default/not_me.rb
-- spec/data/cookbooks/ignorken/metadata.rb
-- spec/data/cookbooks/ignorken/recipes/default.rb
-- spec/data/cookbooks/ignorken/recipes/ignoreme.rb
-- spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb
-- spec/data/cookbooks/java/files/default/java.response
-- spec/data/cookbooks/java/metadata.rb
-- spec/data/cookbooks/name-mismatch-versionnumber/README.md
-- spec/data/cookbooks/name-mismatch-versionnumber/metadata.rb
-- spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
-- spec/data/cookbooks/openldap/attributes/default.rb
-- spec/data/cookbooks/openldap/attributes/smokey.rb
-- spec/data/cookbooks/openldap/definitions/client.rb
-- spec/data/cookbooks/openldap/definitions/server.rb
-- spec/data/cookbooks/openldap/files/default/.dotfile
-- spec/data/cookbooks/openldap/files/default/.ssh/id_rsa
-- spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir
-- spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb
-- spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt
-- spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt
-- spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile
-- spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt
-- spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt
-- spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt
-- spec/data/cookbooks/openldap/libraries/openldap.rb
-- spec/data/cookbooks/openldap/libraries/openldap/version.rb
-- spec/data/cookbooks/openldap/metadata.rb
-- spec/data/cookbooks/openldap/recipes/default.rb
-- spec/data/cookbooks/openldap/recipes/gigantor.rb
-- spec/data/cookbooks/openldap/recipes/one.rb
-- spec/data/cookbooks/openldap/recipes/return.rb
-- spec/data/cookbooks/openldap/templates/default/all_windows_line_endings.erb
-- spec/data/cookbooks/openldap/templates/default/helper_test.erb
-- spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb
-- spec/data/cookbooks/openldap/templates/default/no_windows_line_endings.erb
-- spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb
-- spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb
-- spec/data/cookbooks/openldap/templates/default/some_windows_line_endings.erb
-- spec/data/cookbooks/openldap/templates/default/test.erb
-- spec/data/cookbooks/preseed/files/default/preseed-file.seed
-- spec/data/cookbooks/preseed/files/default/preseed-template.seed
-- spec/data/cookbooks/preseed/metadata.rb
-- spec/data/cookbooks/preseed/templates/default/preseed-template-variables.seed
-- spec/data/cookbooks/preseed/templates/default/preseed-template.seed
-- spec/data/definitions/test.rb
-- spec/data/environment-config.rb
-- spec/data/file-providers-method-snapshot-chef-11-4.json
-- spec/data/fileedit/blank
-- spec/data/fileedit/hosts
-- spec/data/gems/chef-integration-test-0.1.0.gem
-- spec/data/git_bundles/example-repo.gitbundle
-- spec/data/git_bundles/sinatra-test-app-with-callback-files.gitbundle
-- spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle
-- spec/data/git_bundles/sinatra-test-app.gitbundle
-- spec/data/incomplete-metadata-chef-repo/incomplete-metadata/README.md
-- spec/data/incomplete-metadata-chef-repo/incomplete-metadata/metadata.rb
-- spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
-- spec/data/invalid-metadata-chef-repo/invalid-metadata/README.md
-- spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
-- spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
-- spec/data/kitchen/chefignore
-- spec/data/kitchen/openldap/attributes/default.rb
-- spec/data/kitchen/openldap/attributes/robinson.rb
-- spec/data/kitchen/openldap/definitions/client.rb
-- spec/data/kitchen/openldap/definitions/drewbarrymore.rb
-- spec/data/kitchen/openldap/recipes/gigantor.rb
-- spec/data/kitchen/openldap/recipes/ignoreme.rb
-- spec/data/kitchen/openldap/recipes/woot.rb
-- spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb
-- spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb
-- spec/data/knife_subcommand/test_explicit_category.rb
-- spec/data/knife_subcommand/test_name_mapping.rb
-- spec/data/knife_subcommand/test_yourself.rb
-- spec/data/lwrp/providers/buck_passer.rb
-- spec/data/lwrp/providers/buck_passer_2.rb
-- spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb
-- spec/data/lwrp/providers/inline_compiler.rb
-- spec/data/lwrp/providers/monkey_name_printer.rb
-- spec/data/lwrp/providers/paint_drying_watcher.rb
-- spec/data/lwrp/providers/thumb_twiddler.rb
-- spec/data/lwrp/resources/bar.rb
-- spec/data/lwrp/resources/foo.rb
-- spec/data/lwrp/resources_with_default_attributes/nodeattr.rb
-- spec/data/lwrp_const_scoping/resources/conflict.rb
-- spec/data/lwrp_override/providers/buck_passer.rb
-- spec/data/lwrp_override/resources/foo.rb
-- spec/data/mac_users/10.7-8.plist.xml
-- spec/data/mac_users/10.7-8.shadow.xml
-- spec/data/mac_users/10.7.plist.xml
-- spec/data/mac_users/10.7.shadow.xml
-- spec/data/mac_users/10.8.plist.xml
-- spec/data/mac_users/10.8.shadow.xml
-- spec/data/mac_users/10.9.plist.xml
-- spec/data/mac_users/10.9.shadow.xml
-- spec/data/metadata/quick_start/metadata.rb
-- spec/data/nested.json
-- spec/data/nodes/default.rb
-- spec/data/nodes/test.example.com.rb
-- spec/data/nodes/test.rb
-- spec/data/null_config.rb
-- spec/data/object_loader/environments/test.json
-- spec/data/object_loader/environments/test.rb
-- spec/data/object_loader/environments/test_json_class.json
-- spec/data/object_loader/nodes/test.json
-- spec/data/object_loader/nodes/test.rb
-- spec/data/object_loader/nodes/test_json_class.json
-- spec/data/object_loader/roles/test.json
-- spec/data/object_loader/roles/test.rb
-- spec/data/object_loader/roles/test_json_class.json
-- spec/data/old_home_dir/my-dot-emacs
-- spec/data/old_home_dir/my-dot-vim
-- spec/data/partial_one.erb
-- spec/data/recipes.tgz
-- spec/data/recipes/test.rb
-- spec/data/remote_directory_data/remote_dir_file.txt
-- spec/data/remote_directory_data/remote_subdirectory/remote_subdir_file.txt
-- spec/data/remote_file/nyan_cat.png
-- spec/data/remote_file/nyan_cat.png.gz
-- spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb
-- spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb
-- spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb
-- spec/data/run_context/cookbooks/circular-dep1/metadata.rb
-- spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb
-- spec/data/run_context/cookbooks/circular-dep1/recipes/default.rb
-- spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb
-- spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb
-- spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb
-- spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb
-- spec/data/run_context/cookbooks/circular-dep2/metadata.rb
-- spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb
-- spec/data/run_context/cookbooks/circular-dep2/recipes/default.rb
-- spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb
-- spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb
-- spec/data/run_context/cookbooks/dependency1/attributes/default.rb
-- spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb
-- spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb
-- spec/data/run_context/cookbooks/dependency1/libraries/lib.rb
-- spec/data/run_context/cookbooks/dependency1/providers/provider.rb
-- spec/data/run_context/cookbooks/dependency1/recipes/default.rb
-- spec/data/run_context/cookbooks/dependency1/resources/resource.rb
-- spec/data/run_context/cookbooks/dependency2/attributes/default.rb
-- spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb
-- spec/data/run_context/cookbooks/dependency2/libraries/lib.rb
-- spec/data/run_context/cookbooks/dependency2/providers/provider.rb
-- spec/data/run_context/cookbooks/dependency2/recipes/default.rb
-- spec/data/run_context/cookbooks/dependency2/resources/resource.rb
-- spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb
-- spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb
-- spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb
-- spec/data/run_context/cookbooks/no-default-attr/recipes/default.rb
-- spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/recipes/default.rb
-- spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb
-- spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb
-- spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb
-- spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb
-- spec/data/run_context/cookbooks/test-with-deps/metadata.rb
-- spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb
-- spec/data/run_context/cookbooks/test-with-deps/recipes/default.rb
-- spec/data/run_context/cookbooks/test-with-deps/recipes/server.rb
-- spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb
-- spec/data/run_context/cookbooks/test/attributes/default.rb
-- spec/data/run_context/cookbooks/test/attributes/george.rb
-- spec/data/run_context/cookbooks/test/definitions/new_animals.rb
-- spec/data/run_context/cookbooks/test/definitions/new_cat.rb
-- spec/data/run_context/cookbooks/test/definitions/test_res.rb
-- spec/data/run_context/cookbooks/test/providers/provider.rb
-- spec/data/run_context/cookbooks/test/recipes/default.rb
-- spec/data/run_context/cookbooks/test/recipes/one.rb
-- spec/data/run_context/cookbooks/test/recipes/two.rb
-- spec/data/run_context/cookbooks/test/resources/resource.rb
-- spec/data/run_context/nodes/run_context.rb
-- spec/data/search_queries_to_transform.txt
-- spec/data/shef-config.rb
-- spec/data/ssl/5e707473.0
-- spec/data/ssl/chef-rspec.cert
-- spec/data/ssl/chef-rspec.key
-- spec/data/ssl/key.pem
-- spec/data/ssl/private_key.pem
-- spec/data/ssl/private_key_with_whitespace.pem
-- spec/data/standalone_cookbook/Gemfile
-- spec/data/standalone_cookbook/chefignore
-- spec/data/standalone_cookbook/recipes/default.rb
-- spec/data/standalone_cookbook/vendor/bundle/ruby/2.0.0/gems/multi_json-1.9.0/lib/multi_json.rb
-- spec/data/templates/seattle.txt
-- spec/data/trusted_certs/example.crt
-- spec/data/trusted_certs/intermediate.pem
-- spec/data/trusted_certs/opscode.pem
-- spec/data/trusted_certs/root.pem
-- spec/functional/application_spec.rb
-- spec/functional/assets/PkgA.1.0.0.0.bff
-- spec/functional/assets/PkgA.2.0.0.0.bff
-- spec/functional/assets/chefinittest
-- spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm
-- spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm
-- spec/functional/assets/mytest-1.0-1.noarch.rpm
-- spec/functional/assets/mytest-2.0-1.noarch.rpm
-- spec/functional/assets/testchefsubsys
-- spec/functional/audit/rspec_formatter_spec.rb
-- spec/functional/audit/runner_spec.rb
-- spec/functional/dsl/reboot_pending_spec.rb
-- spec/functional/dsl/registry_helper_spec.rb
-- spec/functional/event_loggers/windows_eventlog_spec.rb
-- spec/functional/file_content_management/deploy_strategies_spec.rb
-- spec/functional/http/simple_spec.rb
-- spec/functional/knife/configure_spec.rb
-- spec/functional/knife/cookbook_delete_spec.rb
-- spec/functional/knife/exec_spec.rb
-- spec/functional/knife/smoke_test.rb
-- spec/functional/knife/ssh_spec.rb
-- spec/functional/mixin/shell_out_spec.rb
-- spec/functional/notifications_spec.rb
-- spec/functional/provider/remote_file/cache_control_data_spec.rb
-- spec/functional/provider/whyrun_safe_ruby_block_spec.rb
-- spec/functional/rebooter_spec.rb
-- spec/functional/resource/aix_service_spec.rb
-- spec/functional/resource/aixinit_service_spec.rb
-- spec/functional/resource/base.rb
-- spec/functional/resource/bash_spec.rb
-- spec/functional/resource/batch_spec.rb
-- spec/functional/resource/bff_spec.rb
-- spec/functional/resource/cookbook_file_spec.rb
-- spec/functional/resource/cron_spec.rb
-- spec/functional/resource/deploy_revision_spec.rb
-- spec/functional/resource/directory_spec.rb
-- spec/functional/resource/dsc_resource_spec.rb
-- spec/functional/resource/dsc_script_spec.rb
-- spec/functional/resource/env_spec.rb
-- spec/functional/resource/execute_spec.rb
-- spec/functional/resource/file_spec.rb
-- spec/functional/resource/git_spec.rb
-- spec/functional/resource/group_spec.rb
-- spec/functional/resource/ifconfig_spec.rb
-- spec/functional/resource/link_spec.rb
-- spec/functional/resource/mount_spec.rb
-- spec/functional/resource/ohai_spec.rb
-- spec/functional/resource/package_spec.rb
-- spec/functional/resource/powershell_spec.rb
-- spec/functional/resource/reboot_spec.rb
-- spec/functional/resource/registry_spec.rb
-- spec/functional/resource/remote_directory_spec.rb
-- spec/functional/resource/remote_file_spec.rb
-- spec/functional/resource/rpm_spec.rb
-- spec/functional/resource/template_spec.rb
-- spec/functional/resource/user/dscl_spec.rb
-- spec/functional/resource/user/useradd_spec.rb
-- spec/functional/resource/windows_service_spec.rb
-- spec/functional/rest_spec.rb
-- spec/functional/run_lock_spec.rb
-- spec/functional/shell_spec.rb
-- spec/functional/tiny_server_spec.rb
-- spec/functional/util/path_helper_spec.rb
-- spec/functional/util/powershell/cmdlet_spec.rb
-- spec/functional/version_spec.rb
-- spec/functional/win32/crypto_spec.rb
-- spec/functional/win32/registry_helper_spec.rb
-- spec/functional/win32/security_spec.rb
-- spec/functional/win32/service_manager_spec.rb
-- spec/functional/win32/versions_spec.rb
-- spec/integration/client/client_spec.rb
-- spec/integration/client/ipv6_spec.rb
-- spec/integration/knife/chef_fs_data_store_spec.rb
-- spec/integration/knife/chef_repo_path_spec.rb
-- spec/integration/knife/chef_repository_file_system_spec.rb
-- spec/integration/knife/chefignore_spec.rb
-- spec/integration/knife/common_options_spec.rb
-- spec/integration/knife/cookbook_api_ipv6_spec.rb
-- spec/integration/knife/delete_spec.rb
-- spec/integration/knife/deps_spec.rb
-- spec/integration/knife/diff_spec.rb
-- spec/integration/knife/download_spec.rb
-- spec/integration/knife/list_spec.rb
-- spec/integration/knife/raw_spec.rb
-- spec/integration/knife/redirection_spec.rb
-- spec/integration/knife/serve_spec.rb
-- spec/integration/knife/show_spec.rb
-- spec/integration/knife/upload_spec.rb
-- spec/integration/recipes/lwrp_inline_resources_spec.rb
-- spec/integration/solo/solo_spec.rb
-- spec/rcov.opts
-- spec/scripts/ssl-serve.rb
-- spec/spec_helper.rb
-- spec/stress/win32/file_spec.rb
-- spec/stress/win32/memory_spec.rb
-- spec/stress/win32/security_spec.rb
-- spec/support/chef_helpers.rb
-- spec/support/lib/chef/provider/easy.rb
-- spec/support/lib/chef/provider/snakeoil.rb
-- spec/support/lib/chef/resource/cat.rb
-- spec/support/lib/chef/resource/one_two_three_four.rb
-- spec/support/lib/chef/resource/with_state.rb
-- spec/support/lib/chef/resource/zen_follower.rb
-- spec/support/lib/chef/resource/zen_master.rb
-- spec/support/lib/library_load_order.rb
-- spec/support/matchers/leak.rb
-- spec/support/mock/constant.rb
-- spec/support/mock/platform.rb
-- spec/support/pedant/Gemfile
-- spec/support/pedant/pedant_config.rb
-- spec/support/pedant/run_pedant.rb
-- spec/support/pedant/stickywicket.pem
-- spec/support/platform_helpers.rb
-- spec/support/platforms/prof/gc.rb
-- spec/support/platforms/prof/win32.rb
-- spec/support/platforms/win32/spec_service.rb
-- spec/support/shared/context/config.rb
-- spec/support/shared/functional/diff_disabled.rb
-- spec/support/shared/functional/directory_resource.rb
-- spec/support/shared/functional/file_resource.rb
-- spec/support/shared/functional/http.rb
-- spec/support/shared/functional/knife.rb
-- spec/support/shared/functional/securable_resource.rb
-- spec/support/shared/functional/securable_resource_with_reporting.rb
-- spec/support/shared/functional/win32_service.rb
-- spec/support/shared/functional/windows_script.rb
-- spec/support/shared/integration/app_server_support.rb
-- spec/support/shared/integration/integration_helper.rb
-- spec/support/shared/integration/knife_support.rb
-- spec/support/shared/matchers/exit_with_code.rb
-- spec/support/shared/matchers/match_environment_variable.rb
-- spec/support/shared/shared_examples.rb
-- spec/support/shared/unit/api_error_inspector.rb
-- spec/support/shared/unit/execute_resource.rb
-- spec/support/shared/unit/file_system_support.rb
-- spec/support/shared/unit/platform_introspector.rb
-- spec/support/shared/unit/provider/file.rb
-- spec/support/shared/unit/provider/useradd_based_user_provider.rb
-- spec/support/shared/unit/resource/static_provider_resolution.rb
-- spec/support/shared/unit/script_resource.rb
-- spec/support/shared/unit/windows_script_resource.rb
-- spec/tiny_server.rb
-- spec/unit/api_client/registration_spec.rb
-- spec/unit/api_client_spec.rb
-- spec/unit/application/agent_spec.rb
-- spec/unit/application/apply_spec.rb
-- spec/unit/application/client_spec.rb
-- spec/unit/application/knife_spec.rb
-- spec/unit/application/server_spec.rb
-- spec/unit/application/solo_spec.rb
-- spec/unit/application_spec.rb
-- spec/unit/audit/audit_event_proxy_spec.rb
-- spec/unit/audit/audit_reporter_spec.rb
-- spec/unit/audit/control_group_data_spec.rb
-- spec/unit/audit/rspec_formatter_spec.rb
-- spec/unit/audit/runner_spec.rb
-- spec/unit/chef_class_spec.rb
-- spec/unit/chef_fs/config_spec.rb
-- spec/unit/chef_fs/data_handler/group_handler_spec.rb
-- spec/unit/chef_fs/diff_spec.rb
-- spec/unit/chef_fs/file_pattern_spec.rb
-- spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
-- spec/unit/chef_fs/file_system_spec.rb
-- spec/unit/chef_fs/parallelizer.rb
-- spec/unit/chef_spec.rb
-- spec/unit/client_spec.rb
-- spec/unit/config_fetcher_spec.rb
-- spec/unit/config_spec.rb
-- spec/unit/cookbook/chefignore_spec.rb
-- spec/unit/cookbook/cookbook_version_loader_spec.rb
-- spec/unit/cookbook/file_vendor_spec.rb
-- spec/unit/cookbook/metadata_spec.rb
-- spec/unit/cookbook/synchronizer_spec.rb
-- spec/unit/cookbook/syntax_check_spec.rb
-- spec/unit/cookbook_loader_spec.rb
-- spec/unit/cookbook_manifest_spec.rb
-- spec/unit/cookbook_site_streaming_uploader_spec.rb
-- spec/unit/cookbook_spec.rb
-- spec/unit/cookbook_uploader_spec.rb
-- spec/unit/cookbook_version_file_specificity_spec.rb
-- spec/unit/cookbook_version_spec.rb
-- spec/unit/daemon_spec.rb
-- spec/unit/data_bag_item_spec.rb
-- spec/unit/data_bag_spec.rb
-- spec/unit/deprecation_spec.rb
-- spec/unit/digester_spec.rb
-- spec/unit/dsl/audit_spec.rb
-- spec/unit/dsl/data_query_spec.rb
-- spec/unit/dsl/platform_introspection_spec.rb
-- spec/unit/dsl/reboot_pending_spec.rb
-- spec/unit/dsl/recipe_spec.rb
-- spec/unit/dsl/regsitry_helper_spec.rb
-- spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
-- spec/unit/encrypted_data_bag_item_spec.rb
-- spec/unit/environment_spec.rb
-- spec/unit/exceptions_spec.rb
-- spec/unit/file_access_control_spec.rb
-- spec/unit/file_cache_spec.rb
-- spec/unit/file_content_management/deploy/cp_spec.rb
-- spec/unit/file_content_management/deploy/mv_unix_spec.rb
-- spec/unit/file_content_management/deploy/mv_windows_spec.rb
-- spec/unit/formatters/base_spec.rb
-- spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
-- spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
-- spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
-- spec/unit/guard_interpreter_spec.rb
-- spec/unit/handler/json_file_spec.rb
-- spec/unit/handler_spec.rb
-- spec/unit/http/basic_client_spec.rb
-- spec/unit/http/http_request_spec.rb
-- spec/unit/http/json_input_spec.rb
-- spec/unit/http/simple_spec.rb
-- spec/unit/http/socketless_chef_zero_client_spec.rb
-- spec/unit/http/ssl_policies_spec.rb
-- spec/unit/http/validate_content_length_spec.rb
-- spec/unit/http_spec.rb
-- spec/unit/json_compat_spec.rb
-- spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
-- spec/unit/knife/bootstrap/client_builder_spec.rb
-- spec/unit/knife/bootstrap_spec.rb
-- spec/unit/knife/client_bulk_delete_spec.rb
-- spec/unit/knife/client_create_spec.rb
-- spec/unit/knife/client_delete_spec.rb
-- spec/unit/knife/client_edit_spec.rb
-- spec/unit/knife/client_list_spec.rb
-- spec/unit/knife/client_reregister_spec.rb
-- spec/unit/knife/client_show_spec.rb
-- spec/unit/knife/configure_client_spec.rb
-- spec/unit/knife/configure_spec.rb
-- spec/unit/knife/cookbook_bulk_delete_spec.rb
-- spec/unit/knife/cookbook_create_spec.rb
-- spec/unit/knife/cookbook_delete_spec.rb
-- spec/unit/knife/cookbook_download_spec.rb
-- spec/unit/knife/cookbook_list_spec.rb
-- spec/unit/knife/cookbook_metadata_from_file_spec.rb
-- spec/unit/knife/cookbook_metadata_spec.rb
-- spec/unit/knife/cookbook_show_spec.rb
-- spec/unit/knife/cookbook_site_download_spec.rb
-- spec/unit/knife/cookbook_site_install_spec.rb
-- spec/unit/knife/cookbook_site_share_spec.rb
-- spec/unit/knife/cookbook_site_unshare_spec.rb
-- spec/unit/knife/cookbook_test_spec.rb
-- spec/unit/knife/cookbook_upload_spec.rb
-- spec/unit/knife/core/bootstrap_context_spec.rb
-- spec/unit/knife/core/cookbook_scm_repo_spec.rb
-- spec/unit/knife/core/object_loader_spec.rb
-- spec/unit/knife/core/subcommand_loader_spec.rb
-- spec/unit/knife/core/ui_spec.rb
-- spec/unit/knife/data_bag_create_spec.rb
-- spec/unit/knife/data_bag_edit_spec.rb
-- spec/unit/knife/data_bag_from_file_spec.rb
-- spec/unit/knife/data_bag_secret_options_spec.rb
-- spec/unit/knife/data_bag_show_spec.rb
-- spec/unit/knife/environment_compare_spec.rb
-- spec/unit/knife/environment_create_spec.rb
-- spec/unit/knife/environment_delete_spec.rb
-- spec/unit/knife/environment_edit_spec.rb
-- spec/unit/knife/environment_from_file_spec.rb
-- spec/unit/knife/environment_list_spec.rb
-- spec/unit/knife/environment_show_spec.rb
-- spec/unit/knife/index_rebuild_spec.rb
-- spec/unit/knife/knife_help.rb
-- spec/unit/knife/node_bulk_delete_spec.rb
-- spec/unit/knife/node_delete_spec.rb
-- spec/unit/knife/node_edit_spec.rb
-- spec/unit/knife/node_environment_set_spec.rb
-- spec/unit/knife/node_from_file_spec.rb
-- spec/unit/knife/node_list_spec.rb
-- spec/unit/knife/node_run_list_add_spec.rb
-- spec/unit/knife/node_run_list_remove_spec.rb
-- spec/unit/knife/node_run_list_set_spec.rb
-- spec/unit/knife/node_show_spec.rb
-- spec/unit/knife/raw_spec.rb
-- spec/unit/knife/role_bulk_delete_spec.rb
-- spec/unit/knife/role_create_spec.rb
-- spec/unit/knife/role_delete_spec.rb
-- spec/unit/knife/role_edit_spec.rb
-- spec/unit/knife/role_env_run_list_add_spec.rb
-- spec/unit/knife/role_env_run_list_clear_spec.rb
-- spec/unit/knife/role_env_run_list_remove_spec.rb
-- spec/unit/knife/role_env_run_list_replace_spec.rb
-- spec/unit/knife/role_env_run_list_set_spec.rb
-- spec/unit/knife/role_from_file_spec.rb
-- spec/unit/knife/role_list_spec.rb
-- spec/unit/knife/role_run_list_add_spec.rb
-- spec/unit/knife/role_run_list_clear_spec.rb
-- spec/unit/knife/role_run_list_remove_spec.rb
-- spec/unit/knife/role_run_list_replace_spec.rb
-- spec/unit/knife/role_run_list_set_spec.rb
-- spec/unit/knife/role_show_spec.rb
-- spec/unit/knife/ssh_spec.rb
-- spec/unit/knife/ssl_check_spec.rb
-- spec/unit/knife/ssl_fetch_spec.rb
-- spec/unit/knife/status_spec.rb
-- spec/unit/knife/tag_create_spec.rb
-- spec/unit/knife/tag_delete_spec.rb
-- spec/unit/knife/tag_list_spec.rb
-- spec/unit/knife/user_create_spec.rb
-- spec/unit/knife/user_delete_spec.rb
-- spec/unit/knife/user_edit_spec.rb
-- spec/unit/knife/user_list_spec.rb
-- spec/unit/knife/user_reregister_spec.rb
-- spec/unit/knife/user_show_spec.rb
-- spec/unit/knife_spec.rb
-- spec/unit/log_spec.rb
-- spec/unit/lwrp_spec.rb
-- spec/unit/mash_spec.rb
-- spec/unit/mixin/checksum_spec.rb
-- spec/unit/mixin/command_spec.rb
-- spec/unit/mixin/convert_to_class_name_spec.rb
-- spec/unit/mixin/deep_merge_spec.rb
-- spec/unit/mixin/deprecation_spec.rb
-- spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
-- spec/unit/mixin/homebrew_user_spec.rb
-- spec/unit/mixin/params_validate_spec.rb
-- spec/unit/mixin/path_sanity_spec.rb
-- spec/unit/mixin/powershell_type_coercions_spec.rb
-- spec/unit/mixin/securable_spec.rb
-- spec/unit/mixin/shell_out_spec.rb
-- spec/unit/mixin/template_spec.rb
-- spec/unit/mixin/windows_architecture_helper_spec.rb
-- spec/unit/mixin/xml_escape_spec.rb
-- spec/unit/monkey_patches/uri_spec.rb
-- spec/unit/monologger_spec.rb
-- spec/unit/node/attribute_spec.rb
-- spec/unit/node/immutable_collections_spec.rb
-- spec/unit/node_map_spec.rb
-- spec/unit/node_spec.rb
-- spec/unit/org_spec.rb
-- spec/unit/platform/query_helpers_spec.rb
-- spec/unit/platform_spec.rb
-- spec/unit/policy_builder/expand_node_object_spec.rb
-- spec/unit/policy_builder/policyfile_spec.rb
-- spec/unit/policy_builder_spec.rb
-- spec/unit/provider/breakpoint_spec.rb
-- spec/unit/provider/cookbook_file/content_spec.rb
-- spec/unit/provider/cookbook_file_spec.rb
-- spec/unit/provider/cron/unix_spec.rb
-- spec/unit/provider/cron_spec.rb
-- spec/unit/provider/deploy/revision_spec.rb
-- spec/unit/provider/deploy/timestamped_spec.rb
-- spec/unit/provider/deploy_spec.rb
-- spec/unit/provider/directory_spec.rb
-- spec/unit/provider/dsc_resource_spec.rb
-- spec/unit/provider/dsc_script_spec.rb
-- spec/unit/provider/env/windows_spec.rb
-- spec/unit/provider/env_spec.rb
-- spec/unit/provider/erl_call_spec.rb
-- spec/unit/provider/execute_spec.rb
-- spec/unit/provider/file/content_spec.rb
-- spec/unit/provider/file_spec.rb
-- spec/unit/provider/git_spec.rb
-- spec/unit/provider/group/dscl_spec.rb
-- spec/unit/provider/group/gpasswd_spec.rb
-- spec/unit/provider/group/groupadd_spec.rb
-- spec/unit/provider/group/groupmod_spec.rb
-- spec/unit/provider/group/pw_spec.rb
-- spec/unit/provider/group/usermod_spec.rb
-- spec/unit/provider/group/windows_spec.rb
-- spec/unit/provider/group_spec.rb
-- spec/unit/provider/http_request_spec.rb
-- spec/unit/provider/ifconfig/aix_spec.rb
-- spec/unit/provider/ifconfig/debian_spec.rb
-- spec/unit/provider/ifconfig/redhat_spec.rb
-- spec/unit/provider/ifconfig_spec.rb
-- spec/unit/provider/link_spec.rb
-- spec/unit/provider/log_spec.rb
-- spec/unit/provider/mdadm_spec.rb
-- spec/unit/provider/mount/aix_spec.rb
-- spec/unit/provider/mount/mount_spec.rb
-- spec/unit/provider/mount/solaris_spec.rb
-- spec/unit/provider/mount/windows_spec.rb
-- spec/unit/provider/mount_spec.rb
-- spec/unit/provider/ohai_spec.rb
-- spec/unit/provider/package/aix_spec.rb
-- spec/unit/provider/package/apt_spec.rb
-- spec/unit/provider/package/dpkg_spec.rb
-- spec/unit/provider/package/easy_install_spec.rb
-- spec/unit/provider/package/freebsd/pkg_spec.rb
-- spec/unit/provider/package/freebsd/pkgng_spec.rb
-- spec/unit/provider/package/freebsd/port_spec.rb
-- spec/unit/provider/package/homebrew_spec.rb
-- spec/unit/provider/package/ips_spec.rb
-- spec/unit/provider/package/macports_spec.rb
-- spec/unit/provider/package/openbsd_spec.rb
-- spec/unit/provider/package/pacman_spec.rb
-- spec/unit/provider/package/paludis_spec.rb
-- spec/unit/provider/package/portage_spec.rb
-- spec/unit/provider/package/rpm_spec.rb
-- spec/unit/provider/package/rubygems_spec.rb
-- spec/unit/provider/package/smartos_spec.rb
-- spec/unit/provider/package/solaris_spec.rb
-- spec/unit/provider/package/windows/msi_spec.rb
-- spec/unit/provider/package/windows_spec.rb
-- spec/unit/provider/package/yum_spec.rb
-- spec/unit/provider/package/zypper_spec.rb
-- spec/unit/provider/package_spec.rb
-- spec/unit/provider/package_spec.rbe
-- spec/unit/provider/powershell_spec.rb
-- spec/unit/provider/registry_key_spec.rb
-- spec/unit/provider/remote_directory_spec.rb
-- spec/unit/provider/remote_file/cache_control_data_spec.rb
-- spec/unit/provider/remote_file/content_spec.rb
-- spec/unit/provider/remote_file/fetcher_spec.rb
-- spec/unit/provider/remote_file/ftp_spec.rb
-- spec/unit/provider/remote_file/http_spec.rb
-- spec/unit/provider/remote_file/local_file_spec.rb
-- spec/unit/provider/remote_file_spec.rb
-- spec/unit/provider/route_spec.rb
-- spec/unit/provider/ruby_block_spec.rb
-- spec/unit/provider/script_spec.rb
-- spec/unit/provider/service/aix_service_spec.rb
-- spec/unit/provider/service/aixinit_service_spec.rb
-- spec/unit/provider/service/arch_service_spec.rb
-- spec/unit/provider/service/debian_service_spec.rb
-- spec/unit/provider/service/freebsd_service_spec.rb
-- spec/unit/provider/service/gentoo_service_spec.rb
-- spec/unit/provider/service/init_service_spec.rb
-- spec/unit/provider/service/insserv_service_spec.rb
-- spec/unit/provider/service/invokercd_service_spec.rb
-- spec/unit/provider/service/macosx_spec.rb
-- spec/unit/provider/service/openbsd_service_spec.rb
-- spec/unit/provider/service/redhat_spec.rb
-- spec/unit/provider/service/simple_service_spec.rb
-- spec/unit/provider/service/solaris_smf_service_spec.rb
-- spec/unit/provider/service/systemd_service_spec.rb
-- spec/unit/provider/service/upstart_service_spec.rb
-- spec/unit/provider/service/windows_spec.rb
-- spec/unit/provider/service_spec.rb
-- spec/unit/provider/subversion_spec.rb
-- spec/unit/provider/template/content_spec.rb
-- spec/unit/provider/template_spec.rb
-- spec/unit/provider/user/dscl_spec.rb
-- spec/unit/provider/user/pw_spec.rb
-- spec/unit/provider/user/solaris_spec.rb
-- spec/unit/provider/user/useradd_spec.rb
-- spec/unit/provider/user/windows_spec.rb
-- spec/unit/provider/user_spec.rb
-- spec/unit/provider/whyrun_safe_ruby_block_spec.rb
-- spec/unit/provider_resolver_spec.rb
-- spec/unit/provider_spec.rb
-- spec/unit/pure_application_spec.rb
-- spec/unit/recipe_spec.rb
-- spec/unit/registry_helper_spec.rb
-- spec/unit/resource/apt_package_spec.rb
-- spec/unit/resource/bash_spec.rb
-- spec/unit/resource/batch_spec.rb
-- spec/unit/resource/breakpoint_spec.rb
-- spec/unit/resource/chef_gem_spec.rb
-- spec/unit/resource/conditional_action_not_nothing_spec.rb
-- spec/unit/resource/conditional_spec.rb
-- spec/unit/resource/cookbook_file_spec.rb
-- spec/unit/resource/cron_spec.rb
-- spec/unit/resource/csh_spec.rb
-- spec/unit/resource/deploy_revision_spec.rb
-- spec/unit/resource/deploy_spec.rb
-- spec/unit/resource/directory_spec.rb
-- spec/unit/resource/dpkg_package_spec.rb
-- spec/unit/resource/dsc_resource_spec.rb
-- spec/unit/resource/dsc_script_spec.rb
-- spec/unit/resource/easy_install_package_spec.rb
-- spec/unit/resource/env_spec.rb
-- spec/unit/resource/erl_call_spec.rb
-- spec/unit/resource/execute_spec.rb
-- spec/unit/resource/file/verification_spec.rb
-- spec/unit/resource/file_spec.rb
-- spec/unit/resource/freebsd_package_spec.rb
-- spec/unit/resource/gem_package_spec.rb
-- spec/unit/resource/git_spec.rb
-- spec/unit/resource/group_spec.rb
-- spec/unit/resource/homebrew_package_spec.rb
-- spec/unit/resource/http_request_spec.rb
-- spec/unit/resource/ifconfig_spec.rb
-- spec/unit/resource/ips_package_spec.rb
-- spec/unit/resource/link_spec.rb
-- spec/unit/resource/log_spec.rb
-- spec/unit/resource/macports_package_spec.rb
-- spec/unit/resource/mdadm_spec.rb
-- spec/unit/resource/mount_spec.rb
-- spec/unit/resource/ohai_spec.rb
-- spec/unit/resource/openbsd_package_spec.rb
-- spec/unit/resource/package_spec.rb
-- spec/unit/resource/pacman_package_spec.rb
-- spec/unit/resource/perl_spec.rb
-- spec/unit/resource/portage_package_spec.rb
-- spec/unit/resource/powershell_spec.rb
-- spec/unit/resource/python_spec.rb
-- spec/unit/resource/registry_key_spec.rb
-- spec/unit/resource/remote_directory_spec.rb
-- spec/unit/resource/remote_file_spec.rb
-- spec/unit/resource/resource_notification_spec.rb
-- spec/unit/resource/route_spec.rb
-- spec/unit/resource/rpm_package_spec.rb
-- spec/unit/resource/ruby_block_spec.rb
-- spec/unit/resource/ruby_spec.rb
-- spec/unit/resource/scm_spec.rb
-- spec/unit/resource/script_spec.rb
-- spec/unit/resource/service_spec.rb
-- spec/unit/resource/smartos_package_spec.rb
-- spec/unit/resource/solaris_package_spec.rb
-- spec/unit/resource/subversion_spec.rb
-- spec/unit/resource/template_spec.rb
-- spec/unit/resource/timestamped_deploy_spec.rb
-- spec/unit/resource/user_spec.rb
-- spec/unit/resource/windows_package_spec.rb
-- spec/unit/resource/windows_service_spec.rb
-- spec/unit/resource/yum_package_spec.rb
-- spec/unit/resource_builder_spec.rb
-- spec/unit/resource_collection/resource_list_spec.rb
-- spec/unit/resource_collection/resource_set_spec.rb
-- spec/unit/resource_collection/stepable_iterator_spec.rb
-- spec/unit/resource_collection_spec.rb
-- spec/unit/resource_definition_spec.rb
-- spec/unit/resource_reporter_spec.rb
-- spec/unit/resource_spec.rb
-- spec/unit/rest/auth_credentials_spec.rb
-- spec/unit/rest_spec.rb
-- spec/unit/role_spec.rb
-- spec/unit/run_context/cookbook_compiler_spec.rb
-- spec/unit/run_context_spec.rb
-- spec/unit/run_list/run_list_expansion_spec.rb
-- spec/unit/run_list/run_list_item_spec.rb
-- spec/unit/run_list/versioned_recipe_list_spec.rb
-- spec/unit/run_list_spec.rb
-- spec/unit/run_lock_spec.rb
-- spec/unit/run_status_spec.rb
-- spec/unit/runner_spec.rb
-- spec/unit/scan_access_control_spec.rb
-- spec/unit/search/query_spec.rb
-- spec/unit/shell/model_wrapper_spec.rb
-- spec/unit/shell/shell_ext_spec.rb
-- spec/unit/shell/shell_session_spec.rb
-- spec/unit/shell_out_spec.rb
-- spec/unit/shell_spec.rb
-- spec/unit/user_spec.rb
-- spec/unit/util/backup_spec.rb
-- spec/unit/util/diff_spec.rb
-- spec/unit/util/dsc/configuration_generator_spec.rb
-- spec/unit/util/dsc/lcm_output_parser_spec.rb
-- spec/unit/util/dsc/local_configuration_manager_spec.rb
-- spec/unit/util/dsc/resource_store.rb
-- spec/unit/util/editor_spec.rb
-- spec/unit/util/file_edit_spec.rb
-- spec/unit/util/path_helper_spec.rb
-- spec/unit/util/powershell/cmdlet_spec.rb
-- spec/unit/util/powershell/ps_credential_spec.rb
-- spec/unit/util/selinux_spec.rb
-- spec/unit/util/threaded_job_queue_spec.rb
-- spec/unit/version/platform_spec.rb
-- spec/unit/version_class_spec.rb
-- spec/unit/version_constraint/platform_spec.rb
-- spec/unit/version_constraint_spec.rb
-- spec/unit/windows_service_spec.rb
-- spec/unit/workstation_config_loader_spec.rb
-- tasks/rspec.rb
-homepage: http://www.getchef.com
-licenses:
-- Apache-2.0
-metadata: {}
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - ">="
-    - !ruby/object:Gem::Version
-      version: 2.0.0
-required_rubygems_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - ">="
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: 
-rubygems_version: 2.4.4
-signing_key: 
-specification_version: 4
-summary: A systems integration framework, built to bring the benefits of configuration
-  management to your entire infrastructure.
-test_files: []
diff --git a/omnibus/.gitignore b/omnibus/.gitignore
new file mode 100644
index 0000000..0425859
--- /dev/null
+++ b/omnibus/.gitignore
@@ -0,0 +1,10 @@
+vendor/bundle
+pkg/*
+.kitchen.local.yml
+bin/*
+files/chef-server-cookbooks/cache/
+files/msi/ChefClient-Config.wxi
+cookbooks
+vendor/cookbooks
+build_timestamp
+ldd.out
diff --git a/omnibus/.kitchen.local.yml.vmware.example b/omnibus/.kitchen.local.yml.vmware.example
new file mode 100644
index 0000000..69f001e
--- /dev/null
+++ b/omnibus/.kitchen.local.yml.vmware.example
@@ -0,0 +1,6 @@
+driver:
+  name: vagrant
+  provider: vmware_fusion
+  customize:
+    numvcpus: 4
+    memsize: 4096
diff --git a/omnibus/.kitchen.yml b/omnibus/.kitchen.yml
new file mode 100644
index 0000000..fa3e8c8
--- /dev/null
+++ b/omnibus/.kitchen.yml
@@ -0,0 +1,121 @@
+#
+# NOTE: this runs the omnibus cookbook, but does not actually run Omnibus. Use
+# 'kichen converge' to setup the virtual machine and then `kitchen login` to
+# SSH into the machine and run Omnibus.
+#
+
+driver:
+  name: vagrant
+  forward_agent: yes
+  customize:
+    cpus: 4
+    memory: 4096
+  synced_folders:
+    - ['..', '/home/vagrant/chef']
+    - ['../../omnibus', '/home/vagrant/omnibus']
+    - ['../../omnibus-software', '/home/vagrant/omnibus-software']
+
+provisioner:
+  name: chef_zero
+  # Always install the latest version of Chef.
+  # This is not the version of chef that we're building - this is the version
+  # of chef that omnibus needs to build chef/chef.
+  require_chef_omnibus: true
+
+platforms:
+  - name: centos-5.10
+    run_list: yum-epel::default
+  - name: centos-6.5
+    run_list: yum-epel::default
+  - name: centos-7.0
+    run_list: yum-epel::default
+  - name: debian-7.2.0
+    run_list: apt::default
+  - name: debian-7.4
+    run_list: apt::default
+  - name: debian-6.0.8
+    run_list: apt::default
+  - name: freebsd-9.2
+    run_list:
+      - freebsd::portsnap
+      - freebsd::pkgng
+  - name: freebsd-10.0
+    run_list: freebsd::portsnap
+  - name: ubuntu-10.04
+    run_list: apt::default
+  - name: ubuntu-12.04
+    run_list: apt::default
+  - name: ubuntu-12.10
+    run_list: apt::default
+  - name: ubuntu-13.04
+    run_list: apt::default
+  - name: ubuntu-13.10
+    run_list: apt::default
+  - name: ubuntu-14.04
+    run_list: apt::default
+  # The following (private) boxes are shared via Atlas and are only
+  # available to users working for Chef. Sorry, it's about software licensing.
+  # 
+  # Chef-internal users, you will need to:  
+  # 1.  Create an Atlas account:  https://atlas.hashicorp.com/
+  # 2.  Ping the Release Services room with your Atlas account name
+  #     to be added to the relevant team in Atlas,
+  # 3.  Do `vagrant login` with your Atlas creds so that you can download
+  #     the private boxes.   
+  #
+  # The Mac OS X boxes are VMware only also. You can enable VMware Fusion
+  # as the default provider by copying `.kitchen.local.yml.vmware.example`
+  # over to `.kitchen.local.yml`.
+  #
+  - name: macosx-10.8
+    driver:
+      box: chef/macosx-10.8 # private
+  - name: macosx-10.9
+    driver:
+      box: chef/macosx-10.9 # private
+  - name: macosx-10.10
+    driver:
+      box: chef/macosx-10.10 # private
+  - name: windows-7-professional
+    driver:
+      box: chef/windows-7-professional # private
+  - name: windows-8.1-professional
+    driver:
+      box: chef/windows-8.1-professional # private
+  - name: windows-2008r2-standard
+    driver:
+      box: chef/windows-server-2008r2-standard # private
+  - name: windows-2012r2-standard
+    driver:
+      box: chef/windows-server-2012r2-standard # private
+
+attribute_defaults: &attribute_defaults
+  build_user:          vagrant
+  build_user_group:    vagrant
+  build_user_password: vagrant
+
+suites:
+  - name: angrychef
+    attributes:
+      omnibus:
+        <<: *attribute_defaults
+        install_dir: /opt/angrychef
+    run_list:
+      - omnibus::default
+  - name: chef-fips
+    attributes:
+      omnibus:
+        <<: *attribute_defaults
+        install_dir: /opt/chef-fips
+    run_list:
+      - omnibus::default
+  - name: chef
+    provisioner:
+      chef_omnibus_install_options: -P angrychef
+      chef_omnibus_root: /opt/angrychef
+    attributes:
+      omnibus:
+        <<: *attribute_defaults
+        install_dir: /opt/chef
+    run_list:
+      - omnibus::default
diff --git a/omnibus/Berksfile b/omnibus/Berksfile
new file mode 100644
index 0000000..614c6da
--- /dev/null
+++ b/omnibus/Berksfile
@@ -0,0 +1,12 @@
+source "https://supermarket.chef.io"
+
+cookbook "omnibus"
+
+# Uncomment to use the latest version of the Omnibus cookbook from GitHub
+# cookbook 'omnibus', github: 'opscode-cookbooks/omnibus'
+
+group :integration do
+  cookbook "apt",      "~> 2.3"
+  cookbook "freebsd",  "~> 0.1"
+  cookbook "yum-epel", "~> 0.3"
+end
diff --git a/omnibus/Gemfile b/omnibus/Gemfile
new file mode 100644
index 0000000..33c3ef3
--- /dev/null
+++ b/omnibus/Gemfile
@@ -0,0 +1,21 @@
+source "https://rubygems.org"
+
+gem "omnibus", github: "chef/omnibus"
+gem "omnibus-software", github: "chef/omnibus-software"
+
+# This development group is installed by default when you run `bundle install`,
+# but if you are using Omnibus in a CI-based infrastructure, you do not need
+# the Test Kitchen-based build lab. You can skip these unnecessary dependencies
+# by running `bundle install --without development` to speed up build times.
+group :development do
+  # Use Berkshelf for resolving cookbook dependencies
+  gem "berkshelf", "~> 3.0"
+
+  # Use Test Kitchen with Vagrant for converging the build environment
+  gem "test-kitchen",    "~> 1.5.0"
+  gem "kitchen-vagrant", "~> 0.19.0"
+  gem "winrm-transport", "~> 1.0"
+  gem "pry"
+  gem "pry-byebug"
+  gem "pry-stack_explorer"
+end
diff --git a/omnibus/README.md b/omnibus/README.md
new file mode 100644
index 0000000..24aa0e6
--- /dev/null
+++ b/omnibus/README.md
@@ -0,0 +1,144 @@
+Client Tools Omnibus project
+============================
+This project creates full-stack platform-specific packages for the following projects:
+
+* AngryChef
+* Chef
+* Chef with FIPS enabled
+
+Installation
+------------
+You must have a sane Ruby 1.9+ environment with Bundler installed. Ensure all
+the required gems are installed:
+
+```shell
+$ bundle install --without development
+```
+
+Usage
+-----
+### Build
+
+You create a platform-specific package using the `build project` command:
+
+```shell
+$ bundle exec omnibus build <PROJECT>
+```
+
+The platform/architecture type of the package created will match the platform
+where the `build project` command is invoked. For example, running this command
+on a MacBook Pro will generate a Mac OS X package. After the build completes
+packages will be available in the `pkg/` folder.
+
+### Clean
+
+You can clean up all temporary files generated during the build process with
+the `clean` command:
+
+```shell
+$ bundle exec omnibus clean <PROJECT>
+```
+
+Adding the `--purge` purge option removes __ALL__ files generated during the
+build including the project install directory (`/opt/chef`) and
+the package cache directory (`/var/cache/omnibus/pkg`):
+
+```shell
+$ bundle exec omnibus clean <PROJECT> --purge
+```
+
+### Publish
+
+Omnibus has a built-in mechanism for releasing to a variety of "backends", such
+as Amazon S3 and Artifactory. You must set the proper credentials in your `omnibus.rb`
+config file or specify them via the command line.
+
+```shell
+$ bundle exec omnibus publish path/to/*.deb --backend s3
+```
+
+### Help
+
+Full help for the Omnibus command line interface can be accessed with the
+`help` command:
+
+```shell
+$ bundle exec omnibus help
+```
+
+Kitchen-based Build Environment
+-------------------------------
+Every Omnibus project ships will a project-specific
+[Berksfile](http://berkshelf.com/) that will allow you to build your omnibus projects on all of the projects listed
+in the `.kitchen.yml`. You can add/remove additional platforms as needed by
+changing the list found in the `.kitchen.yml` `platforms` YAML stanza.
+
+This build environment is designed to get you up-and-running quickly. However,
+there is nothing that restricts you to building on other platforms. Simply use
+the [omnibus cookbook](https://github.com/opscode-cookbooks/omnibus) to setup
+your desired platform and execute the build steps listed above.
+
+The default build environment requires Test Kitchen and VirtualBox for local
+development. Test Kitchen also exposes the ability to provision instances using
+various cloud providers like AWS, DigitalOcean, or OpenStack. For more
+information, please see the [Test Kitchen documentation](http://kitchen.ci).
+
+Once you have tweaked your `.kitchen.yml` (or `.kitchen.local.yml`) to your
+liking, you can bring up an individual build environment using the `kitchen`
+command.
+
+```shell
+$ bundle exec kitchen converge <PROJECT>-ubuntu-1204
+```
+
+Then login to the instance and build the project as described in the Usage
+section:
+
+```shell
+$ bundle exec kitchen login <PROJECT>-ubuntu-1204
+[vagrant at ubuntu...] $ cd chef/omnibus
+[vagrant at ubuntu...] $ bundle install --without development # Don't install dev tools!
+[vagrant at ubuntu...] $ ...
+[vagrant at ubuntu...] $ bundle exec omnibus build <PROJECT> -l internal
+```
+
+You can also login to Windows instances but will have to manually call the
+`load-omnibus-toolchain.bat` script which initializes the build environment.
+Please note the mounted code directory is also at `C:\home\vagrant\chef\omnibus`
+as opposed to `C:\Users\vagrant\chef\omnibus`.
+
+```shell
+$ bundle exec kitchen login <PROJECT>-windows-81-professional
+Last login: Sat Sep 13 10:19:04 2014 from 172.16.27.1
+Microsoft Windows [Version 6.3.9600]
+(c) 2013 Microsoft Corporation. All rights reserved.
+
+C:\Users\vagrant>load-omnibus-toolchain.bat
+
+C:\Users\vagrant>cd C:\home\vagrant\chef\omnibus
+
+C:\home\vagrant\chef\omnibus>bundle install --without development
+
+C:\home\vagrant\chef\omnibus>bundle exec omnibus build <PROJECT> -l internal
+```
+
+For a complete list of all commands and platforms, run `kitchen list` or
+`kitchen help`.
+
+License
+-------
+```text
+Copyright 2012-2016, Chef Software, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
diff --git a/omnibus/config/projects/angrychef.rb b/omnibus/config/projects/angrychef.rb
new file mode 100644
index 0000000..48902e6
--- /dev/null
+++ b/omnibus/config/projects/angrychef.rb
@@ -0,0 +1,42 @@
+#
+# Copyright 2012-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This is a clone of the Chef project that we can install on the Chef build and
+# test machines. As such this project definition is just a thin wrapper around
+# `config/project/chef.rb`.
+#
+current_file = __FILE__
+chef_project_contents = IO.read(File.expand_path("../chef.rb", __FILE__))
+self.instance_eval chef_project_contents
+
+name "angrychef"
+friendly_name "Angry Chef Client"
+
+if windows?
+  # NOTE: Ruby DevKit fundamentally CANNOT be installed into "Program Files"
+  #       Native gems will use gcc which will barf on files with spaces,
+  #       which is only fixable if everyone in the world fixes their Makefiles
+  install_dir "#{default_root}/opscode/#{name}"
+  package_name "angrychef"
+else
+  install_dir "#{default_root}/#{name}"
+end
+
+resources_path "#{resources_path}/../chef"
+
+msi_upgrade_code = "D7FDDC1A-7668-404E-AD2F-61F875632A9C"
+project_location_dir = "angrychef"
diff --git a/omnibus/config/projects/chef-fips.rb b/omnibus/config/projects/chef-fips.rb
new file mode 100644
index 0000000..c91dbc4
--- /dev/null
+++ b/omnibus/config/projects/chef-fips.rb
@@ -0,0 +1,60 @@
+#
+# Copyright 2012-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This is the chef client build with FIPS mode enabled.
+#
+current_file = __FILE__
+chef_project_contents = IO.read(File.expand_path("../chef.rb", current_file))
+self.instance_eval chef_project_contents
+
+name "chef-fips"
+friendly_name "Chef Client with FIPS OpenSSL"
+
+if windows?
+  # NOTE: Ruby DevKit fundamentally CANNOT be installed into "Program Files"
+  #       Native gems will use gcc which will barf on files with spaces,
+  #       which is only fixable if everyone in the world fixes their Makefiles
+  install_dir "#{default_root}/opscode/#{name}"
+  package_name "chef-fips"
+else
+  install_dir "#{default_root}/#{name}"
+end
+
+# Even if chef marches ahead, make sure that we stay pinned to 1.10.6
+# bundler 1.11 introduces some new features that require zlib. The zlib1.dll
+# base address is generated by gcc to overlap that of libeay.dll. This will
+# force windows into relocating libeay, freaking out the FIPS integrity
+# verifier. Lol security indeed.
+# Delete this once all dlls we generate are appropriately relocated.
+override :bundler, version: "1.10.6"
+
+override :ruby, version: "2.1.7"
+override :"rb-readline", version: "v0.5.3"
+
+# Global FIPS override flag.
+override :fips, enabled: true
+
+override :chef, version: "local_source"
+override :ohai, version: "master"
+
+dependency "rb-readline"
+
+msi_upgrade_code = "819F5DB3-B818-4358-BB2B-54B8171D0A26"
+project_location_dir = "chef-fips"
+
+# Use chef's scripts for everything.
+resources_path "#{resources_path}/../chef"
diff --git a/omnibus/config/projects/chef.rb b/omnibus/config/projects/chef.rb
new file mode 100644
index 0000000..c85a8ac
--- /dev/null
+++ b/omnibus/config/projects/chef.rb
@@ -0,0 +1,84 @@
+#
+# Copyright 2012-2016, Chef Software, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+name "chef"
+friendly_name "Chef Client"
+maintainer "Chef Software, Inc. <maintainers at chef.io>"
+homepage "https://www.chef.io"
+
+build_iteration 1
+current_file ||= __FILE__
+version_file = File.expand_path("../../../../VERSION", current_file)
+build_version IO.read(version_file).strip
+
+if windows?
+  # NOTE: Ruby DevKit fundamentally CANNOT be installed into "Program Files"
+  #       Native gems will use gcc which will barf on files with spaces,
+  #       which is only fixable if everyone in the world fixes their Makefiles
+  install_dir  "#{default_root}/opscode/#{name}"
+  package_name "chef-client"
+else
+  install_dir "#{default_root}/#{name}"
+end
+
+if windows?
+  override :'ruby-windows', version: "2.0.0-p645"
+  # Leave dev-kit pinned to 4.5 because 4.7 is 20MB larger and we don't want
+  # to unnecessarily make the client any fatter.
+  if windows_arch_i386?
+    override :'ruby-windows-devkit', version: "4.5.2-20111229-1559"
+  end
+else
+  override :ruby, version: "2.1.6"
+end
+
+override :bundler,      version: "1.11.2"
+override :rubygems,     version: "2.5.2"
+
+# Chef Release version pinning
+override :chef, version: "local_source"
+override :ohai, version: "v8.10.0"
+
+dependency "preparation"
+dependency "chef"
+dependency "pry"
+dependency "nokogiri"
+dependency "shebang-cleanup"
+dependency "version-manifest"
+dependency "openssl-customization"
+
+package :rpm do
+  signing_passphrase ENV["OMNIBUS_RPM_SIGNING_PASSPHRASE"]
+end
+
+proj_to_work_around_cleanroom = self
+package :pkg do
+  identifier "com.getchef.pkg.#{proj_to_work_around_cleanroom.name}"
+  signing_identity "Developer ID Installer: Chef Software, Inc. (EU3VF8YLX2)"
+end
+compress :dmg
+
+msi_upgrade_code = "D607A85C-BDFA-4F08-83ED-2ECB4DCD6BC5"
+project_location_dir = name
+package :msi do
+  fast_msi true
+  upgrade_code msi_upgrade_code
+  wix_candle_extension "WixUtilExtension"
+  wix_light_extension "WixUtilExtension"
+  signing_identity "F74E1A68005E8A9C465C3D2FF7B41F3988F0EA09", machine_store: true
+  parameters ChefLogDllPath: windows_safe_path(gem_path("chef-[0-9]*-mingw32/ext/win32-eventlog/chef-log.dll")),
+             ProjectLocationDir: project_location_dir
+end
diff --git a/omnibus/files/mapfiles/solaris b/omnibus/files/mapfiles/solaris
new file mode 100644
index 0000000..c0ca5c1
--- /dev/null
+++ b/omnibus/files/mapfiles/solaris
@@ -0,0 +1,18 @@
+$mapfile_version 2
+DEPEND_VERSIONS libnsl.so {
+  ALLOW = SUNW_1.1;
+  ALLOW = SUNWprivate_1.1;
+};
+DEPEND_VERSIONS libsocket.so {
+  ALLOW = SUNW_1.4;
+  ALLOW = SUNWprivate_1.1;
+};
+DEPEND_VERSIONS libdl.so {
+  ALLOW = SUNW_1.4;
+  ALLOW = SUNWprivate_1.1;
+};
+DEPEND_VERSIONS libc.so {
+  ALLOW = SUNW_1.22.1;
+  ALLOW = SUNW_1.4;
+  ALLOW = SUNWprivate_1.1;
+};
diff --git a/omnibus/files/openssl-customization/windows/ssl_env_hack.rb b/omnibus/files/openssl-customization/windows/ssl_env_hack.rb
new file mode 100644
index 0000000..26b68e4
--- /dev/null
+++ b/omnibus/files/openssl-customization/windows/ssl_env_hack.rb
@@ -0,0 +1,34 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This script sets the SSL_CERT_FILE environment variable to the CA cert bundle
+# that ships with omnibus packages of Chef and Chef DK. If this environment
+# variable is already configured, this script is a no-op.
+#
+# This is required to make Chef tools use https URLs out of the box.
+
+unless ENV.key?("SSL_CERT_FILE")
+  base_dirs = File.dirname(__FILE__).split(File::SEPARATOR)
+
+  (base_dirs.length - 1).downto(0) do |i|
+    candidate_ca_bundle = File.join(base_dirs[0..i] + [ "ssl/certs/cacert.pem" ])
+    if File.exist?(candidate_ca_bundle)
+      ENV["SSL_CERT_FILE"] = candidate_ca_bundle
+      break
+    end
+  end
+end
diff --git a/omnibus/omnibus.rb b/omnibus/omnibus.rb
new file mode 100644
index 0000000..663235d
--- /dev/null
+++ b/omnibus/omnibus.rb
@@ -0,0 +1,54 @@
+#
+# This file is used to configure the Omnibus projects in this repo. It contains
+# some minimal configuration examples for working with Omnibus. For a full list
+# of configurable options, please see the documentation for +omnibus/config.rb+.
+#
+
+# Build internally
+# ------------------------------
+# By default, Omnibus uses system folders (like +/var+ and +/opt+) to build and
+# cache components. If you would to build everything internally, you can
+# uncomment the following options. This will prevent the need for root
+# permissions in most cases.
+#
+# Uncomment this line to change the default base directory to "local"
+# -------------------------------------------------------------------
+# base_dir './local'
+#
+# Alternatively you can tune the individual values
+# ------------------------------------------------
+# cache_dir     './local/omnibus/cache'
+# git_cache_dir './local/omnibus/cache/git_cache'
+# source_dir    './local/omnibus/src'
+# build_dir     './local/omnibus/build'
+# package_dir   './local/omnibus/pkg'
+# package_tmp   './local/omnibus/pkg-tmp'
+
+# Windows architecture defaults - set to x86 unless otherwise specified.
+# ------------------------------
+windows_arch   %w{x86 x64}.include?((ENV["OMNIBUS_WINDOWS_ARCH"] || "").downcase) ?
+                ENV["OMNIBUS_WINDOWS_ARCH"].downcase.to_sym : :x86
+
+# Disable git caching
+# ------------------------------
+# use_git_caching false
+
+# Enable S3 asset caching
+# ------------------------------
+use_s3_caching true
+s3_access_key  ENV["AWS_ACCESS_KEY_ID"]
+s3_secret_key  ENV["AWS_SECRET_ACCESS_KEY"]
+s3_bucket      "opscode-omnibus-cache"
+
+build_retries 3
+fetcher_retries 3
+fetcher_read_timeout 120
+
+# We limit this to 10 workers to eliminate transient timing issues in the
+# way Ruby (and other components) compiles on some more esoteric *nixes.
+workers 10
+
+# Load additional software
+# ------------------------------
+# software_gems ['omnibus-software', 'my-company-software']
+# local_software_dirs ['/path/to/local/software']
diff --git a/omnibus/package-scripts/angrychef/postinst b/omnibus/package-scripts/angrychef/postinst
new file mode 100755
index 0000000..a173efe
--- /dev/null
+++ b/omnibus/package-scripts/angrychef/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/angrychef
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+  echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+  exit 1
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+    mkdir -p "$PREFIX/bin"
+else
+    PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+    case "$opt" in
+      v)  validation_key="${OPTARG}";;
+      o)  organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+      u)  chef_url="${OPTARG}";;
+      \?)    # unknown flag
+          echo >&2 ${USAGE}
+    exit 1;;
+    esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+  mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+  (
+  cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+  ) > ${CONFIG_DIR}/client.rb
+  if [ "" != "$chef_url" ]; then
+    echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+  fi
+  if [ "" != "$organization" ]; then
+    echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+  fi
+  chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+  cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+  chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/angrychef/postrm b/omnibus/package-scripts/angrychef/postrm
new file mode 100755
index 0000000..2476880
--- /dev/null
+++ b/omnibus/package-scripts/angrychef/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+else
+    PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+  binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+  for binary in $binaries; do
+    rm -f $PREFIX/bin/$binary
+  done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+  # not a redhat-ish RPM-based system
+  cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+  # RPM-based system and we're deinstalling rather than upgrading
+  cleanup_symlinks
+fi
diff --git a/omnibus/package-scripts/chef-fips/postinst b/omnibus/package-scripts/chef-fips/postinst
new file mode 100755
index 0000000..8aa6f19
--- /dev/null
+++ b/omnibus/package-scripts/chef-fips/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/chef-fips
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+  echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+  exit 1
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+    mkdir -p "$PREFIX/bin"
+else
+    PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+    case "$opt" in
+      v)  validation_key="${OPTARG}";;
+      o)  organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+      u)  chef_url="${OPTARG}";;
+      \?)    # unknown flag
+          echo >&2 ${USAGE}
+    exit 1;;
+    esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+  mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+  (
+  cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+  ) > ${CONFIG_DIR}/client.rb
+  if [ "" != "$chef_url" ]; then
+    echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+  fi
+  if [ "" != "$organization" ]; then
+    echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+  fi
+  chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+  cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+  chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/chef-fips/postrm b/omnibus/package-scripts/chef-fips/postrm
new file mode 100755
index 0000000..2476880
--- /dev/null
+++ b/omnibus/package-scripts/chef-fips/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+else
+    PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+  binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+  for binary in $binaries; do
+    rm -f $PREFIX/bin/$binary
+  done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+  # not a redhat-ish RPM-based system
+  cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+  # RPM-based system and we're deinstalling rather than upgrading
+  cleanup_symlinks
+fi
diff --git a/omnibus/package-scripts/chef/postinst b/omnibus/package-scripts/chef/postinst
new file mode 100755
index 0000000..4589324
--- /dev/null
+++ b/omnibus/package-scripts/chef/postinst
@@ -0,0 +1,111 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+#
+# Install a full Opscode Client
+#
+
+PROGNAME=`basename $0`
+INSTALLER_DIR=/opt/chef
+CONFIG_DIR=/etc/chef
+USAGE="usage: $0 [-v validation_key] ([-o organization] || [-u url])"
+
+error_exit()
+{
+  echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
+  exit 1
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+is_smartos()
+{
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+    mkdir -p "$PREFIX/bin"
+else
+    PREFIX="/usr"
+fi
+
+validation_key=
+organization=
+chef_url=
+
+while getopts o:u:v: opt
+do
+    case "$opt" in
+      v)  validation_key="${OPTARG}";;
+      o)  organization="${OPTARG}"; chef_url="https://api.opscode.com/organizations/${OPTARG}";;
+      u)  chef_url="${OPTARG}";;
+      \?)    # unknown flag
+          echo >&2 ${USAGE}
+    exit 1;;
+    esac
+done
+shift `expr ${OPTIND} - 1`
+
+if [ "" != "$chef_url" ]; then
+  mkdir -p ${CONFIG_DIR} || error_exit "Cannot create ${CONFIG_DIR}!"
+  (
+  cat <<'EOP'
+log_level :info
+log_location STDOUT
+EOP
+  ) > ${CONFIG_DIR}/client.rb
+  if [ "" != "$chef_url" ]; then
+    echo "chef_server_url '${chef_url}'" >> ${CONFIG_DIR}/client.rb
+  fi
+  if [ "" != "$organization" ]; then
+    echo "validation_client_name '${organization}-validator'" >> ${CONFIG_DIR}/client.rb
+  fi
+  chmod 644 ${CONFIG_DIR}/client.rb
+fi
+
+if [ "" != "$validation_key" ]; then
+  cp ${validation_key} ${CONFIG_DIR}/validation.pem || error_exit "Cannot copy the validation key!"
+  chmod 600 ${CONFIG_DIR}/validation.pem
+fi
+
+# rm -f before ln -sf is required for solaris 9
+rm -f $PREFIX/bin/chef-client
+rm -f $PREFIX/bin/chef-solo
+rm -f $PREFIX/bin/chef-apply
+rm -f $PREFIX/bin/chef-shell
+rm -f $PREFIX/bin/knife
+rm -f $PREFIX/bin/ohai
+
+ln -sf $INSTALLER_DIR/bin/chef-solo $PREFIX/bin || error_exit "Cannot link chef-solo to $PREFIX/bin"
+if [ -f "$INSTALLER_DIR/bin/chef-apply" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-apply $PREFIX/bin || error_exit "Cannot link chef-apply to $PREFIX/bin"
+fi
+if [ -f "$INSTALLER_DIR/bin/chef-shell" ]; then
+  ln -sf $INSTALLER_DIR/bin/chef-shell $PREFIX/bin || error_exit "Cannot link chef-shell to $PREFIX/bin"
+fi
+ln -sf $INSTALLER_DIR/bin/knife $PREFIX/bin || error_exit "Cannot link knife to $PREFIX/bin"
+ln -sf $INSTALLER_DIR/bin/ohai $PREFIX/bin || error_exit "Cannot link ohai to $PREFIX/bin"
+
+# We test for the presence of /usr/bin/chef-client to know if this script succeeds, so this
+# must appear as the last real action in the script
+ln -sf $INSTALLER_DIR/bin/chef-client $PREFIX/bin || error_exit "Cannot link chef-client to $PREFIX/bin"
+
+# Ensure all files/directories in $INSTALLER_DIR are owned by root. This
+# has been fixed on new installs but upgrades from old installs need to
+# be manually fixed.
+chown -Rh 0:0 $INSTALLER_DIR
+
+echo "Thank you for installing Chef!"
+
+exit 0
diff --git a/omnibus/package-scripts/chef/postrm b/omnibus/package-scripts/chef/postrm
new file mode 100755
index 0000000..2476880
--- /dev/null
+++ b/omnibus/package-scripts/chef/postrm
@@ -0,0 +1,42 @@
+#!/bin/sh
+# WARNING: REQUIRES /bin/sh
+#
+# - must run on /bin/sh on solaris 9
+# - must run on /bin/sh on AIX 6.x
+# - if you think you are a bash wizard, you probably do not understand
+#   this programming language.  do not touch.
+# - if you are under 40, get peer review from your elders.
+
+is_smartos() {
+  uname -v | grep "^joyent" 2>&1 >/dev/null
+}
+
+is_darwin()
+{
+  uname -v | grep "^Darwin" 2>&1 >/dev/null
+}
+
+if is_smartos; then
+    PREFIX="/opt/local"
+elif is_darwin; then
+    PREFIX="/usr/local"
+else
+    PREFIX="/usr"
+fi
+
+cleanup_symlinks() {
+  binaries="chef-client chef-solo chef-apply chef-shell knife ohai"
+  for binary in $binaries; do
+    rm -f $PREFIX/bin/$binary
+  done
+}
+
+# Clean up binary symlinks if they exist
+# see: http://tickets.opscode.com/browse/CHEF-3022
+if [ ! -f /etc/redhat-release -a ! -f /etc/fedora-release -a ! -f /etc/system-release -a ! -f /etc/SuSE-release ]; then
+  # not a redhat-ish RPM-based system
+  cleanup_symlinks
+elif [ "x$1" = "x0" ]; then
+  # RPM-based system and we're deinstalling rather than upgrading
+  cleanup_symlinks
+fi
diff --git a/omnibus/resources/chef/dmg/background.png b/omnibus/resources/chef/dmg/background.png
new file mode 100644
index 0000000..82c605a
Binary files /dev/null and b/omnibus/resources/chef/dmg/background.png differ
diff --git a/omnibus/resources/chef/dmg/icon.png b/omnibus/resources/chef/dmg/icon.png
new file mode 100644
index 0000000..2195d7c
Binary files /dev/null and b/omnibus/resources/chef/dmg/icon.png differ
diff --git a/omnibus/resources/chef/msi/assets/LICENSE.rtf b/omnibus/resources/chef/msi/assets/LICENSE.rtf
new file mode 100644
index 0000000..b18e6f5
--- /dev/null
+++ b/omnibus/resources/chef/msi/assets/LICENSE.rtf
@@ -0,0 +1,197 @@
+{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Courier New;}}
+
+{\*\generator Msftedit 5.41.21.2500;}\viewkind4\uc1\pard\qc\lang1033\f0\fs20 Apache License\par
+
+Version 2.0, January 2004\par
+
+http://www.apache.org/licenses/\par
+
+\pard\par
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
+
+\par
+
+1. Definitions.\par
+
+\par
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par
+
+\par
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par
+
+\par
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\par
+
+\par
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par
+
+\par
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation, source, and configuration files.\par
+
+\par
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\par
+
+\par
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\par
+
+\par
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\par
+
+\par
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or it [...]
+
+\par
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\par
+
+\par
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\par
+
+\par
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license plies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combinat [...]
+
+\par
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\par
+
+\par
+
+      (a) You must give any other recipients of the Work or\par
+
+          Derivative Works a copy of this License; and\par
+
+\par
+
+      (b) You must cause any modified files to carry prominent notices\par
+
+          stating that You changed the files; and\par
+
+\par
+
+      (c) You must retain, in the Source form of any Derivative Works\par
+
+          that You distribute, all copyright, patent, trademark, and\par
+
+          attribution notices from the Source form of the Work,\par
+
+          excluding those notices that do not pertain to any part of\par
+
+          the Derivative Works; and\par
+
+\par
+
+      (d) If the Work includes a "NOTICE" text file as part of its\par
+
+          distribution, then any Derivative Works that You distribute\par
+
+          must include a readable copy of the attribution notices\par
+
+          contained within such NOTICE file, excluding those notices\par
+
+          that do not pertain to any part of the Derivative Works, in\par
+
+          at least one of the following places: within a NOTICE text\par
+
+          file distributed as part of the Derivative Works; within the\par
+
+          Source form or documentation, if provided along with the\par
+
+          Derivative Works; or, within a display generated by the\par
+
+          Derivative Works, if and wherever such third-party notices\par
+
+          normally appear. The contents of the NOTICE file are for\par
+
+          informational purposes only and do not modify the License.\par
+
+          You may add Your own attribution notices within Derivative\par
+
+          Works that You distribute, alongside or as an addendum to the\par
+
+          NOTICE text from the Work, provided that such additional\par
+
+          attribution notices cannot be construed as modifying the\par
+
+          License.\par
+
+\par
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\par
+
+\par
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\par
+
+\par
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\par
+
+\par
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the [...]
+
+\par
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limit [...]
+
+\par
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor h [...]
+
+\par
+
+END OF TERMS AND CONDITIONS\par
+
+\par
+
+APPENDIX: How to apply the Apache License to your work.\par
+
+\par
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.\par
+
+\par
+
+   Copyright [yyyy] [name of copyright owner]\par
+
+\par
+
+   Licensed under the Apache License, Version 2.0 (the "License");\par
+
+   you may not use this file except in compliance with the License.\par
+
+   You may obtain a copy of the License at\par
+
+\par
+
+       http://www.apache.org/licenses/LICENSE-2.0\par
+
+\par
+
+   Unless required by applicable law or agreed to in writing, software\par
+
+   distributed under the License is distributed on an "AS IS" BASIS,\par
+
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\par
+
+   implied. See the License for the specific language governing\par
+
+   permissions and limitations under the License.\par
+
+\par
+
+}
+
+ 
\ No newline at end of file
diff --git a/omnibus/resources/chef/msi/assets/banner_background.bmp b/omnibus/resources/chef/msi/assets/banner_background.bmp
new file mode 100644
index 0000000..5769a88
Binary files /dev/null and b/omnibus/resources/chef/msi/assets/banner_background.bmp differ
diff --git a/omnibus/resources/chef/msi/assets/dialog_background.bmp b/omnibus/resources/chef/msi/assets/dialog_background.bmp
new file mode 100644
index 0000000..4dbe489
Binary files /dev/null and b/omnibus/resources/chef/msi/assets/dialog_background.bmp differ
diff --git a/omnibus/resources/chef/msi/assets/oc.ico b/omnibus/resources/chef/msi/assets/oc.ico
new file mode 100644
index 0000000..c4cee7b
Binary files /dev/null and b/omnibus/resources/chef/msi/assets/oc.ico differ
diff --git a/omnibus/resources/chef/msi/assets/oc_16x16.ico b/omnibus/resources/chef/msi/assets/oc_16x16.ico
new file mode 100644
index 0000000..d3bd065
Binary files /dev/null and b/omnibus/resources/chef/msi/assets/oc_16x16.ico differ
diff --git a/omnibus/resources/chef/msi/assets/oc_32x32.ico b/omnibus/resources/chef/msi/assets/oc_32x32.ico
new file mode 100644
index 0000000..5eee004
Binary files /dev/null and b/omnibus/resources/chef/msi/assets/oc_32x32.ico differ
diff --git a/omnibus/resources/chef/msi/localization-en-us.wxl.erb b/omnibus/resources/chef/msi/localization-en-us.wxl.erb
new file mode 100644
index 0000000..62c27b9
--- /dev/null
+++ b/omnibus/resources/chef/msi/localization-en-us.wxl.erb
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
+  <!-- http://wix.codeplex.com/SourceControl/changeset/view/792e101c5cf7#src%2fext%2fUIExtension%2fwixlib%2fWixUI_en-us.wxl -->
+  <String Id="LANG">1033</String>
+  <String Id="ProductName"><%= friendly_name %></String>
+  <String Id="ManufacturerName">Chef Software, Inc.</String>
+  <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] Setup Wizard</String>
+
+  <String Id="LicenseAgreementDlgTitle">{\WixUI_Font_Title_White}End-User License Agreement</String>
+  <String Id="LicenseAgreementDlgDescription">{\WixUI_Font_Normal_White}Please read the following license agreement carefully</String>
+
+  <String Id="InstallDirDlgTitle">{\WixUI_Font_Title_White}Destination Folder</String>
+  <String Id="InstallDirDlgDescription">{\WixUI_Font_Normal_White}Click Next to install to the default folder or click Change to choose another.</String>
+
+  <String Id="ProgressDlgTitleInstalling">{\WixUI_Font_Title_White}Installing [ProductName]</String>
+
+  <String Id="VerifyReadyDlgInstallTitle">{\WixUI_Font_Title_White}Ready to install [ProductName]</String>
+
+  <!-- Service -->
+  <!-- Keep these in sync with the name and description in chef-service-manager -->
+  <String Id="ServiceDisplayName"><%= friendly_name %> Service</String>
+  <String Id="ServiceDescription">Runs <%= friendly_name %> on regular, configurable intervals.</String>
+  <String Id="FeatureMainName"><%= friendly_name %></String>
+  <String Id="FeatureServiceName"><%= friendly_name %> Service</String>
+  <String Id="FeaturePSModuleName"><%= friendly_name %> PowerShell wrappers</String>
+
+  <String Id="MinimumOSVersionMessage">This package requires minimum OS version: Windows 7/Windows Server 2008 R2 or greater.</String>
+  <String Id="DowngradeErrorMessage">A newer version of [ProductName] is already installed.</String>
+  <String Id="FileExtractionProgress">Extracting files, please wait...</String>
+</WixLocalization>
diff --git a/omnibus/resources/chef/msi/parameters.wxi.erb b/omnibus/resources/chef/msi/parameters.wxi.erb
new file mode 100644
index 0000000..febd173
--- /dev/null
+++ b/omnibus/resources/chef/msi/parameters.wxi.erb
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Include>
+  <?define VersionNumber="<%= version %>" ?>
+  <?define DisplayVersionNumber="<%= display_version %>" ?>
+  <?define UpgradeCode="<%= upgrade_code %>" ?>
+<% parameters.each do |key, value| -%>
+  <?define <%= key %>="<%= value %>" ?>
+<% end -%>
+</Include>
diff --git a/omnibus/resources/chef/msi/source.wxs.erb b/omnibus/resources/chef/msi/source.wxs.erb
new file mode 100644
index 0000000..bdde026
--- /dev/null
+++ b/omnibus/resources/chef/msi/source.wxs.erb
@@ -0,0 +1,192 @@
+<?xml version='1.0'?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+
+  <!-- This is how we include wxi files -->
+  <?include "parameters.wxi" ?>
+
+  <!--
+    Id="*" is to enable upgrading. * means that the product ID will be autogenerated on each build.
+    Name is made of localized product name and version number.
+  -->
+  <Product Id="*" Name="!(loc.ProductName) v$(var.DisplayVersionNumber)" Language="!(loc.LANG)"
+          Version="$(var.VersionNumber)" Manufacturer="!(loc.ManufacturerName)" UpgradeCode="$(var.UpgradeCode)">
+
+    <!--
+      Define the minimum supported installer version (2.0).
+      The install should be done for the whole machine not just the current user
+    -->
+    <Package InstallerVersion="200" InstallPrivileges="elevated"
+             Compressed="yes" InstallScope="perMachine" />
+
+    <!--
+      Create property references for the well known SIDs of the 
+      accounts we want to restrict for the project location folder
+    -->
+    <PropertyRef Id="WIX_ACCOUNT_LOCALSYSTEM" />
+    <PropertyRef Id="WIX_ACCOUNT_ADMINISTRATORS" />
+    <PropertyRef Id="WIX_ACCOUNT_USERS" />
+
+    <Media Id="1" Cabinet="ChefClient.cab" EmbedCab="yes" CompressionLevel="high" />
+
+    <!--
+      Uncomment launch condition below to check for minimum OS
+      601 = Windows 7/Server 2008R2.
+    -->
+    <!-- Condition Message="!(loc.MinimumOSVersionMessage)">
+      <![CDATA[Installed OR VersionNT >= 601]]>
+    </Condition -->
+
+    <!-- We always do Major upgrades -->
+    <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeErrorMessage)" />
+
+
+    <!--
+      If fastmsi is set, custom actions will be invoked during install to unzip
+      project files, and during uninstall to remove the project folder
+    -->
+    <% if fastmsi %>
+    <SetProperty Id="FastUnzip"
+                 Value="FASTZIPDIR=[INSTALLLOCATION];FASTZIPAPPNAME=$(var.ProjectLocationDir)"
+                 Sequence="execute"
+                 Before="FastUnzip" />
+
+    <CustomAction Id="FastUnzip"
+                  BinaryKey="CustomActionFastMsiDLL"
+                  DllEntry="FastUnzip"
+                  Execute="deferred"
+                  Impersonate="no"
+                  Return="check" />
+
+    <Binary Id="CustomActionFastMsiDLL"
+            SourceFile="CustomActionFastMsi.CA.dll" />
+
+    <CustomAction Id="Cleanup"
+                  Directory="INSTALLLOCATION"
+                  ExeCommand="cmd /C "rd /S /Q $(var.ProjectLocationDir)""
+                  Execute="deferred"
+                  Impersonate="no"
+                  Return="ignore" />
+
+    <InstallExecuteSequence>
+      <Custom Action="FastUnzip" After="InstallFiles">NOT Installed</Custom>
+      <Custom Action="Cleanup" After="RemoveFiles">REMOVE~="ALL"</Custom>
+    </InstallExecuteSequence>
+
+    <UI>
+      <ProgressText Action="FastUnzip">!(loc.FileExtractionProgress)</ProgressText>
+    </UI>
+    <% end %>
+
+    <Directory Id="TARGETDIR" Name="SourceDir">
+      <Directory Id="WindowsVolume">
+        <!-- Service needs chef directory to be present. -->
+        <Directory Id="CONFIGLOCATION" Name="chef">
+          <Component Id="CONFIGLOCATIONDIR" Guid="{F66F6394-51A4-4C5D-908B-E55584473436}" >
+            <CreateFolder Directory="CONFIGLOCATION" />
+          </Component>
+        </Directory>
+        <Directory Id="INSTALLLOCATION" Name="opscode">
+          <Directory Id="PROJECTLOCATION" Name="$(var.ProjectLocationDir)" >
+            <Component Id="ProjectLocationPermissions" Guid="{75f50556-efae-4ede-beb2-a2c9b1a4d43f}" >
+              <!--
+                Windows client SKUs give the Authenticated Users group modify rights
+                to new folders created. We ONLY want the local system account and any administrator to have that right to protect non admin users from injecting code that could be executed by a service running as SYSTEM
+              -->
+              <CreateFolder>
+                <Permission User="[WIX_ACCOUNT_LOCALSYSTEM]" GenericAll="yes"/>
+                <Permission User="[WIX_ACCOUNT_ADMINISTRATORS]" GenericAll="yes"/>
+                <Permission User="[WIX_ACCOUNT_USERS]" GenericRead="yes" GenericExecute="yes"/>
+              </CreateFolder>
+            </Component>
+            <Directory Id="PROJECTLOCATIONBIN" Name="bin" >
+              <Component Id="ChefClientPath" Guid="{7F663F88-55A2-4E20-82BF-8BD2E60BB83A}" >
+                <Environment Id="ClientPathEnvironment"
+                             Name="PATH" Action="set" Part="last" System="yes" Value="[PROJECTLOCATIONBIN]" />
+              </Component>
+            </Directory>
+            <Directory Id="PSMODULES" Name="modules" >
+              <Component Id="ChefPSModulePath" Guid="{357DA654-F02E-430A-9EA6-A10554E3EF38}" >
+                <Environment Id="ChefPSModulePathEnvironment"
+                             Name="PSModulePath" Action="set" Part="last" System="yes" Value="[PSMODULES]" />
+              </Component>
+            </Directory>
+            <Directory Id="EMBEDDED" Name="embedded" >
+              <Directory Id="EMBEDDEDBIN" Name="bin" >
+                <Component Id="ChefClientService" Guid="{69B2D8BE-4A47-4BE3-AEE8-83FAEB6E2FAF}" >
+                  <File Id="RubyExecutable" Source="$(var.ProjectSourceDir)\embedded\bin\ruby.exe" KeyPath="yes" />
+                  <ServiceInstall Name="chef-client" Type="ownProcess"
+                                  Start="auto" Vital="yes" ErrorControl="ignore"
+                                  Arguments="[PROJECTLOCATION]bin\chef-windows-service"
+                                  DisplayName="!(loc.ServiceDisplayName)"
+                                  Description="!(loc.ServiceDescription)">
+                      <ServiceDependency Id="Winmgmt" />
+                      <ServiceConfig DelayedAutoStart="yes" OnInstall="yes" />
+                  </ServiceInstall>
+                  <ServiceControl Id="ControlChefClientService" Name="chef-client"
+                                  Remove="both" Stop="both" Wait="yes" />
+                </Component>
+                <Component Id="ChefClientLog" Guid="{8e492d59-3a0c-43fd-b889-e35dfa33da91}">
+                    <util:EventSource xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
+                        Name="Chef" Log="Application"
+                        EventMessageFile="[PROJECTLOCATION]$(var.ChefLogDllPath)"
+                        />
+                </Component>
+              </Directory>
+            </Directory>
+          </Directory>
+        </Directory>
+      </Directory>
+    </Directory>
+
+    <!-- Set the components defined in our fragment files that will be used for our feature  -->
+    <Feature Id="ChefClientFeature" Title="!(loc.FeatureMainName)" Absent="disallow" AllowAdvertise="no" Level="1" ConfigurableDirectory="INSTALLLOCATION">
+      <ComponentGroupRef Id="ProjectDir" />
+      <ComponentRef Id="ProjectLocationPermissions" />
+      <ComponentRef Id="ChefClientPath" />
+      <ComponentRef Id="CONFIGLOCATIONDIR" />
+      <ComponentRef Id="ChefClientLog" />
+    </Feature>
+
+    <Feature Id="ChefPSModuleFeature" Title="!(loc.FeaturePSModuleName)" Level="1000" AllowAdvertise="no">
+      <ComponentRef Id="ChefPSModulePath" />
+    </Feature>
+
+    <Feature Id="ChefServiceFeature" Title="!(loc.FeatureServiceName)" Level="1000" AllowAdvertise="no">
+      <ComponentRef Id="ChefClientService" />
+    </Feature>
+
+    <!--
+      TODO:
+
+      * create initial Client config? ie C:\chef\client.rb?
+      * optionally install extra tools?  ie git?
+
+    -->
+
+    <!--
+      UI Stuff
+    -->
+    <Icon Id="oc.ico" SourceFile="Resources\assets\oc_16x16.ico"/>
+    <Property Id="ARPPRODUCTICON" Value="oc.ico" />
+    <Property Id="ARPHELPLINK" Value="http://www.getchef.com/support/" />
+    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />
+
+    <UIRef Id="ChefClientUI_InstallDir"/>
+    <UI Id="ChefClientUI_InstallDir">
+      <UIRef Id="WixUI_FeatureTree"/>
+      <TextStyle Id="WixUI_Font_Normal_White" FaceName="Tahoma" Size="8" Red="255" Green="255" Blue="255" />
+      <TextStyle Id="WixUI_Font_Bigger_White" FaceName="Tahoma" Size="12" Red="255" Green="255" Blue="255" />
+      <TextStyle Id="WixUI_Font_Title_White" FaceName="Tahoma" Size="9" Bold="yes" Red="255" Green="255" Blue="255" />
+    </UI>
+
+    <WixVariable Id="WixUILicenseRtf" Value="Resources\assets\LICENSE.rtf" />
+    <WixVariable Id="WixUIDialogBmp" Value="Resources\assets\dialog_background.bmp" />
+    <WixVariable Id="WixUIBannerBmp" Value="Resources\assets\banner_background.bmp" />
+
+    <WixVariable Id="WixUIExclamationIco" Value="Resources\assets\oc_32x32.ico" />
+    <WixVariable Id="WixUIInfoIco" Value="Resources\assets\oc_32x32.ico" />
+    <WixVariable Id="WixUINewIco" Value="Resources\assets\oc_16x16.ico" />
+    <WixVariable Id="WixUIUpIco" Value="Resources\assets\oc_16x16.ico" />
+
+  </Product>
+</Wix>
diff --git a/omnibus/resources/chef/pkg/background.png b/omnibus/resources/chef/pkg/background.png
new file mode 100644
index 0000000..027453a
Binary files /dev/null and b/omnibus/resources/chef/pkg/background.png differ
diff --git a/omnibus/resources/chef/pkg/license.html.erb b/omnibus/resources/chef/pkg/license.html.erb
new file mode 100644
index 0000000..21b7991
--- /dev/null
+++ b/omnibus/resources/chef/pkg/license.html.erb
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright <%= Time.new.year %> Chef Software Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/omnibus/resources/chef/pkg/welcome.html.erb b/omnibus/resources/chef/pkg/welcome.html.erb
new file mode 100644
index 0000000..04a02fb
--- /dev/null
+++ b/omnibus/resources/chef/pkg/welcome.html.erb
@@ -0,0 +1,5 @@
+
+  This installer will help you install <%= friendly_name %> version <%= build_version %>.
+
+
+  You will be guided through the steps necessary to install this software.
diff --git a/pedant.gemfile b/pedant.gemfile
new file mode 100644
index 0000000..3302bcc
--- /dev/null
+++ b/pedant.gemfile
@@ -0,0 +1,25 @@
+source "https://rubygems.org"
+gemspec :name => "chef"
+
+# TODO figure out how to grab this stuff from the main Gemfile
+gem "activesupport", "< 4.0.0", :group => :compat_testing, :platform => "ruby"
+
+# We are pinning chef-zero to 4.2.x until ChefFS can deal
+# with V1 api calls or chef-zero supports both v0 and v1
+gem "chef-zero", "~> 4.2.3"
+
+group(:docgen) do
+  gem "tomlrb"
+  gem "yard"
+end
+
+group(:development, :test) do
+  gem "simplecov"
+  gem 'rack', "~> 1.5.1"
+
+  gem 'ruby-shadow', :platforms => :ruby unless RUBY_PLATFORM.downcase.match(/(aix|cygwin)/)
+end
+
+# If you want to load debugging tools into the bundle exec sandbox,
+# add these additional dependencies into chef/Gemfile.local
+eval(IO.read(__FILE__ + '.local'), binding) if File.exists?(__FILE__ + '.local')
diff --git a/rubygems-pkg/rubygems-update-2.4.6.gem b/rubygems-pkg/rubygems-update-2.4.6.gem
new file mode 100644
index 0000000..97ebec6
Binary files /dev/null and b/rubygems-pkg/rubygems-update-2.4.6.gem differ
diff --git a/spec/data/apt/chef-integration-test-1.0/debian/copyright b/spec/data/apt/chef-integration-test-1.0/debian/copyright
index 72b6c65..e840a11 100644
--- a/spec/data/apt/chef-integration-test-1.0/debian/copyright
+++ b/spec/data/apt/chef-integration-test-1.0/debian/copyright
@@ -8,7 +8,7 @@ Upstream Author(s):
 
 Copyright:
 
-    Copyright (C) 2010 Opscode, Inc
+    Copyright 2010-2016, Chef Software Inc.
 
 License:
 
@@ -26,7 +26,7 @@ License:
 
 The Debian packaging is:
 
-    Copyright (C) 2010 Opscode, Inc (<legal at opscode.com>)
+    Copyright 2010-2016, Chef Software Inc. (<legal at chef.io>)
 
 
 and is licensed under the Apache 2.0 license.
diff --git a/spec/data/apt/chef-integration-test-1.1/debian/copyright b/spec/data/apt/chef-integration-test-1.1/debian/copyright
index 72b6c65..e840a11 100644
--- a/spec/data/apt/chef-integration-test-1.1/debian/copyright
+++ b/spec/data/apt/chef-integration-test-1.1/debian/copyright
@@ -8,7 +8,7 @@ Upstream Author(s):
 
 Copyright:
 
-    Copyright (C) 2010 Opscode, Inc
+    Copyright 2010-2016, Chef Software Inc.
 
 License:
 
@@ -26,7 +26,7 @@ License:
 
 The Debian packaging is:
 
-    Copyright (C) 2010 Opscode, Inc (<legal at opscode.com>)
+    Copyright 2010-2016, Chef Software Inc. (<legal at chef.io>)
 
 
 and is licensed under the Apache 2.0 license.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/changelog b/spec/data/apt/chef-integration-test2-1.0/debian/changelog
new file mode 100644
index 0000000..1b846f8
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/changelog
@@ -0,0 +1,5 @@
+chef-integration-test2 (1.0-1) unstable; urgency=low
+
+  * Initial release (Closes: #CHEF-1718)
+
+ -- Joshua Timberman <joshua at opscode.com>  Thu, 30 Sep 2010 09:53:45 -0600
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log
new file mode 100644
index 0000000..2d06fcd
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log
@@ -0,0 +1,45 @@
+dh_auto_configure
+dh_auto_build
+dh_auto_test
+dh_prep
+dh_installdirs
+dh_auto_install
+dh_install
+dh_installdocs
+dh_installchangelogs
+dh_installexamples
+dh_installman
+dh_installcatalogs
+dh_installcron
+dh_installdebconf
+dh_installemacsen
+dh_installifupdown
+dh_installinfo
+dh_pysupport
+dh_installinit
+dh_installmenu
+dh_installmime
+dh_installmodules
+dh_installlogcheck
+dh_installlogrotate
+dh_installpam
+dh_installppp
+dh_installudev
+dh_installwm
+dh_installxfonts
+dh_bugfiles
+dh_lintian
+dh_gconf
+dh_icons
+dh_perl
+dh_usrlocal
+dh_link
+dh_compress
+dh_fixperms
+dh_strip
+dh_makeshlibs
+dh_shlibdeps
+dh_installdeb
+dh_gencontrol
+dh_md5sums
+dh_builddeb
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars
new file mode 100644
index 0000000..abd3ebe
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars
@@ -0,0 +1 @@
+misc:Depends=
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles
new file mode 100644
index 0000000..ac4307e
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles
@@ -0,0 +1 @@
+/usr/share/doc/chef-integration-test2/copyright
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control
new file mode 100644
index 0000000..27d53d9
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control
@@ -0,0 +1,10 @@
+Package: chef-integration-test2
+Version: 1.0-1
+Architecture: amd64
+Maintainer: Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+Installed-Size: 36
+Section: ruby
+Priority: extra
+Homepage: http://tickets.opscode.com
+Description: Chef integration tests for APT in Cucumber
+ This package is used for cucumber integration testing in Chef.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums
new file mode 100644
index 0000000..144b793
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums
@@ -0,0 +1 @@
+8b3b9ff6cdfe7d7b2b8b8d4f7b9e381f  usr/share/doc/chef-integration-test2/changelog.Debian.gz
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/compat b/spec/data/apt/chef-integration-test2-1.0/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/conffiles b/spec/data/apt/chef-integration-test2-1.0/debian/conffiles
new file mode 100644
index 0000000..ac4307e
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/conffiles
@@ -0,0 +1 @@
+/usr/share/doc/chef-integration-test2/copyright
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/control b/spec/data/apt/chef-integration-test2-1.0/debian/control
new file mode 100644
index 0000000..f2731a6
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/control
@@ -0,0 +1,13 @@
+Source: chef-integration-test2
+Section: ruby
+Priority: extra
+Maintainer: Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+Build-Depends: debhelper (>= 7.0.50~)
+Standards-Version: 3.8.4
+Homepage: http://tickets.opscode.com
+
+Package: chef-integration-test2
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Chef integration tests for APT in Cucumber
+ This package is used for cucumber integration testing in Chef.
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/copyright b/spec/data/apt/chef-integration-test2-1.0/debian/copyright
new file mode 100644
index 0000000..e840a11
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/copyright
@@ -0,0 +1,34 @@
+This work was packaged by:
+
+    Joshua Timberman <Joshua Timberman <joshua at opscode.com>> on Thu, 30 Sep 2010 09:53:45 -0600
+
+Upstream Author(s):
+
+    Opscode, Inc.
+
+Copyright:
+
+    Copyright 2010-2016, Chef Software Inc.
+
+License:
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+The Debian packaging is:
+
+    Copyright 2010-2016, Chef Software Inc. (<legal at chef.io>)
+
+
+and is licensed under the Apache 2.0 license.
+
+See "/usr/share/common-licenses/Apache-2.0"
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/files b/spec/data/apt/chef-integration-test2-1.0/debian/files
new file mode 100644
index 0000000..640e4c6
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/files
@@ -0,0 +1 @@
+chef-integration-test2_1.0-1_amd64.deb ruby extra
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/rules b/spec/data/apt/chef-integration-test2-1.0/debian/rules
new file mode 100755
index 0000000..b760bee
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+	dh $@ 
diff --git a/spec/data/apt/chef-integration-test2-1.0/debian/source/format b/spec/data/apt/chef-integration-test2-1.0/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2-1.0/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz b/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz
new file mode 100644
index 0000000..6c002a7
Binary files /dev/null and b/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz differ
diff --git a/spec/data/apt/chef-integration-test2_1.0-1.dsc b/spec/data/apt/chef-integration-test2_1.0-1.dsc
new file mode 100644
index 0000000..b247f49
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1.dsc
@@ -0,0 +1,18 @@
+Format: 3.0 (quilt)
+Source: chef-integration-test2
+Binary: chef-integration-test2
+Architecture: any
+Version: 1.0-1
+Maintainer: Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+Homepage: http://tickets.opscode.com
+Standards-Version: 3.8.4
+Build-Depends: debhelper (>= 7.0.50~)
+Checksums-Sha1: 
+ 755c304197c6559128aed206ea70643fec2bb90d 248 chef-integration-test2_1.0.orig.tar.gz
+ 8b7df49a9e2c57b4460c2738852db1156a21a089 1369 chef-integration-test2_1.0-1.debian.tar.gz
+Checksums-Sha256: 
+ 8b206a7b3d422290bc8d82bd700cb89f1c6e3962b96be6a3955c7a0159f9031c 248 chef-integration-test2_1.0.orig.tar.gz
+ 77a7956e222c35afcddc4a5a8d338ca6e36dc1fbd720af255ce2412885f82702 1369 chef-integration-test2_1.0-1.debian.tar.gz
+Files: 
+ f1f7d7bbe63ad631d25d707f564a8d33 248 chef-integration-test2_1.0.orig.tar.gz
+ 4fab5c1cd9a7b47c4f319af776f48a1d 1369 chef-integration-test2_1.0-1.debian.tar.gz
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.build b/spec/data/apt/chef-integration-test2_1.0-1_amd64.build
new file mode 100644
index 0000000..8ef31d3
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1_amd64.build
@@ -0,0 +1,91 @@
+ dpkg-buildpackage -rfakeroot -D -us -uc
+dpkg-buildpackage: warning: using a gain-root-command while being root
+dpkg-buildpackage: set CFLAGS to default value: -g -O2
+dpkg-buildpackage: set CPPFLAGS to default value: 
+dpkg-buildpackage: set LDFLAGS to default value: -Wl,-Bsymbolic-functions
+dpkg-buildpackage: set FFLAGS to default value: -g -O2
+dpkg-buildpackage: set CXXFLAGS to default value: -g -O2
+dpkg-buildpackage: source package chef-integration-test2
+dpkg-buildpackage: source version 1.0-1
+dpkg-buildpackage: source changed by Joshua Timberman <joshua at opscode.com>
+dpkg-buildpackage: host architecture amd64
+ fakeroot debian/rules clean
+dh clean 
+   dh_testdir
+   dh_auto_clean
+   dh_clean
+ dpkg-source -b chef-integration-test2-1.0
+dpkg-source: info: using source format `3.0 (quilt)'
+dpkg-source: info: building chef-integration-test2 using existing ./chef-integration-test2_1.0.orig.tar.gz
+dpkg-source: warning: ignoring deletion of directory cache
+dpkg-source: warning: ignoring deletion of directory cache/chef-integration-test2
+dpkg-source: warning: ignoring deletion of file cache/chef-integration-test2/contents
+dpkg-source: info: building chef-integration-test2 in chef-integration-test2_1.0-1.debian.tar.gz
+dpkg-source: info: building chef-integration-test2 in chef-integration-test2_1.0-1.dsc
+ debian/rules build
+dh build 
+   dh_testdir
+   dh_auto_configure
+   dh_auto_build
+   dh_auto_test
+ fakeroot debian/rules binary
+dh binary 
+   dh_testroot
+   dh_prep
+   dh_installdirs
+   dh_auto_install
+   dh_install
+   dh_installdocs
+   dh_installchangelogs
+   dh_installexamples
+   dh_installman
+   dh_installcatalogs
+   dh_installcron
+   dh_installdebconf
+   dh_installemacsen
+   dh_installifupdown
+   dh_installinfo
+   dh_pysupport
+   dh_installinit
+   dh_installmenu
+   dh_installmime
+   dh_installmodules
+   dh_installlogcheck
+   dh_installlogrotate
+   dh_installpam
+   dh_installppp
+   dh_installudev
+   dh_installwm
+   dh_installxfonts
+   dh_bugfiles
+   dh_lintian
+   dh_gconf
+   dh_icons
+   dh_perl
+   dh_usrlocal
+   dh_link
+   dh_compress
+   dh_fixperms
+   dh_strip
+   dh_makeshlibs
+   dh_shlibdeps
+   dh_installdeb
+   dh_gencontrol
+dpkg-gencontrol: warning: unknown substitution variable ${shlibs:Depends}
+   dh_md5sums
+   dh_builddeb
+dpkg-deb: building package `chef-integration-test2' in `../chef-integration-test2_1.0-1_amd64.deb'.
+ dpkg-genchanges  >../chef-integration-test2_1.0-1_amd64.changes
+dpkg-genchanges: including full source code in upload
+dpkg-buildpackage: full upload (original source is included)
+Now running lintian...
+warning: lintian's authors do not recommend running it with root privileges!
+E: chef-integration-test2 source: maintainer-address-malformed Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+W: chef-integration-test2 source: changelog-should-mention-nmu
+W: chef-integration-test2 source: source-nmu-has-incorrect-version-number 1.0-1
+W: chef-integration-test2: new-package-should-close-itp-bug
+W: chef-integration-test2: wrong-bug-number-in-closes l3:#CHEF
+E: chef-integration-test2: file-in-usr-marked-as-conffile /usr/share/doc/chef-integration-test2/copyright
+E: chef-integration-test2: maintainer-address-malformed Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+W: chef-integration-test2: empty-binary-package
+Finished running lintian.
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes b/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes
new file mode 100644
index 0000000..be3cd45
--- /dev/null
+++ b/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes
@@ -0,0 +1,31 @@
+Format: 1.8
+Date: Thu, 30 Sep 2010 09:53:45 -0600
+Source: chef-integration-test2
+Binary: chef-integration-test2
+Architecture: source amd64
+Version: 1.0-1
+Distribution: unstable
+Urgency: low
+Maintainer: Joshua Timberman <Joshua Timberman <joshua at opscode.com>>
+Changed-By: Joshua Timberman <joshua at opscode.com>
+Description: 
+ chef-integration-test2 - Chef integration tests for APT in Cucumber
+Changes: 
+ chef-integration-test2 (1.0-1) unstable; urgency=low
+ .
+   * Initial release (Closes: #CHEF-1718)
+Checksums-Sha1: 
+ 7e065fdf71f4d798312b318a29cec43b7bc1c8e1 885 chef-integration-test2_1.0-1.dsc
+ 755c304197c6559128aed206ea70643fec2bb90d 248 chef-integration-test2_1.0.orig.tar.gz
+ 8b7df49a9e2c57b4460c2738852db1156a21a089 1369 chef-integration-test2_1.0-1.debian.tar.gz
+ f3f89c051bce36d40ef1be12d231c44b2d5be05b 1694 chef-integration-test2_1.0-1_amd64.deb
+Checksums-Sha256: 
+ 80d314349e1d978f242d05482ca81c9361739047daa4adcecc9e5e622fdc6fb4 885 chef-integration-test2_1.0-1.dsc
+ 8b206a7b3d422290bc8d82bd700cb89f1c6e3962b96be6a3955c7a0159f9031c 248 chef-integration-test2_1.0.orig.tar.gz
+ 77a7956e222c35afcddc4a5a8d338ca6e36dc1fbd720af255ce2412885f82702 1369 chef-integration-test2_1.0-1.debian.tar.gz
+ 19a767db0a947a350fb1c8492699e8a808fbe1838d4a582001106cfbe520ad8f 1694 chef-integration-test2_1.0-1_amd64.deb
+Files: 
+ 9f927b32d95b5406c696b5b0b23177e8 885 ruby extra chef-integration-test2_1.0-1.dsc
+ f1f7d7bbe63ad631d25d707f564a8d33 248 ruby extra chef-integration-test2_1.0.orig.tar.gz
+ 4fab5c1cd9a7b47c4f319af776f48a1d 1369 ruby extra chef-integration-test2_1.0-1.debian.tar.gz
+ 9914e6152e278b6828bcade3b3f5580c 1694 ruby extra chef-integration-test2_1.0-1_amd64.deb
diff --git a/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb b/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb
new file mode 100644
index 0000000..7b9b69d
Binary files /dev/null and b/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb differ
diff --git a/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz b/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz
new file mode 100644
index 0000000..18f7aa1
Binary files /dev/null and b/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz differ
diff --git a/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb b/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
index 01d302f..0bb34e7 100644
--- a/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
+++ b/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb
@@ -2,7 +2,7 @@
 # Cookbook Name:: name-mismatch
 # Recipe:: default
 #
-# Copyright (C) 2014 
+# Copyright 2014-2016, 
 #
 # 
 #
diff --git a/spec/data/cookbooks/openldap/templates/default/helpers.erb b/spec/data/cookbooks/openldap/templates/default/helpers.erb
new file mode 100644
index 0000000..b973a52
--- /dev/null
+++ b/spec/data/cookbooks/openldap/templates/default/helpers.erb
@@ -0,0 +1,14 @@
+<%= @cookbook_name %>
+<%= @recipe_name %>
+<%= @recipe_line_string %>
+<%= @recipe_path %>
+<%= @recipe_line %>
+<%= @template_name %>
+<%= @template_path %>
+<%= cookbook_name %>
+<%= recipe_name %>
+<%= recipe_line_string %>
+<%= recipe_path %>
+<%= recipe_line %>
+<%= template_name %>
+<%= template_path %>
diff --git a/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb b/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb
new file mode 100644
index 0000000..2d356ec
--- /dev/null
+++ b/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb
@@ -0,0 +1 @@
+before <%= render 'nested_partial.erb', :variables => { :hello => @test } %> after
diff --git a/spec/data/cookbooks/openldap/templates/default/nested_partial.erb b/spec/data/cookbooks/openldap/templates/default/nested_partial.erb
new file mode 100644
index 0000000..415646c
--- /dev/null
+++ b/spec/data/cookbooks/openldap/templates/default/nested_partial.erb
@@ -0,0 +1 @@
+{<%= @hello %>}
diff --git a/spec/data/cookbooks/supports-platform-constraints/metadata.rb b/spec/data/cookbooks/supports-platform-constraints/metadata.rb
new file mode 100644
index 0000000..3620249
--- /dev/null
+++ b/spec/data/cookbooks/supports-platform-constraints/metadata.rb
@@ -0,0 +1,5 @@
+name 'supports-platform-constraints'
+version '0.1.0'
+
+supports 'centos', '>= 6'
+supports 'freebsd', '> 10.1-fake-p12'
diff --git a/spec/data/dsc_lcm.pfx b/spec/data/dsc_lcm.pfx
new file mode 100644
index 0000000..3912ed3
Binary files /dev/null and b/spec/data/dsc_lcm.pfx differ
diff --git a/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb b/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
index 65ae049..0d8cca1 100644
--- a/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
+++ b/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb
@@ -2,7 +2,7 @@
 # Cookbook Name:: incomplete-metadata
 # Recipe:: default
 #
-# Copyright (C) 2014 
+# Copyright 2014-2016, 
 #
 # 
 #
diff --git a/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb b/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
index f548ad1..1130ee4 100644
--- a/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
+++ b/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb
@@ -1,5 +1,3 @@
-raise "THIS METADATA HAS A BUG"
-
 name             'invalid-metadata'
 maintainer       ''
 maintainer_email ''
@@ -8,3 +6,4 @@ description      'Installs/Configures invalid-metadata'
 long_description 'Installs/Configures invalid-metadata'
 version          '0.1.0'
 
+raise "THIS METADATA HAS A BUG"
diff --git a/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb b/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
index 1411b9e..33ec114 100644
--- a/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
+++ b/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb
@@ -2,7 +2,7 @@
 # Cookbook Name:: invalid-metadata
 # Recipe:: default
 #
-# Copyright (C) 2014 
+# Copyright 2014-2016, 
 #
 # 
 #
diff --git a/spec/data/lwrp/providers/buck_passer.rb b/spec/data/lwrp/providers/buck_passer.rb
index 9792e2c..2bbca07 100644
--- a/spec/data/lwrp/providers/buck_passer.rb
+++ b/spec/data/lwrp/providers/buck_passer.rb
@@ -1,12 +1,28 @@
 provides :buck_passer
 
+def without_deprecation_warnings(&block)
+  old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+  Chef::Config[:treat_deprecation_warnings_as_errors] = false
+  begin
+    block.call
+  ensure
+    Chef::Config[:treat_deprecation_warnings_as_errors] = old_treat_deprecation_warnings_as_errors
+  end
+end
+
 action :pass_buck do
   lwrp_foo :prepared_thumbs do
     action :prepare_thumbs
-    provider :lwrp_thumb_twiddler
+    # We know there will be a deprecation error here; head it off
+    without_deprecation_warnings do
+      provider :lwrp_thumb_twiddler
+    end
   end
   lwrp_foo :twiddled_thumbs do
     action :twiddle_thumbs
-    provider :lwrp_thumb_twiddler
+    # We know there will be a deprecation error here; head it off
+    without_deprecation_warnings do
+      provider :lwrp_thumb_twiddler
+    end
   end
 end
diff --git a/spec/data/lwrp/providers/buck_passer_2.rb b/spec/data/lwrp/providers/buck_passer_2.rb
index d34da3c..c3bab72 100644
--- a/spec/data/lwrp/providers/buck_passer_2.rb
+++ b/spec/data/lwrp/providers/buck_passer_2.rb
@@ -1,10 +1,26 @@
+def without_deprecation_warnings(&block)
+  old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+  Chef::Config[:treat_deprecation_warnings_as_errors] = false
+  begin
+    block.call
+  ensure
+    Chef::Config[:treat_deprecation_warnings_as_errors] = old_treat_deprecation_warnings_as_errors
+  end
+end
+
 action :pass_buck do
   lwrp_bar :prepared_eyes do
     action :prepare_eyes
-    provider :lwrp_paint_drying_watcher
+    # We know there will be a deprecation error here; head it off
+    without_deprecation_warnings do
+      provider :lwrp_paint_drying_watcher
+    end
   end
   lwrp_bar :dried_paint_watched do
     action :watch_paint_dry
-    provider :lwrp_paint_drying_watcher
+    # We know there will be a deprecation error here; head it off
+    without_deprecation_warnings do
+      provider :lwrp_paint_drying_watcher
+    end
   end
 end
diff --git a/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb b/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb
index f5841fb..77c1111 100644
--- a/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb
+++ b/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb
@@ -3,11 +3,23 @@
 # are passed properly (as demonstrated by the call to generate_new_name).
 attr_reader :enclosed_resource
 
+def without_deprecation_warnings(&block)
+  old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+  Chef::Config[:treat_deprecation_warnings_as_errors] = false
+  begin
+    block.call
+  ensure
+    Chef::Config[:treat_deprecation_warnings_as_errors] = old_treat_deprecation_warnings_as_errors
+  end
+end
+
 action :twiddle_thumbs do
   @enclosed_resource = lwrp_foo :foo do
     monkey generate_new_name(new_resource.monkey){ 'the monkey' }
-    action :twiddle_thumbs
-    provider :lwrp_monkey_name_printer
+    # We know there will be a deprecation error here; head it off
+    without_deprecation_warnings do
+      provider :lwrp_monkey_name_printer
+    end
   end
 end
 
diff --git a/spec/data/lwrp_override/resources/foo.rb b/spec/data/lwrp_override/resources/foo.rb
index 14decb9..2fc13d3 100644
--- a/spec/data/lwrp_override/resources/foo.rb
+++ b/spec/data/lwrp_override/resources/foo.rb
@@ -3,3 +3,8 @@
 actions :never_execute
 
 attribute :ever, :kind_of => String
+
+class ::Chef
+  def method_created_by_override_lwrp_foo
+  end
+end
diff --git a/spec/data/run_context/cookbooks/include/recipes/default.rb b/spec/data/run_context/cookbooks/include/recipes/default.rb
new file mode 100644
index 0000000..8d22994
--- /dev/null
+++ b/spec/data/run_context/cookbooks/include/recipes/default.rb
@@ -0,0 +1,24 @@
+module ::RanResources
+  def self.resources
+    @resources ||= []
+  end
+end
+class RunContextCustomResource < Chef::Resource
+  action :create do
+    ruby_block '4' do
+      block { RanResources.resources << 4 }
+    end
+    recipe_eval do
+      ruby_block '1' do
+        block { RanResources.resources << 1 }
+      end
+      include_recipe 'include::includee'
+      ruby_block '3' do
+        block { RanResources.resources << 3 }
+      end
+    end
+    ruby_block '5' do
+      block { RanResources.resources << 5 }
+    end
+  end
+end
diff --git a/spec/data/run_context/cookbooks/include/recipes/includee.rb b/spec/data/run_context/cookbooks/include/recipes/includee.rb
new file mode 100644
index 0000000..87bb7f1
--- /dev/null
+++ b/spec/data/run_context/cookbooks/include/recipes/includee.rb
@@ -0,0 +1,3 @@
+ruby_block '2' do
+  block { RanResources.resources << 2 }
+end
diff --git a/spec/data/trusted_certs/opscode.pem b/spec/data/trusted_certs/opscode.pem
index 37a3dd1..e421a4e 100644
--- a/spec/data/trusted_certs/opscode.pem
+++ b/spec/data/trusted_certs/opscode.pem
@@ -1,60 +1,57 @@
 -----BEGIN CERTIFICATE-----
-MIIFrDCCBJSgAwIBAgIQB1O/fCb6cEytJ4BP3HTbCTANBgkqhkiG9w0BAQUFADBI
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSIwIAYDVQQDExlE
-aWdpQ2VydCBTZWN1cmUgU2VydmVyIENBMB4XDTE0MDYxMDAwMDAwMFoXDTE1MDcw
-MTEyMDAwMFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO
-BgNVBAcTB1NlYXR0bGUxGzAZBgNVBAoTEkNoZWYgU29mdHdhcmUsIEluYzEWMBQG
-A1UEAwwNKi5vcHNjb2RlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAMm+rf2RcPGBlZoM+hI4BxlaHbdRg1GZJ/T46UWFOBnZFVP++TX/pyjDsvns
-xymcQywtoN/26+UIys6oWX1um9ikEokvf67LdsUeemQGFHFky8X1Ka2hVtKnxBhi
-XZfvyHDR4IyFWU9AwmhnqySzxqCtynUu8Gktx7JVfqbRFMZ186pDcSw8LoaqjTVG
-SzO7eNH2sM3doMueAHj7ITc2wUzmfa0Pdh+K8UoCn/HopU5LzycziJVPYvUkLT2m
-YCV7VWRc+kObZseHhZAbyaDk3RgPQ/eRMhytAgbruBHWDqNesNw+ZA70w856Oj2Y
-geO7JF+5V6WvkywrF8vydaoM2l8CAwEAAaOCAm8wggJrMB8GA1UdIwQYMBaAFJBx
-2zfrc8jv3NUeErY0uitaoKaSMB0GA1UdDgQWBBQK5zjZwbcmcMNLnI2h1ioAldEV
-ujCBygYDVR0RBIHCMIG/gg0qLm9wc2NvZGUuY29tghBjb3JwLm9wc2NvZGUuY29t
-ghIqLmNvcnAub3BzY29kZS5jb22CDyoubGVhcm5jaGVmLmNvbYISKi5jb3JwLmdl
-dGNoZWYuY29tgg0qLmdldGNoZWYuY29tggwqLm9wc2NvZGUudXOCC2dldGNoZWYu
-Y29tggtvcHNjb2RlLmNvbYIRYXBpLmJlcmtzaGVsZi5jb22CDWxlYXJuY2hlZi5j
-b22CCm9wc2NvZGUudXMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjBhBgNVHR8EWjBYMCqgKKAmhiRodHRwOi8vY3JsMy5kaWdp
-Y2VydC5jb20vc3NjYS1nNi5jcmwwKqAooCaGJGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0
-LmNvbS9zc2NhLWc2LmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsG
-AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMHgGCCsGAQUFBwEB
-BGwwajAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGCCsG
-AQUFBzAChjZodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTZWN1
-cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEA
-kgBpJ2t+St7SmWfeNU9EWAhy0NuUnRIi1jnqXdapfPmS6V/M0i2wP/p+crMty78e
-+3ieuF5s0GJBLs85Hikcl3SlrrbIBJxozov1TY6zeOi6+TCsdXer6t6iQKz36zno
-+k+T6lnMCyo9+pk1PhcAWyfo1Fz4xVOBVec/71VovFkkGD2//KB+sbDs+yh21N9M
-ReO7duj16rQSctfO9R2h65djBNlgz6hXY2nlw8/x3uFfZobXOxDrTcH6Z8HIslkE
-MiTXGix6zdqJaFRCWi+prnAztWs+jEy+v95VSEHPj3xpwZ9WjsxQN0kFA2EX61v/
-kGunmyhehGjblQRt7bpyiA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEjzCCA3egAwIBAgIQBp4dt3/PHfupevXlyaJANzANBgkqhkiG9w0BAQUFADBh
+MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
 MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
-QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEgxCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxIjAgBgNVBAMTGURpZ2lDZXJ0IFNlY3Vy
-ZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7V+Qh
-qdWbYDd+jqFhf4HiGsJ1ZNmRUAvkNkQkbjDSm3on+sJqrmpwCTi5IArIZRBKiKwx
-8tyS8mOhXYBjWYCSIxzm73ZKUDXJ2HE4ue3w5kKu0zgmeTD5IpTG26Y/QXiQ2N5c
-fml9+JAVOtChoL76srIZodgr0c6/a91Jq6OS/rWryME+7gEA2KlEuEJziMNh9atK
-gygK0tRJ+mqxzd9XLJTl4sqDX7e6YlwvaKXwwLn9K9HpH9gaYhW9/z2m98vv5ttl
-LyU47PvmIGZYljQZ0hXOIdMkzNkUb9j+Vcfnb7YPGoxJvinyulqagSY3JG/XSBJs
-Lln1nBi72fZo4t9FAgMBAAGjggFaMIIBVjASBgNVHRMBAf8ECDAGAQH/AgEAMA4G
-A1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6
-Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3Js
-My5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFo
-dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3Js
-MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
-aWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBSQcds363PI79zVHhK2NLorWqCmkjAf
-BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTANBgkqhkiG9w0BAQUFAAOC
-AQEAMM7RlVEArgYLoQ4CwBestn+PIPZAdXQczHixpE/q9NDEnaLegQcmH0CIUfAf
-z7dMQJnQ9DxxmHOIlywZ126Ej6QfnFog41FcsMWemWpPyGn3EP9OrRnZyVizM64M
-2ZYpnnGycGOjtpkWQh1l8/egHn3F1GUUsmKE1GxcCAzYbJMrtHZZitF//wPYwl24
-LyLWOPD2nGt9RuuZdPfrSg6ppgTre87wXGuYMVqYQOtpxAX0IKjKCDplbDgV9Vws
-slXkLGtB8L5cRspKKaBIXiDSRf8F3jSvcEuBOeLKB1d8tjHcISnivpcOd5AUUUDh
-v+PMGxmcJcqnBrJT3yOyzxIZow==
+QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg
+U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83
+nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd
+KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f
+/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX
+kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0
+/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C
+AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
+aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6
+Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1
+oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
+QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
+d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh
+xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
+CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl
+5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA
+8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC
+2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit
+c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0
+j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFDTCCA/WgAwIBAgIQBZ8R1sZP2Lbc8x554UUQ2DANBgkqhkiG9w0BAQsFADBN
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
+aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTQxMTEwMDAwMDAwWhcN
+MTcxMTE0MTIwMDAwWjBlMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
+bjEQMA4GA1UEBxMHU2VhdHRsZTEbMBkGA1UEChMSQ2hlZiBTb2Z0d2FyZSwgSW5j
+MRIwEAYDVQQDDAkqLmNoZWYuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC3xCIczkV10O5jTDpbd4YlPLC6kfnVoOkno2N/OOlcLQu3ulj/Lj1j4r6e
+2XthJLcFgTO+y+1/IKnnpLKDfkx1YngWEBXEBP+MrrpDUKKs053s45/bI9QBPISA
+tXgnYxMH9Glo6FWWd13TUq++OKGw1p1wazH64XK4MAf5y/lkmWXIWumNuO35ZqtB
+ME3wJISwVHzHB2CQjlDklt+Mb0APEiIFIZflgu9JNBYzLdvUtxiz15FUZQI7SsYL
+TfXOD1KBNMWqN8snG2e5gRAzB2D161DFvAZt8OiYUe+3QurNlTYVzeHv1ok6UqgM
+ZcLzg8m801rRip0D7FCGvMCU/ktdAgMBAAGjggHPMIIByzAfBgNVHSMEGDAWgBQP
+gGEcgjFh1S8o541GOLQs4cbZ4jAdBgNVHQ4EFgQUwldjw4Pb4HV+wxGZ7MSSRh+d
+pm4wHQYDVR0RBBYwFIIJKi5jaGVmLmlvggdjaGVmLmlvMA4GA1UdDwEB/wQEAwIF
+oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwawYDVR0fBGQwYjAvoC2g
+K4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nMy5jcmwwL6At
+oCuGKWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zc2NhLXNoYTItZzMuY3JsMEIG
+A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
+LmRpZ2ljZXJ0LmNvbS9DUFMwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhho
+dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNl
+cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQw
+DAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAvcTWenNuvvrhX2omm8LQ
+zWOuu8jqpoflACwD4lOSZ4TgOe4pQGCjXq8aRBD5k+goqQrPVf9lHnelUHFQac0Q
+5WT4YUmisUbF0S4uY5OGQymM52MvUWG4ODL4gaWhFvN+HAXrDPP/9iitsjV0QOnl
+CDq7Q4/XYRYW3opu5nLLbfW6v4QvF5yzZagEACGs7Vt32p6l391UcU8f6wiB3uMD
+eioCvjpv/+2YOUNlDPCM3uBubjUhHOwO817wBxXkzdk1OSRe4jzcw/uX6wL7birt
+fbaSkpilvVX529pSzB2Lvi9xWOoGMM578dpQ0h3PwhmmvKhhCWP+pI05k3oSkYCP
+ng==
 -----END CERTIFICATE-----
diff --git a/spec/functional/application_spec.rb b/spec/functional/application_spec.rb
index 00ff0f7..19a23e0 100644
--- a/spec/functional/application_spec.rb
+++ b/spec/functional/application_spec.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "chef/mixin/shell_out"
 
 describe Chef::Application do
   include Chef::Mixin::ShellOut
@@ -42,15 +42,15 @@ describe Chef::Application do
       Chef::Config[:ftp_proxy] = nil
       Chef::Config[:no_proxy] = nil
 
-      @app.configure_proxy_environment_variables
+      Chef::Config.export_proxies
     end
 
     it "saves built proxy to ENV which shell_out can use" do
       so = if windows?
-        shell_out("echo %http_proxy%")
-      else
-        shell_out("echo $http_proxy")
-      end
+             shell_out("echo %http_proxy%")
+           else
+             shell_out("echo $http_proxy")
+           end
 
       expect(so.stdout.chomp).to eq("http://proxy.example.org:8080")
     end
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg
new file mode 100644
index 0000000..a2d3e7b
Binary files /dev/null and b/spec/functional/assets/chocolatey_feed/test-A.1.0.nupkg differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg
new file mode 100644
index 0000000..9ce9445
Binary files /dev/null and b/spec/functional/assets/chocolatey_feed/test-A.1.5.nupkg differ
diff --git a/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg
new file mode 100644
index 0000000..250084d
Binary files /dev/null and b/spec/functional/assets/chocolatey_feed/test-A.2.0.nupkg differ
diff --git a/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg
new file mode 100644
index 0000000..f275c78
Binary files /dev/null and b/spec/functional/assets/chocolatey_feed/test-B.1.0.nupkg differ
diff --git a/spec/functional/audit/rspec_formatter_spec.rb b/spec/functional/audit/rspec_formatter_spec.rb
index 009374d..209694a 100644
--- a/spec/functional/audit/rspec_formatter_spec.rb
+++ b/spec/functional/audit/rspec_formatter_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Author:: Claire McQuin (<claire at getchef.com>)
+# Author:: Claire McQuin (<claire at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +18,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-require 'chef/audit/rspec_formatter'
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
+require "chef/audit/rspec_formatter"
 
 describe Chef::Audit::RspecFormatter do
   include RSpec::Support::InSubProcess
diff --git a/spec/functional/audit/runner_spec.rb b/spec/functional/audit/runner_spec.rb
index 4949428..54f014e 100644
--- a/spec/functional/audit/runner_spec.rb
+++ b/spec/functional/audit/runner_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-require 'tempfile'
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
+require "tempfile"
 
 ##
 # This functional test ensures that our runner can be setup to not interfere with existing RSpec
@@ -46,21 +46,15 @@ describe Chef::Audit::Runner do
     RSpec::Core::Sandbox.sandboxed { ex.run }
   end
 
-  before do
-    Chef::Config[:log_location] = stdout
-  end
-  
   describe "#run" do
 
     let(:audits) { {} }
     let(:run_context) { instance_double(Chef::RunContext, :events => events, :audits => audits) }
     let(:control_group_name) { "control_group_name" }
 
-    it "Correctly runs an empty controls block" do
-      in_sub_process do
-        runner.run
-      end
-    end
+    # Set cookbook path to include our parent, so that it will recognize this
+    # rspec file as one that should show up in the backtrace.
+    before(:each) { Chef::Config[:cookbook_path] = File.dirname(__FILE__) }
 
     shared_context "passing audit" do
       let(:audits) do
@@ -69,7 +63,7 @@ describe Chef::Audit::Runner do
             expect(2 - 2).to eq(0)
           end
         end
-        { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass)}
+        { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass) }
       end
     end
 
@@ -80,54 +74,44 @@ describe Chef::Audit::Runner do
             expect(2 - 1).to eq(0)
           end
         end
-        { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail)}
+        { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail) }
       end
     end
 
-    context "there is a single successful control" do
-      include_context "passing audit"
-      it "correctly runs" do
-        in_sub_process do
-          runner.run
-
-          expect(stdout.string).to match(/1 example, 0 failures/)
+    describe "log location is stdout" do
+      before do
+        allow(Chef::Log).to receive(:info) do |msg|
+          stdout.puts(msg)
         end
       end
-    end
 
-    context "there is a single failing control" do
-      include_context "failing audit"
-      it "correctly runs" do
+      it "Correctly runs an empty controls block" do
         in_sub_process do
           runner.run
-
-          expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
-          expect(stdout.string).to match(/1 example, 1 failure/)
-          expect(stdout.string).to match(/# control_group_name should fail/)
         end
       end
-    end
 
-    describe "log location is a file" do
-      let(:tmpfile) { Tempfile.new("audit") }
-      before do
-        Chef::Config[:log_location] = tmpfile.path
-      end
+      context "there is a single successful control" do
+        include_context "passing audit"
+        it "correctly runs" do
+          in_sub_process do
+            runner.run
 
-      after do
-        tmpfile.close
-        tmpfile.unlink
+            expect(stdout.string).to match(/1 example, 0 failures/)
+          end
+        end
       end
 
-      include_context "failing audit"
-      it "correctly runs" do
-        in_sub_process do
-          runner.run
+      context "there is a single failing control" do
+        include_context "failing audit"
+        it "correctly runs" do
+          in_sub_process do
+            runner.run
 
-          contents = tmpfile.read
-          expect(contents).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
-          expect(contents).to match(/1 example, 1 failure/)
-          expect(contents).to match(/# control_group_name should fail/)
+            expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
+            expect(stdout.string).to match(/1 example, 1 failure/)
+            expect(stdout.string).to match(/# control_group_name should fail/)
+          end
         end
       end
     end
diff --git a/spec/functional/dsl/reboot_pending_spec.rb b/spec/functional/dsl/reboot_pending_spec.rb
index 14dd941..c7a93c6 100644
--- a/spec/functional/dsl/reboot_pending_spec.rb
+++ b/spec/functional/dsl/reboot_pending_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,99 +22,84 @@ require "spec_helper"
 
 describe Chef::DSL::RebootPending, :windows_only do
   def run_ohai
-    ohai = Ohai::System.new
-    # Would be nice to limit this to platform/kernel/arch etc for Ohai 7
-    ohai.all_plugins
-    node.consume_external_attrs(ohai.data,{})
-
-    ohai
-  end
-
-  def registry_unsafe?
-    registry.value_exists?('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }) ||
-    registry.key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired')
-    registry.key_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired') ||
-    registry.key_exists?('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile')
+    node.consume_external_attrs(OHAI_SYSTEM.data, {})
   end
 
   let(:node) { Chef::Node.new }
-  let(:events) { Chef::EventDispatch::Dispatcher.new }
   let!(:ohai) { run_ohai } # Ensure we have necessary node data
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
   let(:recipe) { Chef::Recipe.new("a windows cookbook", "the windows recipe", run_context) }
   let(:registry) { Chef::Win32::Registry.new(run_context) }
 
   describe "reboot_pending?" do
+    let(:reg_key) { nil }
+    let(:original_set) { false }
 
-    describe "when there is nothing to indicate a reboot is pending" do
-      it "should return false" do
-        skip "Found existing registry keys" if registry_unsafe?
-        expect(recipe.reboot_pending?).to be_falsey
-      end
-    end
+    before(:all) { @any_flag = Hash.new }
+
+    after { @any_flag[reg_key] = original_set }
 
     describe 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations' do
+      let(:reg_key) { 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager' }
+      let(:original_set) { registry.value_exists?(reg_key, { :name => "PendingFileRenameOperations" }) }
+
       it "returns true if the registry value exists" do
-        skip "Found existing registry keys" if registry_unsafe?
-        registry.set_value('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager',
-            { :name => 'PendingFileRenameOperations', :type => :multi_string, :data => ['\??\C:\foo.txt|\??\C:\bar.txt'] })
+        skip "found existing registry key" if original_set
+        registry.set_value(reg_key,
+            { :name => "PendingFileRenameOperations", :type => :multi_string, :data => ['\??\C:\foo.txt|\??\C:\bar.txt'] })
 
         expect(recipe.reboot_pending?).to be_truthy
       end
 
       after do
-        unless registry_unsafe?
-          registry.delete_value('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' })
+        unless original_set
+          registry.delete_value(reg_key, { :name => "PendingFileRenameOperations" })
         end
       end
     end
 
-    describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' do
+    describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired' do
+      let(:reg_key) { 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired' }
+      let(:original_set) { registry.key_exists?(reg_key) }
+
       it "returns true if the registry key exists" do
-        skip "Found existing registry keys" if registry_unsafe?
-        registry.create_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired', false)
+        skip "found existing registry key" if original_set
+        pending "Permissions are limited to 'TrustedInstaller' by default"
+        registry.create_key(reg_key, false)
 
         expect(recipe.reboot_pending?).to be_truthy
       end
 
       after do
-        unless registry_unsafe?
-          registry.delete_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired', false)
+        unless original_set
+          registry.delete_key(reg_key, false)
         end
       end
     end
 
-    describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired' do
+    describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' do
+      let(:reg_key) { 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' }
+      let(:original_set) { registry.key_exists?(reg_key) }
+
       it "returns true if the registry key exists" do
-        pending "Permissions are limited to 'TrustedInstaller' by default"
-        skip "Found existing registry keys" if registry_unsafe?
-        registry.create_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired', false)
+        skip "found existing registry key" if original_set
+        registry.create_key(reg_key, false)
 
         expect(recipe.reboot_pending?).to be_truthy
       end
 
       after do
-        unless registry_unsafe?
-          registry.delete_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired', false)
+        unless original_set
+          registry.delete_key(reg_key, false)
         end
       end
     end
 
-    describe 'HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile\Flags' do
-      it "returns true if the registry key exists" do
-        skip "Found existing registry keys" if registry_unsafe?
-        registry.create_key('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile', true)
-        registry.set_value('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile',
-                    { :name => 'Flags', :type => :dword, :data => 3 })
-
-        expect(recipe.reboot_pending?).to be_truthy
-      end
-
-      after do
-        unless registry_unsafe?
-          registry.delete_value('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile', { :name => 'Flags' })
-          registry.delete_key('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile', false)
-        end
+    describe "when there is nothing to indicate a reboot is pending" do
+      it "should return false" do
+        skip "reboot pending" if @any_flag.any? { |_, v| v == true }
+        expect(recipe.reboot_pending?).to be_falsey
       end
     end
   end
diff --git a/spec/functional/dsl/registry_helper_spec.rb b/spec/functional/dsl/registry_helper_spec.rb
index df5b09f..d90d509 100644
--- a/spec/functional/dsl/registry_helper_spec.rb
+++ b/spec/functional/dsl/registry_helper_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,15 +25,13 @@ describe Chef::Resource::RegistryKey, :windows_only do
     ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root"
     ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch"
     ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-      reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous'
-      reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
+      reg["RootType1", Win32::Registry::REG_SZ] = "fibrous"
+      reg.write("Roots", Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
     end
 
     events = Chef::EventDispatch::Dispatcher.new
     node = Chef::Node.new
-    ohai = Ohai::System.new
-    ohai.all_plugins
-    node.consume_external_attrs(ohai.data,{})
+    node.consume_external_attrs(OHAI_SYSTEM.data, {})
     run_context = Chef::RunContext.new(node, {}, events)
     @resource = Chef::Resource.new("foo", run_context)
   end
@@ -44,7 +42,7 @@ describe Chef::Resource::RegistryKey, :windows_only do
     end
     it "returns true if registry has specified value" do
       values = @resource.registry_get_values("HKCU\\Software\\Root")
-      expect(values.include?({:name=>"RootType1",:type=>:string,:data=>"fibrous"})).to eq(true)
+      expect(values.include?({ :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
     end
     it "returns true if specified registry_has_subkey" do
       expect(@resource.registry_has_subkeys?("HKCU\\Software\\Root")).to eq(true)
@@ -54,10 +52,10 @@ describe Chef::Resource::RegistryKey, :windows_only do
       expect(subkeys.include?("Branch")).to eq(true)
     end
     it "returns true if registry_value_exists" do
-      expect(@resource.registry_value_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"})).to eq(true)
+      expect(@resource.registry_value_exists?("HKCU\\Software\\Root", { :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
     end
     it "returns true if data_value_exists" do
-      expect(@resource.registry_data_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"})).to eq(true)
+      expect(@resource.registry_data_exists?("HKCU\\Software\\Root", { :name => "RootType1", :type => :string, :data => "fibrous" })).to eq(true)
     end
   end
 end
diff --git a/spec/functional/event_loggers/windows_eventlog_spec.rb b/spec/functional/event_loggers/windows_eventlog_spec.rb
index 0723e7b..031405f 100644
--- a/spec/functional/event_loggers/windows_eventlog_spec.rb
+++ b/spec/functional/event_loggers/windows_eventlog_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Jay Mundrawala (<jdm at getchef.com>)
+# Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,60 +16,65 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'securerandom'
-require 'chef/event_loggers/windows_eventlog'
+require "spec_helper"
+require "securerandom"
+require "chef/event_loggers/windows_eventlog"
 if Chef::Platform.windows? and not Chef::Platform::windows_server_2003?
-  require 'win32/eventlog'
+  require "win32/eventlog"
   include Win32
 end
 
 describe Chef::EventLoggers::WindowsEventLogger, :windows_only, :not_supported_on_win2k3 do
-  let(:run_id)       { SecureRandom.uuid }
-  let(:version)      { SecureRandom.uuid }
-  let(:elapsed_time) { SecureRandom.random_number(100) }
+  def rand
+    random.rand(1 << 32).to_s
+  end
+
+  let(:random)       { Random.new }
+  let(:run_id)       { rand }
+  let(:version)      { rand }
+  let(:elapsed_time) { rand }
   let(:logger)       { Chef::EventLoggers::WindowsEventLogger.new }
   let(:flags)        { nil }
   let(:node)         { nil }
-  let(:run_status)   { double('Run Status', {run_id: run_id, elapsed_time: elapsed_time }) }
+  let(:run_status)   { double("Run Status", { run_id: run_id, elapsed_time: elapsed_time }) }
   let(:event_log)    { EventLog.new("Application") }
   let!(:offset)      { event_log.read_last_event.record_number }
-  let(:mock_exception) { double('Exception', {message: SecureRandom.uuid, backtrace:[SecureRandom.uuid, SecureRandom.uuid]})}
+  let(:mock_exception) { double("Exception", { message: rand, backtrace: [rand, rand] }) }
 
-  it 'is available' do
+  it "is available" do
     expect(Chef::EventLoggers::WindowsEventLogger.available?).to be_truthy
   end
 
-  it 'writes run_start event with event_id 10000 and contains version' do
+  it "writes run_start event with event_id 10000 and contains version" do
     logger.run_start(version)
 
-    expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10000 &&
+    expect(event_log.read(flags, offset).any? { |e| e.source == "Chef" && e.event_id == 10000 &&
                                                e.string_inserts[0].include?(version)}).to be_truthy
   end
 
-  it 'writes run_started event with event_id 10001 and contains the run_id' do
+  it "writes run_started event with event_id 10001 and contains the run_id" do
     logger.run_started(run_status)
 
-    expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10001 &&
+    expect(event_log.read(flags, offset).any? { |e| e.source == "Chef" && e.event_id == 10001 &&
                                                e.string_inserts[0].include?(run_id)}).to be_truthy
   end
 
-  it 'writes run_completed event with event_id 10002 and contains the run_id and elapsed time' do
+  it "writes run_completed event with event_id 10002 and contains the run_id and elapsed time" do
     logger.run_started(run_status)
     logger.run_completed(node)
 
-    expect(event_log.read(flags, offset).any? { |e| e.source == 'Chef' && e.event_id == 10002 &&
+    expect(event_log.read(flags, offset).any? { |e| e.source == "Chef" && e.event_id == 10002 &&
                                                 e.string_inserts[0].include?(run_id) &&
                                                 e.string_inserts[1].include?(elapsed_time.to_s)
     }).to be_truthy
   end
 
-  it 'writes run_failed event with event_id 10003 and contains the run_id, elapsed time, and exception info' do
+  it "writes run_failed event with event_id 10003 and contains the run_id, elapsed time, and exception info" do
     logger.run_started(run_status)
     logger.run_failed(mock_exception)
 
     expect(event_log.read(flags, offset).any? do |e|
-      e.source == 'Chef' && e.event_id == 10003 &&
+      e.source == "Chef" && e.event_id == 10003 &&
         e.string_inserts[0].include?(run_id) &&
         e.string_inserts[1].include?(elapsed_time.to_s) &&
         e.string_inserts[2].include?(mock_exception.class.name) &&
@@ -79,11 +84,11 @@ describe Chef::EventLoggers::WindowsEventLogger, :windows_only, :not_supported_o
     end).to be_truthy
   end
 
-  it 'writes run_failed event with event_id 10003 even when run_status is not set' do
+  it "writes run_failed event with event_id 10003 even when run_status is not set" do
     logger.run_failed(mock_exception)
 
     expect(event_log.read(flags, offset).any? do |e|
-      e.source == 'Chef' && e.event_id == 10003 &&
+      e.source == "Chef" && e.event_id == 10003 &&
         e.string_inserts[0].include?("UNKNOWN") &&
         e.string_inserts[1].include?("UNKNOWN") &&
         e.string_inserts[2].include?(mock_exception.class.name) &&
diff --git a/spec/functional/file_content_management/deploy_strategies_spec.rb b/spec/functional/file_content_management/deploy_strategies_spec.rb
index 8a995d0..7c54af3 100644
--- a/spec/functional/file_content_management/deploy_strategies_spec.rb
+++ b/spec/functional/file_content_management/deploy_strategies_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 shared_examples_for "a content deploy strategy" do
 
@@ -38,7 +38,6 @@ shared_examples_for "a content deploy strategy" do
   let(:content_deployer) { described_class.new }
   let(:target_file_path) { File.join(sandbox_dir, "cp-deploy-strategy-target-file.txt") }
 
-
   describe "creating the file" do
 
     ##
@@ -69,7 +68,7 @@ shared_examples_for "a content deploy strategy" do
 
     def ace_inherits?(ace)
       flags = ace.flags
-      (flags & masks::OBJECT_INHERIT_ACE) !=0
+      (flags & masks::OBJECT_INHERIT_ACE) != 0
     end
 
     let(:parent_inheritable_aces) do
@@ -126,7 +125,7 @@ shared_examples_for "a content deploy strategy" do
       security_descriptor_invariants.inject({}) do |prop_map, property|
         prop_map[property] = descriptor.send(property)
         prop_map
-       end
+      end
     end
 
     before do
@@ -180,7 +179,7 @@ describe Chef::FileContentManagement::Deploy::Cp do
       :uid,
       :gid,
       :mode,
-      :ino
+      :ino,
     ]
   end
 
@@ -188,7 +187,7 @@ describe Chef::FileContentManagement::Deploy::Cp do
     [
       :owner,
       :group,
-      :dacl
+      :dacl,
     ]
   end
 
@@ -202,7 +201,7 @@ describe Chef::FileContentManagement::Deploy::MvUnix, :unix_only do
     [
       :uid,
       :gid,
-      :mode
+      :mode,
     ]
   end
 
@@ -220,7 +219,7 @@ describe Chef::FileContentManagement::Deploy::MvWindows, :windows_only do
       [
        :owner,
        :group,
-       :dacl
+       :dacl,
       ]
     end
 
diff --git a/spec/functional/http/simple_spec.rb b/spec/functional/http/simple_spec.rb
index 36468b4..aeb7be7 100644
--- a/spec/functional/http/simple_spec.rb
+++ b/spec/functional/http/simple_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
 
 describe Chef::HTTP::Simple do
   include ChefHTTPShared
@@ -84,14 +84,14 @@ describe Chef::HTTP::Simple do
   context "when Chef::Log.level = :debug" do
     before do
       Chef::Log.level = :debug
-      @debug_log = ''
+      @debug_log = ""
       allow(Chef::Log).to receive(:debug) { |str| @debug_log << str }
     end
 
-    let(:source) { 'http://localhost:9000' }
+    let(:source) { "http://localhost:9000" }
 
     it "Logs the request and response for 200's but not the body" do
-      http_client.get('http://localhost:9000/nyan_cat.png')
+      http_client.get("http://localhost:9000/nyan_cat.png")
       expect(@debug_log).to match(/200/)
       expect(@debug_log).to match(/HTTP Request Header Data/)
       expect(@debug_log).to match(/HTTP Status and Header Data/)
@@ -101,7 +101,7 @@ describe Chef::HTTP::Simple do
     end
 
     it "Logs the request and response for 200 POST, but not the body" do
-      http_client.post('http://localhost:9000/posty', 'hithere')
+      http_client.post("http://localhost:9000/posty", "hithere")
       expect(@debug_log).to match(/200/)
       expect(@debug_log).to match(/HTTP Request Header Data/)
       expect(@debug_log).to match(/HTTP Status and Header Data/)
@@ -113,7 +113,7 @@ describe Chef::HTTP::Simple do
 
     it "Logs the request and response and bodies for 400 response" do
       expect do
-        http_client.get('http://localhost:9000/bad_request')
+        http_client.get("http://localhost:9000/bad_request")
       end.to raise_error(Net::HTTPServerException)
       expect(@debug_log).to match(/400/)
       expect(@debug_log).to match(/HTTP Request Header Data/)
@@ -126,7 +126,7 @@ describe Chef::HTTP::Simple do
 
     it "Logs the request and response and bodies for 400 POST response" do
       expect do
-        http_client.post('http://localhost:9000/bad_request', 'hithere')
+        http_client.post("http://localhost:9000/bad_request", "hithere")
       end.to raise_error(Net::HTTPServerException)
       expect(@debug_log).to match(/400/)
       expect(@debug_log).to match(/HTTP Request Header Data/)
diff --git a/spec/functional/knife/configure_spec.rb b/spec/functional/knife/configure_spec.rb
index 3bef18a..f1da2d6 100644
--- a/spec/functional/knife/configure_spec.rb
+++ b/spec/functional/knife/configure_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,18 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/knife/configure'
-require 'ohai'
+require "chef/knife/configure"
 
 describe "knife configure" do
   let (:ohai) do
-    o = Ohai::System.new
-    o.load_plugins
-    o.require_plugin 'os'
-    o.require_plugin 'hostname'
-    o
+    OHAI_SYSTEM
   end
 
   it "loads the fqdn from Ohai" do
     knife_configure = Chef::Knife::Configure.new
-    hostname_guess = ohai[:fqdn] || ohai[:machinename] || ohai[:hostname] || 'localhost'
+    hostname_guess = ohai[:fqdn] || ohai[:machinename] || ohai[:hostname] || "localhost"
     expect(knife_configure.guess_servername).to eql(hostname_guess)
   end
 end
diff --git a/spec/functional/knife/cookbook_delete_spec.rb b/spec/functional/knife/cookbook_delete_spec.rb
index 15ac8f5..a43e3a3 100644
--- a/spec/functional/knife/cookbook_delete_spec.rb
+++ b/spec/functional/knife/cookbook_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
 
 describe Chef::Knife::CookbookDelete do
   before(:all) do
@@ -32,7 +32,7 @@ describe Chef::Knife::CookbookDelete do
 
     Chef::Config[:node_name] = nil
     Chef::Config[:client_key] = nil
-    Chef::Config[:chef_server_url] = 'http://localhost:9000'
+    Chef::Config[:chef_server_url] = "http://localhost:9000"
   end
 
   after(:all) do
@@ -40,20 +40,30 @@ describe Chef::Knife::CookbookDelete do
   end
 
   context "when the cookbook doesn't exist" do
-    before do
-      @log_output = StringIO.new
-
-      Chef::Log.logger = Logger.new(@log_output)
-      Chef::Log.level = :debug
+    let(:log_output) { StringIO.new }
 
+    before do
       @knife.name_args = %w{no-such-cookbook}
-      @api.get("/cookbooks/no-such-cookbook", 404, Chef::JSONCompat.to_json({'error'=>'dear Tim, no. -Sent from my iPad'}))
+      @api.get("/cookbooks/no-such-cookbook", 404, Chef::JSONCompat.to_json({ "error" => "dear Tim, no. -Sent from my iPad" }))
+    end
+
+    around do |ex|
+      old_logger = Chef::Log.logger
+      old_level = Chef::Log.level
+      begin
+        Chef::Log.logger = Logger.new(log_output)
+        Chef::Log.level = :debug
+        ex.run
+      ensure
+        Chef::Log.logger = old_logger
+        Chef::Log.level = old_level
+      end
     end
 
     it "logs an error and exits" do
-      allow(@knife.ui).to receive(:stderr).and_return(@log_output)
-      expect {@knife.run}.to raise_error(SystemExit)
-      expect(@log_output.string).to match(/Cannot find a cookbook named no-such-cookbook to delete/)
+      allow(@knife.ui).to receive(:stderr).and_return(log_output)
+      expect { @knife.run }.to raise_error(SystemExit)
+      expect(log_output.string).to match(/Cannot find a cookbook named no-such-cookbook to delete/)
     end
 
   end
@@ -61,7 +71,7 @@ describe Chef::Knife::CookbookDelete do
   context "when there is only one version of a cookbook" do
     before do
       @knife.name_args = %w{obsolete-cookbook}
-      @cookbook_list = {'obsolete-cookbook' => { 'versions' => ['version' => '1.0.0']} }
+      @cookbook_list = { "obsolete-cookbook" => { "versions" => ["version" => "1.0.0"] } }
       @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
     end
 
@@ -102,9 +112,9 @@ describe Chef::Knife::CookbookDelete do
   context "when there are several versions of a cookbook" do
     before do
       @knife.name_args = %w{obsolete-cookbook}
-      versions = ['1.0.0', '1.1.0', '1.2.0']
-      with_version = lambda { |version| { 'version' => version } }
-      @cookbook_list = {'obsolete-cookbook' => { 'versions' => versions.map(&with_version) } }
+      versions = ["1.0.0", "1.1.0", "1.2.0"]
+      with_version = lambda { |version| { "version" => version } }
+      @cookbook_list = { "obsolete-cookbook" => { "versions" => versions.map(&with_version) } }
       @api.get("/cookbooks/obsolete-cookbook", 200, Chef::JSONCompat.to_json(@cookbook_list))
     end
 
diff --git a/spec/functional/knife/exec_spec.rb b/spec/functional/knife/exec_spec.rb
index 6262094..838d156 100644
--- a/spec/functional/knife/exec_spec.rb
+++ b/spec/functional/knife/exec_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
 
 describe Chef::Knife::Exec do
   before(:all) do
@@ -32,7 +32,7 @@ describe Chef::Knife::Exec do
 
     Chef::Config[:node_name] = nil
     Chef::Config[:client_key] = nil
-    Chef::Config[:chef_server_url] = 'http://localhost:9000'
+    Chef::Config[:chef_server_url] = "http://localhost:9000"
 
     $output = StringIO.new
   end
@@ -44,7 +44,7 @@ describe Chef::Knife::Exec do
   it "executes a script in the context of the chef-shell main context" do
     @node = Chef::Node.new
     @node.name("ohai-world")
-    response = {"rows" => [@node],"start" => 0,"total" => 1}
+    response = { "rows" => [@node], "start" => 0, "total" => 1 }
     @api.get(%r{^/search/node}, 200, Chef::JSONCompat.to_json(response))
     code = "$output.puts nodes.all"
     @knife.config[:exec] = code
diff --git a/spec/functional/knife/smoke_test.rb b/spec/functional/knife/smoke_test.rb
index 607e806..350644d 100644
--- a/spec/functional/knife/smoke_test.rb
+++ b/spec/functional/knife/smoke_test.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe "knife smoke tests" do
 
@@ -31,4 +31,12 @@ describe "knife smoke tests" do
     knife_cmd.error!
     expect(knife_cmd.stdout).to include(Chef::VERSION)
   end
+
+  it "can run and show help" do
+    knife_path = File.expand_path("../../bin/knife", CHEF_SPEC_DATA)
+    knife_cmd = Mixlib::ShellOut.new("#{knife_path} --help")
+    knife_cmd.run_command
+    knife_cmd.error!
+    expect(knife_cmd.stdout).to include("Usage")
+  end
 end
diff --git a/spec/functional/knife/ssh_spec.rb b/spec/functional/knife/ssh_spec.rb
index 5b8ad6f..a23220e 100644
--- a/spec/functional/knife/ssh_spec.rb
+++ b/spec/functional/knife/ssh_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
 
 describe Chef::Knife::Ssh do
 
@@ -31,58 +31,74 @@ describe Chef::Knife::Ssh do
     @server.stop
   end
 
+  let(:ssh_config) { Hash.new }
+  before do
+    allow(Net::SSH).to receive(:configuration_for).and_return(ssh_config)
+  end
+
+  # Force log level to info.
+  around do |ex|
+    old_level = Chef::Log.level
+    begin
+      Chef::Log.level = :info
+      ex.run
+    ensure
+      Chef::Log.level = old_level
+    end
+  end
+
   describe "identity file" do
     context "when knife[:ssh_identity_file] is set" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa"
       end
 
       it "uses the ssh_identity_file" do
         @knife.run
-        expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+        expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
       end
     end
 
     context "when knife[:ssh_identity_file] is set and frozen" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa".freeze
       end
 
       it "uses the ssh_identity_file" do
         @knife.run
-        expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+        expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
       end
     end
 
     context "when -i is provided" do
       before do
-        setup_knife(['-i ~/.ssh/aws.rsa', '*:*', 'uptime'])
+        setup_knife(["-i ~/.ssh/aws.rsa", "*:*", "uptime"])
         Chef::Config[:knife][:ssh_identity_file] = nil
       end
 
       it "should use the value on the command line" do
         @knife.run
-        expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+        expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
       end
 
       it "should override what is set in knife.rb" do
         Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/other.rsa"
         @knife.run
-        expect(@knife.config[:identity_file]).to eq("~/.ssh/aws.rsa")
+        expect(@knife.config[:ssh_identity_file]).to eq("~/.ssh/aws.rsa")
       end
     end
 
     context "when knife[:ssh_identity_file] is not provided]" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_identity_file] = nil
       end
 
       it "uses the default" do
         @knife.run
-        expect(@knife.config[:identity_file]).to eq(nil)
+        expect(@knife.config[:ssh_identity_file]).to eq(nil)
       end
     end
   end
@@ -90,7 +106,7 @@ describe Chef::Knife::Ssh do
   describe "port" do
     context "when -p 31337 is provided" do
       before do
-        setup_knife(['-p 31337', '*:*', 'uptime'])
+        setup_knife(["-p 31337", "*:*", "uptime"])
       end
 
       it "uses the ssh_port" do
@@ -103,7 +119,7 @@ describe Chef::Knife::Ssh do
   describe "user" do
     context "when knife[:ssh_user] is set" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_user] = "ubuntu"
       end
 
@@ -115,7 +131,7 @@ describe Chef::Knife::Ssh do
 
     context "when knife[:ssh_user] is set and frozen" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_user] = "ubuntu".freeze
       end
 
@@ -127,7 +143,7 @@ describe Chef::Knife::Ssh do
 
     context "when -x is provided" do
       before do
-        setup_knife(['-x ubuntu', '*:*', 'uptime'])
+        setup_knife(["-x ubuntu", "*:*", "uptime"])
         Chef::Config[:knife][:ssh_user] = nil
       end
 
@@ -145,7 +161,7 @@ describe Chef::Knife::Ssh do
 
     context "when knife[:ssh_user] is not provided]" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_user] = nil
       end
 
@@ -159,31 +175,31 @@ describe Chef::Knife::Ssh do
   describe "attribute" do
     context "when knife[:ssh_attribute] is set" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_attribute] = "ec2.public_hostname"
       end
 
       it "uses the ssh_attribute" do
         @knife.run
-        expect(@knife.config[:attribute]).to eq("ec2.public_hostname")
+        expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("ec2.public_hostname")
       end
     end
 
     context "when knife[:ssh_attribute] is not provided]" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_attribute] = nil
       end
 
       it "uses the default" do
         @knife.run
-        expect(@knife.config[:attribute]).to eq("fqdn")
+        expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn")
       end
     end
 
     context "when -a ec2.public_ipv4 is provided" do
       before do
-        setup_knife(['-a ec2.public_hostname', '*:*', 'uptime'])
+        setup_knife(["-a ec2.public_hostname", "*:*", "uptime"])
         Chef::Config[:knife][:ssh_attribute] = nil
       end
 
@@ -196,7 +212,7 @@ describe Chef::Knife::Ssh do
         # This is the setting imported from knife.rb
         Chef::Config[:knife][:ssh_attribute] = "fqdn"
         # Then we run knife with the -a flag, which sets the above variable
-        setup_knife(['-a ec2.public_hostname', '*:*', 'uptime'])
+        setup_knife(["-a ec2.public_hostname", "*:*", "uptime"])
         @knife.run
         expect(@knife.config[:attribute]).to eq("ec2.public_hostname")
       end
@@ -206,7 +222,7 @@ describe Chef::Knife::Ssh do
   describe "gateway" do
     context "when knife[:ssh_gateway] is set" do
       before do
-        setup_knife(['*:*', 'uptime'])
+        setup_knife(["*:*", "uptime"])
         Chef::Config[:knife][:ssh_gateway] = "user at ec2.public_hostname"
       end
 
@@ -219,7 +235,7 @@ describe Chef::Knife::Ssh do
 
     context "when -G user at ec2.public_hostname is provided" do
       before do
-        setup_knife(['-G user at ec2.public_hostname', '*:*', 'uptime'])
+        setup_knife(["-G user at ec2.public_hostname", "*:*", "uptime"])
         Chef::Config[:knife][:ssh_gateway] = nil
       end
 
@@ -232,7 +248,7 @@ describe Chef::Knife::Ssh do
 
     context "when the gateway requires a password" do
       before do
-        setup_knife(['-G user at ec2.public_hostname', '*:*', 'uptime'])
+        setup_knife(["-G user at ec2.public_hostname", "*:*", "uptime"])
         Chef::Config[:knife][:ssh_gateway] = nil
         allow(@knife.session).to receive(:via) do |host, user, options|
           raise Net::SSH::AuthenticationFailed unless options[:password]
@@ -246,7 +262,7 @@ describe Chef::Knife::Ssh do
     end
   end
 
-  def setup_knife(params=[])
+  def setup_knife(params = [])
     @knife = Chef::Knife::Ssh.new(params)
     # We explicitly avoid running #configure_chef, which would read a knife.rb
     # if available, but #merge_configs (which is called by #configure_chef) is
@@ -258,7 +274,7 @@ describe Chef::Knife::Ssh do
 
     Chef::Config[:node_name] = nil
     Chef::Config[:client_key] = nil
-    Chef::Config[:chef_server_url] = 'http://localhost:9000'
+    Chef::Config[:chef_server_url] = "http://localhost:9000"
 
     @api.get("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0", 200) {
       %({"total":1, "start":0, "rows":[{"name":"i-xxxxxxxx", "json_class":"Chef::Node", "automatic":{"fqdn":"the.fqdn", "ec2":{"public_hostname":"the_public_hostname"}},"recipes":[]}]})
diff --git a/spec/functional/mixin/powershell_out_spec.rb b/spec/functional/mixin/powershell_out_spec.rb
new file mode 100644
index 0000000..293e955
--- /dev/null
+++ b/spec/functional/mixin/powershell_out_spec.rb
@@ -0,0 +1,43 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/powershell_out"
+
+describe Chef::Mixin::PowershellOut, windows_only: true do
+  include Chef::Mixin::PowershellOut
+
+  describe "#powershell_out" do
+    it "runs a powershell command and collects stdout" do
+      expect(powershell_out("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+    end
+
+    it "does not raise exceptions when the command is invalid" do
+      powershell_out("this-is-not-a-valid-command").run_command
+    end
+  end
+
+  describe "#powershell_out!" do
+    it "runs a powershell command and collects stdout" do
+      expect(powershell_out!("get-process").run_command.stdout).to match /Handles\s+NPM\(K\)\s+PM\(K\)\s+WS\(K\)\s+VM\(M\)\s+CPU\(s\)\s+Id\s+ProcessName/
+    end
+
+    it "raises exceptions when the command is invalid" do
+      expect { powershell_out!("this-is-not-a-valid-command").run_command }.to raise_exception(Mixlib::ShellOut::ShellCommandFailed)
+    end
+  end
+end
diff --git a/spec/functional/mixin/shell_out_spec.rb b/spec/functional/mixin/shell_out_spec.rb
index 35e5b30..48f6b7d 100644
--- a/spec/functional/mixin/shell_out_spec.rb
+++ b/spec/functional/mixin/shell_out_spec.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Mixin::ShellOut do
   include Chef::Mixin::ShellOut
@@ -24,24 +24,24 @@ describe Chef::Mixin::ShellOut do
     describe "when environment['LC_ALL'] is not set" do
       it "should use the default shell_out setting" do
         cmd = if windows?
-          shell_out_with_systems_locale('echo %LC_ALL%')
-        else
-          shell_out_with_systems_locale('echo $LC_ALL')
-        end
+                shell_out_with_systems_locale("echo %LC_ALL%")
+              else
+                shell_out_with_systems_locale("echo $LC_ALL")
+              end
 
-        expect(cmd.stdout.chomp).to match_environment_variable('LC_ALL')
+        expect(cmd.stdout.chomp).to match_environment_variable("LC_ALL")
       end
     end
 
     describe "when environment['LC_ALL'] is set" do
       it "should use the option's setting" do
         cmd = if windows?
-          shell_out_with_systems_locale('echo %LC_ALL%', :environment => {'LC_ALL' => 'POSIX'})
-        else
-          shell_out_with_systems_locale('echo $LC_ALL', :environment => {'LC_ALL' => 'POSIX'})
-        end
+                shell_out_with_systems_locale("echo %LC_ALL%", :environment => { "LC_ALL" => "POSIX" })
+              else
+                shell_out_with_systems_locale("echo $LC_ALL", :environment => { "LC_ALL" => "POSIX" })
+              end
 
-        expect(cmd.stdout.chomp).to eq 'POSIX'
+        expect(cmd.stdout.chomp).to eq "POSIX"
       end
     end
   end
diff --git a/spec/functional/notifications_spec.rb b/spec/functional/notifications_spec.rb
index a02fdff..1b1ef83 100644
--- a/spec/functional/notifications_spec.rb
+++ b/spec/functional/notifications_spec.rb
@@ -1,6 +1,5 @@
-require 'spec_helper'
-require 'chef/recipe'
-
+require "spec_helper"
+require "chef/recipe"
 
 # The goal of these tests is to make sure that loading resources from a file creates the necessary notifications.
 # Then once converge has started, both immediate and delayed notifications are called as the resources are converged.
@@ -74,6 +73,76 @@ describe "Notifications" do
     runner.converge
   end
 
+  it "should notify from one resource to another before" do
+    log_resource = recipe.declare_resource(:log, "log") do
+      message "This is a log message"
+      action :write
+      notifies :install, "package[vim]", :before
+    end
+    update_action(log_resource, 2)
+
+    package_resource = recipe.declare_resource(:package, "vim") do
+      action :nothing
+    end
+
+    actions = []
+    [ log_resource, package_resource ].each do |resource|
+      allow(resource).to receive(:run_action).and_wrap_original do |m, action, notification_type, notifying_resource|
+        actions << { resource: resource.to_s, action: action }
+        actions[-1][:why_run] = Chef::Config[:why_run] if Chef::Config[:why_run]
+        actions[-1][:notification_type] = notification_type if notification_type
+        actions[-1][:notifying_resource] = notifying_resource.to_s if notifying_resource
+        m.call(action, notification_type, notifying_resource)
+      end
+    end
+
+    runner.converge
+
+    expect(actions).to eq [
+      # First it runs why-run to check if the resource would update
+      { resource: log_resource.to_s,     action: :write,   why_run: true },
+      # Then it runs the before action
+      { resource: package_resource.to_s, action: :install, notification_type: :before, notifying_resource: log_resource.to_s },
+      # Then it runs the actual action
+      { resource: log_resource.to_s,     action: :write },
+      { resource: package_resource.to_s, action: :nothing },
+    ]
+  end
+
+  it "should not notify from one resource to another before if the resource is not updated" do
+    log_resource = recipe.declare_resource(:log, "log") do
+      message "This is a log message"
+      action :write
+      notifies :install, "package[vim]", :before
+    end
+
+    package_resource = recipe.declare_resource(:package, "vim") do
+      action :nothing
+    end
+
+    actions = []
+    [ log_resource, package_resource ].each do |resource|
+      allow(resource).to receive(:run_action).and_wrap_original do |m, action, notification_type, notifying_resource|
+        actions << { resource: resource.to_s, action: action }
+        actions[-1][:why_run] = Chef::Config[:why_run] if Chef::Config[:why_run]
+        actions[-1][:notification_type] = notification_type if notification_type
+        actions[-1][:notifying_resource] = notifying_resource.to_s if notifying_resource
+        m.call(action, notification_type, notifying_resource)
+      end
+    end
+
+    runner.converge
+
+    expect(actions).to eq [
+      # First it runs why-run to check if the resource would update
+      { resource: log_resource.to_s,     action: :write, why_run: true },
+      # Then it does NOT run the before action
+      # Then it runs the actual action
+      { resource: log_resource.to_s,     action: :write },
+      { resource: package_resource.to_s, action: :nothing },
+    ]
+  end
+
   it "should notify from one resource to another delayed" do
     log_resource = recipe.declare_resource(:log, "log") do
       message "This is a log message"
@@ -94,7 +163,7 @@ describe "Notifications" do
 
     runner.converge
   end
-  
+
   describe "when one resource is defined lazily" do
 
     it "subscribes to a resource defined in a ruby block" do
@@ -158,10 +227,10 @@ describe "Notifications" do
   end
 
   # Mocks having the provider run successfully and update the resource
-  def update_action(resource)
+  def update_action(resource, times = 1)
     p = Chef::Provider.new(resource, run_context)
-    expect(resource).to receive(:provider_for_action).and_return(p)
-    expect(p).to receive(:run_action) {
+    expect(resource).to receive(:provider_for_action).exactly(times).times.and_return(p)
+    expect(p).to receive(:run_action).exactly(times).times {
       resource.updated_by_last_action(true)
     }
   end
diff --git a/spec/functional/provider/remote_file/cache_control_data_spec.rb b/spec/functional/provider/remote_file/cache_control_data_spec.rb
index 41f228a..c56787e 100755
--- a/spec/functional/provider/remote_file/cache_control_data_spec.rb
+++ b/spec/functional/provider/remote_file/cache_control_data_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
 
 describe Chef::Provider::RemoteFile::CacheControlData do
 
   before do
-    @original_config = Chef::Config.hash_dup    
+    @original_config = Chef::Config.hash_dup
   end
 
   after do
-    Chef::Config.configuration = @original_config if @original_config    
+    Chef::Config.configuration = @original_config if @original_config
   end
-  
+
   before(:each) do
     Chef::Config[:file_cache_path] = Dir.mktmpdir
   end
@@ -38,7 +38,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
   end
 
   let(:uri) { URI.parse("http://www.bing.com/robots.txt") }
-  
+
   describe "when the cache control data save method is invoked" do
 
     subject(:cache_control_data) do
@@ -66,7 +66,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
       saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
       expect(saved_cache_control_data.etag).to eq(cache_control_data.etag)
       expect(saved_cache_control_data.mtime).to eq(cache_control_data.mtime)
-      expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)  
+      expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
     end
 
     # Cover the very long remote file path case -- see CHEF-4422 where
@@ -75,7 +75,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
     # file system API's on both Windows and Unix systems.
     context "when the length of the uri exceeds the path length limits for the local file system" do
       let(:uri_exceeds_file_system_limit) do
-        URI.parse("http://www.bing.com/" + ('0' * 1024))
+        URI.parse("http://www.bing.com/" + ("0" * 1024))
       end
 
       let(:uri) { uri_exceeds_file_system_limit }
@@ -91,11 +91,10 @@ describe Chef::Provider::RemoteFile::CacheControlData do
         saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum)
         expect(saved_cache_control_data.etag).to eq(cache_control_data.etag)
         expect(saved_cache_control_data.mtime).to eq(cache_control_data.mtime)
-        expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)  
+        expect(saved_cache_control_data.checksum).to eq(cache_control_data.checksum)
       end
 
     end
   end
 
 end
-
diff --git a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
index b3c2333..892e108 100644
--- a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
+++ b/spec/functional/provider/whyrun_safe_ruby_block_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::WhyrunSafeRubyBlock do
   let(:node) { Chef::Node.new }
@@ -43,7 +43,7 @@ describe Chef::Resource::WhyrunSafeRubyBlock do
     end
 
     it "updates the evil laugh, even in why-run mode" do
-      new_resource.run_action(new_resource.action)
+      Array(new_resource.action).each { |action| new_resource.run_action(action) }
       expect($evil_global_evil_laugh).to eq(:mwahahaha)
       expect(new_resource).to be_updated
     end
diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb
index 7630216..4b77c40 100644
--- a/spec/functional/rebooter_spec.rb
+++ b/spec/functional/rebooter_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Chris Doherty <cdoherty at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Platform::Rebooter do
 
@@ -24,7 +24,7 @@ describe Chef::Platform::Rebooter do
     {
       :delay_mins => 5,
       :requested_by => "reboot resource functional test",
-      :reason => "rebooter spec test"
+      :reason => "rebooter spec test",
     }
   end
 
@@ -43,8 +43,8 @@ describe Chef::Platform::Rebooter do
 
   let(:expected) do
     {
-      :windows => 'shutdown /r /t 5 /c "rebooter spec test"',
-      :linux => 'shutdown -r +5 "rebooter spec test"'
+      :windows => 'shutdown /r /t 300 /c "rebooter spec test"',
+      :linux => 'shutdown -r +5 "rebooter spec test"',
     }
   end
 
@@ -68,9 +68,9 @@ describe Chef::Platform::Rebooter do
         run_context.cancel_reboot
       end
 
-      shared_context 'test a reboot method' do
+      shared_context "test a reboot method" do
         def test_rebooter_method(method_sym, is_windows, expected_reboot_str)
-          allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
+          allow(ChefConfig).to receive(:windows?).and_return(is_windows)
           expect(rebooter).to receive(:shell_out!).once.with(expected_reboot_str)
           expect(rebooter).to receive(method_sym).once.and_call_original
           rebooter.send(method_sym, run_context.node)
@@ -78,25 +78,25 @@ describe Chef::Platform::Rebooter do
       end
 
       describe 'when using #reboot_if_needed!' do
-        include_context 'test a reboot method'
+        include_context "test a reboot method"
 
-        it 'should produce the correct string on Windows' do
+        it "should produce the correct string on Windows" do
           test_rebooter_method(:reboot_if_needed!, true, expected[:windows])
         end
 
-        it 'should produce the correct (Linux-specific) string on non-Windows' do
+        it "should produce the correct (Linux-specific) string on non-Windows" do
           test_rebooter_method(:reboot_if_needed!, false, expected[:linux])
         end
       end
 
       describe 'when using #reboot!' do
-        include_context 'test a reboot method'
+        include_context "test a reboot method"
 
-        it 'should produce the correct string on Windows' do
+        it "should produce the correct string on Windows" do
           test_rebooter_method(:reboot!, true, expected[:windows])
         end
 
-        it 'should produce the correct (Linux-specific) string on non-Windows' do
+        it "should produce the correct (Linux-specific) string on non-Windows" do
           test_rebooter_method(:reboot!, false, expected[:linux])
         end
       end
diff --git a/spec/functional/resource/aix_service_spec.rb b/spec/functional/resource/aix_service_spec.rb
index 9dec87d..5fff3e0 100755
--- a/spec/functional/resource/aix_service_spec.rb
+++ b/spec/functional/resource/aix_service_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,24 +17,24 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 shared_examples "src service" do
 
   include Chef::Mixin::ShellOut
 
   def service_should_be_started
-    expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("active")
+    expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ").last).to eq("active")
   end
 
   def service_should_be_stopped
-    expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ').last).to eq("inoperative")
+    expect(shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ").last).to eq("inoperative")
   end
 
   def get_service_pid
-    args = shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(' ')
+    args = shell_out!("lssrc -a | grep #{new_resource.service_name}").stdout.split(" ")
     if args.length == 3
       args[1]
     else
@@ -94,7 +94,6 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
       shell_out!("rmssys -s ctestsys")
     end
 
-
     let(:new_resource) do
       new_resource = Chef::Resource::Service.new("ctestsys", run_context)
       new_resource
@@ -108,8 +107,8 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
     it_behaves_like "src service"
   end
 
-
-  describe "When service is a group" do
+  # Cannot run this test on a WPAR
+  describe "When service is a group", :not_wpar do
     before(:all) do
       script_dir = File.join(File.dirname(__FILE__), "/../assets/")
       shell_out!("mkssys -s ctestsys -p #{script_dir}/testchefsubsys -u #{get_user_id} -S -n 15 -f 9 -R -Q -G ctestgrp")
diff --git a/spec/functional/resource/aixinit_service_spec.rb b/spec/functional/resource/aixinit_service_spec.rb
index 19b65ca..bf50046 100755
--- a/spec/functional/resource/aixinit_service_spec.rb
+++ b/spec/functional/resource/aixinit_service_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
-require 'fileutils'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
+require "fileutils"
 
 describe Chef::Resource::Service, :requires_root, :aix_only do
 
@@ -29,17 +29,17 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
   # Platform specific validation routines.
   def service_should_be_started(file_name)
     # The existence of this file indicates that the service was started.
-    expect(File.exists?("/tmp/#{file_name}")).to be_truthy
+    expect(File.exists?("#{Dir.tmpdir}/#{file_name}")).to be_truthy
   end
 
   def service_should_be_stopped(file_name)
-    expect(File.exists?("/tmp/#{file_name}")).to be_falsey
+    expect(File.exists?("#{Dir.tmpdir}/#{file_name}")).to be_falsey
   end
 
   def valide_symlinks(expected_output, run_level = nil, status = nil, priority = nil)
     directory = []
-    if priority.is_a?Hash
-      priority.each do |level,o|
+    if priority.is_a? Hash
+      priority.each do |level, o|
         directory << "/etc/rc.d/rc#{level}.d/#{(o[0] == :start ? 'S' : 'K')}#{o[1]}#{new_resource.service_name}"
       end
       directory
@@ -51,7 +51,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
   end
 
   def delete_test_files
-    files = Dir.glob("/tmp/chefinit[a-z_]*.txt")
+    files = Dir.glob("#{Dir.tmpdir}/chefinit[a-z_]*.txt")
     File.delete(*files)
   end
 
@@ -59,7 +59,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
   let(:new_resource) do
     new_resource = Chef::Resource::Service.new("chefinittest", run_context)
     new_resource.provider Chef::Provider::Service::AixInit
-    new_resource.supports({:status => true, :restart => true, :reload => true})
+    new_resource.supports({ :status => true, :restart => true, :reload => true })
     new_resource
   end
 
@@ -70,7 +70,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
 
   before(:all) do
     File.delete("/etc/rc.d/init.d/chefinittest") if File.exists?("/etc/rc.d/init.d/chefinittest")
-    FileUtils.cp("#{File.join(File.dirname(__FILE__), "/../assets/chefinittest")}",  "/etc/rc.d/init.d/chefinittest")
+    FileUtils.cp("#{File.join(File.dirname(__FILE__), "/../assets/chefinittest")}", "/etc/rc.d/init.d/chefinittest")
   end
 
   after(:all) do
@@ -130,7 +130,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
     context "when the service doesn't set a priority" do
       it "creates symlink with status S" do
         new_resource.run_action(:enable)
-        valide_symlinks(["/etc/rc.d/rc2.d/Schefinittest"],2,'S')
+        valide_symlinks(["/etc/rc.d/rc2.d/Schefinittest"], 2, "S")
       end
     end
 
@@ -141,19 +141,19 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
 
       it "creates a symlink with status S and a priority" do
         new_resource.run_action(:enable)
-        valide_symlinks(["/etc/rc.d/rc2.d/S75chefinittest"], 2,'S',75)
+        valide_symlinks(["/etc/rc.d/rc2.d/S75chefinittest"], 2, "S", 75)
       end
     end
 
     context "when the service sets complex priorities (hash)" do
       before do
-        priority = {2 => [:start, 20], 3 => [:stop, 10]}
+        priority = { 2 => [:start, 20], 3 => [:stop, 10] }
         new_resource.priority(priority)
       end
 
       it "create symlink with status start (S) or stop (K) and a priority " do
         new_resource.run_action(:enable)
-        valide_symlinks(["/etc/rc.d/rc2.d/S20chefinittest", "/etc/rc.d/rc3.d/K10chefinittest"], 2,'S',new_resource.priority)
+        valide_symlinks(["/etc/rc.d/rc2.d/S20chefinittest", "/etc/rc.d/rc3.d/K10chefinittest"], 2, "S", new_resource.priority)
       end
     end
   end
@@ -171,7 +171,7 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
 
       it "creates symlink with status K" do
         new_resource.run_action(:disable)
-        valide_symlinks(["/etc/rc.d/rc2.d/Kchefinittest"], 2,'K')
+        valide_symlinks(["/etc/rc.d/rc2.d/Kchefinittest"], 2, "K")
       end
     end
 
@@ -187,13 +187,13 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
 
       it "creates a symlink with status K and a priority" do
         new_resource.run_action(:disable)
-        valide_symlinks(["/etc/rc.d/rc2.d/K25chefinittest"], 2,'K',25)
+        valide_symlinks(["/etc/rc.d/rc2.d/K25chefinittest"], 2, "K", 25)
       end
     end
 
     context "when the service sets complex priorities (hash)" do
       before do
-        @priority = {2 => [:stop, 20], 3 => [:start, 10]}
+        @priority = { 2 => [:stop, 20], 3 => [:start, 10] }
         new_resource.priority(@priority)
         File.symlink("/etc/rc.d/init.d/chefinittest", "/etc/rc.d/rc2.d/Schefinittest")
       end
@@ -204,8 +204,8 @@ describe Chef::Resource::Service, :requires_root, :aix_only do
 
       it "create symlink with status stop (K) and a priority " do
         new_resource.run_action(:disable)
-        valide_symlinks(["/etc/rc.d/rc2.d/K80chefinittest"], 2,'K',80)
+        valide_symlinks(["/etc/rc.d/rc2.d/K80chefinittest"], 2, "K", 80)
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/spec/functional/resource/base.rb b/spec/functional/resource/base.rb
index 10b26f9..38175e8 100644
--- a/spec/functional/resource/base.rb
+++ b/spec/functional/resource/base.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,6 @@
 # limitations under the License.
 #
 
-
 def run_context
   @run_context ||= begin
     node = Chef::Node.new
@@ -27,4 +26,3 @@ def run_context
     Chef::RunContext.new(node, {}, events)
   end
 end
-
diff --git a/spec/functional/resource/bash_spec.rb b/spec/functional/resource/bash_spec.rb
index 209ec4a..13ffac5 100644
--- a/spec/functional/resource/bash_spec.rb
+++ b/spec/functional/resource/bash_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
+require "spec_helper"
+require "functional/resource/base"
 
 describe Chef::Resource::Bash, :unix_only do
   let(:code) { "echo hello" }
@@ -28,7 +28,7 @@ describe Chef::Resource::Bash, :unix_only do
   }
 
   describe "when setting the command attribute" do
-    let (:command) { 'wizard racket' }
+    let (:command) { "wizard racket" }
 
     # in Chef-12 the `command` attribute is largely useless, but does set the identity attribute
     # so that notifications need to target the value of the command.  it will not run the `command`
@@ -81,7 +81,7 @@ describe Chef::Resource::Bash, :unix_only do
   end
 
   it "times out when a timeout is set on the resource" do
-    resource.code 'sleep 600'
+    resource.code "sleep 600"
     resource.timeout 0.1
     expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
   end
diff --git a/spec/functional/resource/batch_spec.rb b/spec/functional/resource/batch_spec.rb
index 39133fd..e4fc642 100644
--- a/spec/functional/resource/batch_spec.rb
+++ b/spec/functional/resource/batch_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::WindowsScript::Batch, :windows_only do
   include_context Chef::Resource::WindowsScript
 
-  let(:output_command) { ' > ' }
+  let(:output_command) { " > " }
 
-  let (:architecture_command) { '@echo %PROCESSOR_ARCHITECTURE%' }
+  let (:architecture_command) { "@echo %PROCESSOR_ARCHITECTURE%" }
 
   it_behaves_like "a Windows script running on Windows"
 
diff --git a/spec/functional/resource/bff_spec.rb b/spec/functional/resource/bff_spec.rb
index b969254..e7f7540 100644
--- a/spec/functional/resource/bff_spec.rb
+++ b/spec/functional/resource/bff_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Prabhu Das (<prabhu.das at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 # Run the test only for AIX platform.
-describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform] != 'aix' do
+describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform] != "aix" do
   include Chef::Mixin::ShellOut
 
   let(:new_resource) do
@@ -39,11 +39,10 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
     !::File.exists?("/usr/PkgA/bin/acommand")
   end
 
-
   before(:all) do
     @pkg_name = "PkgA.rte"
-    @pkg_path = "/tmp/PkgA.1.0.0.0.bff"
-    FileUtils.cp 'spec/functional/assets/PkgA.1.0.0.0.bff' , @pkg_path
+    @pkg_path = "#{Dir.tmpdir}/PkgA.1.0.0.0.bff"
+    FileUtils.cp "spec/functional/assets/PkgA.1.0.0.0.bff" , @pkg_path
   end
 
   after(:all) do
@@ -70,15 +69,15 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
 
     after(:each) do
       shell_out("installp -u #{@pkg_name}")
-      FileUtils.rm "/tmp/installp.log"
+      FileUtils.rm "#{Dir.tmpdir}/installp.log"
     end
   end
 
   context "package upgrade action" do
     before(:each) do
       shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}")
-      @pkg_path = "/tmp/PkgA.2.0.0.0.bff"
-      FileUtils.cp 'spec/functional/assets/PkgA.2.0.0.0.bff' , @pkg_path
+      @pkg_path = "#{Dir.tmpdir}/PkgA.2.0.0.0.bff"
+      FileUtils.cp "spec/functional/assets/PkgA.2.0.0.0.bff" , @pkg_path
     end
 
     it "should upgrade package" do
@@ -115,8 +114,7 @@ describe Chef::Resource::BffPackage, :requires_root, :external => ohai[:platform
     end
 
     after(:each) do
-      FileUtils.rm "/tmp/installp.log"
+      FileUtils.rm "#{Dir.tmpdir}/installp.log"
     end
   end
 end
-
diff --git a/spec/functional/resource/chocolatey_package_spec.rb b/spec/functional/resource/chocolatey_package_spec.rb
new file mode 100644
index 0000000..e442008
--- /dev/null
+++ b/spec/functional/resource/chocolatey_package_spec.rb
@@ -0,0 +1,124 @@
+#
+# Author:: Matt Wrock (<matt at mattwrock.com>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "spec_helper"
+require "chef/mixin/powershell_out"
+
+describe Chef::Resource::ChocolateyPackage, :windows_only do
+  include Chef::Mixin::PowershellOut
+
+  before(:all) do
+    powershell_out!("iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))")
+    unless ENV["PATH"] =~ /chocolatey\\bin/
+      ENV["PATH"] = "C:\\ProgramData\\chocolatey\\bin;#{ENV["PATH"]}"
+    end
+  end
+
+  let(:package_name) { "test-A" }
+  let(:package_list) { proc { powershell_out!("choco list -lo -r #{Array(package_name).join(' ')}").stdout.chomp } }
+  let(:package_source) { File.join(CHEF_SPEC_ASSETS, "chocolatey_feed") }
+
+  subject do
+    new_resource = Chef::Resource::ChocolateyPackage.new("test choco package", run_context)
+    new_resource.package_name package_name
+    new_resource.source package_source if package_source
+    new_resource
+  end
+
+  context "installing a package" do
+    after { Chef::Resource::ChocolateyPackage.new(package_name, run_context).run_action(:remove) }
+
+    it "installs the latest version" do
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|2.0")
+    end
+
+    it "does not install if already installed" do
+      subject.run_action(:install)
+      subject.run_action(:install)
+      expect(subject).not_to be_updated_by_last_action
+    end
+
+    it "installs version given" do
+      subject.version "1.0"
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|1.0")
+    end
+
+    it "installs new version if one is already installed" do
+      subject.version "1.0"
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|1.0")
+
+      subject.version "2.0"
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|2.0")
+    end
+
+    context "installing multiple packages" do
+      let(:package_name) { [ "test-A", "test-B" ] }
+
+      it "installs both packages" do
+        subject.run_action(:install)
+        expect(package_list.call).to eq("test-A|2.0\r\ntest-B|1.0")
+      end
+    end
+
+    it "raises if package is not found" do
+      subject.package_name "blah"
+      expect { subject.run_action(:install) }.to raise_error Chef::Exceptions::Package
+    end
+
+    it "raises if package version is not found" do
+      subject.version "3.0"
+      expect { subject.run_action(:install) }.to raise_error Chef::Exceptions::Package
+    end
+  end
+
+  context "upgrading a package" do
+    after { Chef::Resource::ChocolateyPackage.new(package_name, run_context).run_action(:remove) }
+
+    it "upgrades to a specific version" do
+      subject.version "1.0"
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|1.0")
+
+      subject.version "1.5"
+      subject.run_action(:upgrade)
+      expect(package_list.call).to eq("#{package_name}|1.5")
+    end
+
+    it "upgrades to the latest version if no version given" do
+      subject.version "1.0"
+      subject.run_action(:install)
+      expect(package_list.call).to eq("#{package_name}|1.0")
+
+      subject2 = Chef::Resource::ChocolateyPackage.new("test-A", run_context)
+      subject2.source package_source
+      subject2.run_action(:upgrade)
+      expect(package_list.call).to eq("#{package_name}|2.0")
+    end
+  end
+
+  context "removing a package" do
+    it "removes an installed package" do
+      subject.run_action(:install)
+      Chef::Resource::ChocolateyPackage.new(package_name, run_context).run_action(:remove)
+      expect(package_list.call).to eq("")
+    end
+  end
+end
diff --git a/spec/functional/resource/cookbook_file_spec.rb b/spec/functional/resource/cookbook_file_spec.rb
index 6d4c5b4..cd678e5 100644
--- a/spec/functional/resource/cookbook_file_spec.rb
+++ b/spec/functional/resource/cookbook_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::CookbookFile do
   include_context Chef::Resource::File
 
-  let(:file_base) { 'cookbook_file_spec' }
-  let(:source) { 'java.response' }
-  let(:cookbook_name) { 'java' }
+  let(:file_base) { "cookbook_file_spec" }
+  let(:source) { "java.response" }
+  let(:cookbook_name) { "java" }
   let(:expected_content) do
-    content = File.open(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response'), "rb") do |f|
+    content = File.open(File.join(CHEF_SPEC_DATA, "cookbooks", "java", "files", "default", "java.response"), "rb") do |f|
       f.read
     end
     content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding)
@@ -39,7 +39,7 @@ describe Chef::Resource::CookbookFile do
   def create_resource
     # set up cookbook collection for this run to use, based on our
     # spec data.
-    cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+    cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
     Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
     loader = Chef::CookbookLoader.new(cookbook_repo)
     loader.load_cookbooks
@@ -66,7 +66,7 @@ describe Chef::Resource::CookbookFile do
   # implementation
   # stages files in temp.
   context "targets a file outside of the system temp directory" do
-    let(:windows_non_temp_dir) { File.join(ENV['systemdrive'], make_tmpname(file_base, "non-temp")) }
+    let(:windows_non_temp_dir) { File.join(ENV["systemdrive"], make_tmpname(file_base, "non-temp")) }
     let(:path) { File.join(windows_non_temp_dir, make_tmpname(file_base)) }
 
     before do
diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb
index ed30756..2906715 100644
--- a/spec/functional/resource/cron_spec.rb
+++ b/spec/functional/resource/cron_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 describe Chef::Resource::Cron, :requires_root, :unix_only do
 
@@ -55,17 +55,17 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
   # Actual tests
   let(:new_resource) do
     new_resource = Chef::Resource::Cron.new("Chef functional test cron", run_context)
-    new_resource.user  'root'
+    new_resource.user  "root"
     # @hourly is not supported on solaris, aix
     if ohai[:platform] == "solaris" || ohai[:platform] == "solaris2" || ohai[:platform] == "aix"
       new_resource.minute "0 * * * *"
     else
-      new_resource.minute '@hourly'
+      new_resource.minute "@hourly"
     end
-    new_resource.hour ''
-    new_resource.day ''
-    new_resource.month ''
-    new_resource.weekday ''
+    new_resource.hour ""
+    new_resource.day ""
+    new_resource.month ""
+    new_resource.weekday ""
     new_resource.command "/bin/true"
     new_resource
   end
@@ -107,8 +107,8 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
   exclude_solaris = ["solaris", "opensolaris", "solaris2", "omnios"].include?(ohai[:platform])
   describe "create action with various attributes", :external => exclude_solaris do
     def create_and_validate_with_attribute(resource, attribute, value)
-      if ohai[:platform] == 'aix'
-         expect {resource.run_action(:create)}.to raise_error(Chef::Exceptions::Cron, /Aix cron entry does not support environment variables. Please set them in script and use script in cron./)
+      if ohai[:platform] == "aix"
+        expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Aix cron entry does not support environment variables. Please set them in script and use script in cron./)
       else
         resource.run_action(:create)
         # Verify if the cron is created successfully
@@ -117,7 +117,7 @@ describe Chef::Resource::Cron, :requires_root, :unix_only do
     end
 
     def cron_attribute_should_exists(cron_name, attribute, value)
-      return if ['aix', 'solaris'].include?(ohai[:platform])
+      return if ["aix", "solaris"].include?(ohai[:platform])
       # Test if the attribute exists on newly created cron
       cron_should_exists(cron_name, "")
       expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{attribute.upcase}=#{value}\"").exitstatus).to eq(0)
diff --git a/spec/functional/resource/deploy_revision_spec.rb b/spec/functional/resource/deploy_revision_spec.rb
index e5f5341..4772067 100644
--- a/spec/functional/resource/deploy_revision_spec.rb
+++ b/spec/functional/resource/deploy_revision_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 # Deploy relies heavily on symlinks, so it doesn't work on windows.
 describe Chef::Resource::DeployRevision, :unix_only => true do
@@ -193,7 +193,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
 
       it "restarts the application" do
         expect(File).to exist(rel_path("current/restart.txt"))
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
       end
 
       it "is marked as updated" do
@@ -214,7 +214,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:latest_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
       end
 
       it "is marked updated" do
@@ -248,7 +248,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
 
       it "restarts the application" do
         expect(File).to exist(rel_path("current/restart.txt"))
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
       end
 
       it "is marked as updated" do
@@ -265,7 +265,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:latest_rev)
 
       it "does not restart the app" do
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev})
       end
 
       it "is not marked updated" do
@@ -283,7 +283,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:latest_rev)
 
       it "restarts the app" do
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_latest_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_latest_rev_again})
       end
 
       it "is marked updated" do
@@ -301,7 +301,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:latest_rev)
 
       it "restarts the application after the new deploy" do
-        expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev])
+        expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev})
       end
 
       it "is marked updated" do
@@ -324,7 +324,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:latest_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again})
       end
 
       it "is marked updated" do
@@ -349,7 +349,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:previous_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again})
       end
 
       it "is marked updated" do
@@ -392,7 +392,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:previous_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again})
       end
 
       it "is marked updated" do
@@ -437,7 +437,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:second_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_second_rev deploy_to_previous_rev deploy_to_previous_rev_again deploy_to_latest_rev deploy_to_latest_rev_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_previous_rev_again deploy_to_latest_rev deploy_to_latest_rev_again})
       end
 
       it "is marked updated" do
@@ -474,7 +474,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       the_app_is_deployed_at_revision(:second_rev)
 
       it "restarts the application after rolling back" do
-        expect(actual_operations_order).to eq(%w[deploy_to_second_rev deploy_to_previous_rev deploy_to_second_rev_again deploy_to_latest_rev deploy_to_second_rev_again_again])
+        expect(actual_operations_order).to eq(%w{deploy_to_second_rev deploy_to_previous_rev deploy_to_second_rev_again deploy_to_latest_rev deploy_to_second_rev_again_again})
       end
 
       it "is marked updated" do
@@ -689,7 +689,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
     end
 
     it "runs migrations in between the before_migrate and before_symlink steps" do
-      expect(actual_operations_order).to eq(%w[before_migrate migration before_symlink before_restart after_restart])
+      expect(actual_operations_order).to eq(%w{before_migrate migration before_symlink before_restart after_restart})
     end
   end
 
@@ -799,7 +799,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
 
         let(:deploy_that_fails) do
           resource = deploy_to_latest_rev.dup
-          errant_callback = lambda {|x| raise Exception, "I am a failed deploy" }
+          errant_callback = lambda { |x| raise Exception, "I am a failed deploy" }
           resource.send(callback, &errant_callback)
           resource
         end
@@ -819,7 +819,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
       end
 
       before do
-        expect { deploy_that_fails.run_action(:deploy) }.to raise_error(Chef::Exceptions::Exec)
+        expect { deploy_that_fails.run_action(:deploy) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
         deploy_to_latest_with_callback_tracking.run_action(:deploy)
       end
 
@@ -862,7 +862,7 @@ describe Chef::Resource::DeployRevision, :unix_only => true do
 
       let(:deploy_that_fails) do
         resource = deploy_to_previous_rev.dup
-        resource.after_restart {|x| raise Exception, "I am a failed deploy" }
+        resource.after_restart { |x| raise Exception, "I am a failed deploy" }
         resource
       end
 
diff --git a/spec/functional/resource/directory_spec.rb b/spec/functional/resource/directory_spec.rb
index 88a8109..0c1345d 100644
--- a/spec/functional/resource/directory_spec.rb
+++ b/spec/functional/resource/directory_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Directory do
   include_context Chef::Resource::Directory
@@ -33,7 +33,7 @@ describe Chef::Resource::Directory do
   end
 
   let(:resource) do
-  	create_resource
+    create_resource
   end
 
   it_behaves_like "a directory resource"
diff --git a/spec/functional/resource/dpkg_package_spec.rb b/spec/functional/resource/dpkg_package_spec.rb
new file mode 100644
index 0000000..d652562
--- /dev/null
+++ b/spec/functional/resource/dpkg_package_spec.rb
@@ -0,0 +1,339 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/shell_out"
+
+describe Chef::Resource::DpkgPackage, :requires_root, :debian_family_only, arch: "x86_64" do
+  include Chef::Mixin::ShellOut
+
+  let(:apt_data) { File.join(CHEF_SPEC_DATA, "apt") }
+
+  let(:test1_0) { File.join(apt_data, "chef-integration-test_1.0-1_amd64.deb") }
+  let(:test1_1) { File.join(apt_data, "chef-integration-test_1.1-1_amd64.deb") }
+  let(:test2_0) { File.join(apt_data, "chef-integration-test2_1.0-1_amd64.deb") }
+
+  let(:run_context) {
+    node = TEST_NODE.dup
+    events = Chef::EventDispatch::Dispatcher.new
+    Chef::RunContext.new(node, {}, events)
+  }
+
+  let(:dpkg_package) { Chef::Resource::DpkgPackage.new(test1_0, run_context) }
+
+  before(:each) do
+    shell_out("dpkg -P chef-integration-test chef-integration-test2")
+  end
+
+  # handles setting the name property after the initializer runs
+  def set_dpkg_package_name(name)
+    dpkg_package.name name
+    dpkg_package.package_name name
+  end
+
+  def should_be_purged_or_removed(package, action = nil)
+    status = shell_out("dpkg -s #{package}")
+    output = status.stdout + status.stderr
+    if action.nil? || action == :purge
+      expect(output).to match(/no info|not-installed|not installed/)
+    elsif action == :remove
+      expect(output).to match(/deinstall ok config-files/)
+    else
+      raise "Unknown action"
+    end
+  end
+
+  shared_examples_for "common behavior for upgrade or install" do
+    it "installs a package when given only the filename as a name argument (no source)" do
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+    end
+
+    it "installs a package when given the name and a source argument" do
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+    end
+
+    it "installs a package when given a different name and a source argument" do
+      set_dpkg_package_name "some other name"
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+    end
+
+    it "installs a package when given a path as a package_name and no source" do
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.package_name test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+    end
+
+    it "raises an error when the name is not a path and the source is not given" do
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.package_name "chef-integration-test"
+      expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "raises an error when passed a package_name that does not exist" do
+      set_dpkg_package_name File.join(test1_0, "make.it.fail")
+      expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "raises an error when passed a source that does not exist" do
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.source File.join(test1_0, "make.it.fail")
+      expect { dpkg_package.run_action(action) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "should not install an already installed package" do
+      shell_out!("dpkg -i #{test1_0}")
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+    end
+
+    it "should handle a multipackage install" do
+      set_dpkg_package_name [ test1_0, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+      shell_out!("dpkg -s chef-integration-test2")
+    end
+
+    it "should not update multipackages that are up-to-date" do
+      shell_out!("dpkg -i #{test1_0} #{test2_0}")
+      set_dpkg_package_name [ test1_0, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+      shell_out!("dpkg -s chef-integration-test2")
+    end
+
+    it "should install the second if the first is installed" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name [ test1_0, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+      shell_out!("dpkg -s chef-integration-test2")
+    end
+
+    it "should install the first if the second is installed" do
+      shell_out!("dpkg -i #{test2_0}")
+      set_dpkg_package_name [ test1_0, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test")
+      shell_out!("dpkg -s chef-integration-test2")
+    end
+  end
+
+  context "action :install" do
+    let(:action) { :install }
+    it_behaves_like "common behavior for upgrade or install"
+
+    it "should not upgrade a package" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name test1_1
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+    end
+
+    it "should not upgrade on a multipackage install" do
+      shell_out!("dpkg -i #{test1_0} #{test2_0}")
+      set_dpkg_package_name [ test1_1, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+    end
+  end
+
+  context "action :upgrade" do
+    let(:action) { :upgrade }
+    it_behaves_like "common behavior for upgrade or install"
+
+    it "should upgrade a package" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name test1_1
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+    end
+
+    it "should upgrade on a multipackage install" do
+      shell_out!("dpkg -i #{test1_0} #{test2_0}")
+      set_dpkg_package_name [ test1_1, test2_0 ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+    end
+  end
+
+  shared_examples_for "common behavior for remove or purge" do
+    it "should remove a package that is installed when the name is a source" do
+      shell_out!("dpkg -i #{test1_0}")
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should do nothing if the package is not installed when the name is a source" do
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should remove a package that is installed when the name is the package name and source is nil" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should do nothing if the package is not installed when the name is the package name and the source is nil" do
+      set_dpkg_package_name "chef-integration-test"
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should remove a package that is installed when the name is changed but the source is a package" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name "some other name"
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should do nothing if the package is not installed when the name is changed but the source is a package" do
+      set_dpkg_package_name "some other name"
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should remove a package if the name is a file that does not exist, but the source exists" do
+      shell_out!("dpkg -i #{test1_0}")
+      dpkg_package.name "whatever"
+      dpkg_package.package_name File.join(test1_0, "make.it.fail")
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should do nothing if the package is not installed when the name is a file that does not exist, but the source exists" do
+      set_dpkg_package_name "some other name"
+      dpkg_package.name "whatever"
+      dpkg_package.package_name File.join(test1_0, "make.it.fail")
+      dpkg_package.source test1_0
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should remove a package if the package_name is correct, but the source does not exist" do
+      shell_out!("dpkg -i #{test1_0}")
+      dpkg_package.name "whatever"
+      dpkg_package.package_name "chef-integration-test"
+      dpkg_package.source File.join(test1_0, "make.it.fail")
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should do nothing if the package_name is correct, but the source does not exist, and the package is not installed" do
+      dpkg_package.name "whatever"
+      dpkg_package.package_name "chef-integration-test"
+      dpkg_package.source File.join(test1_0, "make.it.fail")
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+    end
+
+    it "should remove both packages when called with two" do
+      shell_out!("dpkg -i #{test1_0} #{test2_0}")
+      set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+      should_be_purged_or_removed("chef-integration-test2", action)
+    end
+
+    it "should remove a package when only the first one is installed" do
+      shell_out!("dpkg -i #{test1_0}")
+      set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+      should_be_purged_or_removed("chef-integration-test2")
+    end
+
+    it "should remove a package when only the second one is installed" do
+      shell_out!("dpkg -i #{test2_0}")
+      set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+      should_be_purged_or_removed("chef-integration-test2", action)
+    end
+
+    it "should do nothing when both packages are not installed" do
+      set_dpkg_package_name [ "chef-integration-test", "chef-integration-test2" ]
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test")
+      should_be_purged_or_removed("chef-integration-test2")
+    end
+  end
+
+  context "action :remove" do
+    let(:action) { :remove }
+    it_behaves_like "common behavior for remove or purge"
+
+    it "should not remove a removed package when the name is a source" do
+      # the "test2" file has a conffile declared in it
+      shell_out!("dpkg -i #{test2_0}")
+      shell_out!("dpkg -r chef-integration-test2")
+      set_dpkg_package_name "chef-integration-test2"
+      dpkg_package.run_action(action)
+      expect(dpkg_package).not_to be_updated_by_last_action
+      shell_out!("dpkg -s chef-integration-test2") # its still 'installed'
+    end
+  end
+
+  context "action :purge" do
+    let(:action) { :purge }
+    it_behaves_like "common behavior for remove or purge"
+
+    it "should purge a removed package when the name is a source" do
+      # the "test2" file has a conffile declared in it
+      shell_out!("dpkg -i #{test2_0}")
+      shell_out!("dpkg -r chef-integration-test2")
+      set_dpkg_package_name "chef-integration-test2"
+      dpkg_package.run_action(action)
+      expect(dpkg_package).to be_updated_by_last_action
+      should_be_purged_or_removed("chef-integration-test2", action)
+    end
+  end
+end
diff --git a/spec/functional/resource/dsc_resource_spec.rb b/spec/functional/resource/dsc_resource_spec.rb
index 6f453ee..129333c 100644
--- a/spec/functional/resource/dsc_resource_spec.rb
+++ b/spec/functional/resource/dsc_resource_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
-  before(:all) do
-    @ohai = Ohai::System.new
-    @ohai.all_plugins(['platform', 'os', 'languages/powershell'])
-  end
-
   let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new }
 
   let(:node) {
     Chef::Node.new.tap do |n|
-      n.consume_external_attrs(@ohai.data, {})
+      n.consume_external_attrs(OHAI_SYSTEM.data, {})
     end
   }
 
@@ -38,24 +33,26 @@ describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
     Chef::Resource::DscResource.new("dsc_resource_test", run_context)
   }
 
-  context 'when Powershell does not support Invoke-DscResource'
-  context 'when Powershell supports Invoke-DscResource' do
+  context "when Powershell does not support Invoke-DscResource"
+  context "when Powershell supports Invoke-DscResource" do
     before do
       if !Chef::Platform.supports_dsc_invoke_resource?(node)
-        skip 'Requires Powershell >= 5.0.10018.0'
+        skip "Requires Powershell >= 5.0.10018.0"
+      elsif !Chef::Platform.dsc_refresh_mode_disabled?(node)
+        skip "Requires LCM RefreshMode is Disabled"
       end
     end
-    context 'with an invalid dsc resource' do
-      it 'raises an exception if the resource is not found' do
-        new_resource.resource 'thisdoesnotexist'
+    context "with an invalid dsc resource" do
+      it "raises an exception if the resource is not found" do
+        new_resource.resource "thisdoesnotexist"
         expect { new_resource.run_action(:run) }.to raise_error(
                                             Chef::Exceptions::ResourceNotFound)
       end
     end
 
-    context 'with a valid dsc resource' do
-      let(:tmp_file_name) { Dir::Tmpname.create('tmpfile') {} }
-      let(:test_text) { "'\"!@#$%^&*)(}{][\u2713~n"}
+    context "with a valid dsc resource" do
+      let(:tmp_file_name) { Dir::Tmpname.create("tmpfile") {} }
+      let(:test_text) { "'\"!@#$%^&*)(}{][\u2713~n" }
 
       before do
         new_resource.resource :File
@@ -67,16 +64,16 @@ describe Chef::Resource::DscResource, :windows_powershell_dsc_only do
         File.delete(tmp_file_name) if File.exists? tmp_file_name
       end
 
-      it 'converges the resource if it is not converged' do
+      it "converges the resource if it is not converged" do
         new_resource.run_action(:run)
-        contents = File.open(tmp_file_name, 'rb:bom|UTF-16LE') do |f|
-          f.read.encode('UTF-8')
+        contents = File.open(tmp_file_name, "rb:bom|UTF-16LE") do |f|
+          f.read.encode("UTF-8")
         end
         expect(contents).to eq(test_text)
         expect(new_resource).to be_updated
       end
 
-      it 'does not converge the resource if it is already converged' do
+      it "does not converge the resource if it is already converged" do
         new_resource.run_action(:run)
         expect(new_resource).to be_updated
         reresource =
diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb
index a736949..5f264fd 100644
--- a/spec/functional/resource/dsc_script_spec.rb
+++ b/spec/functional/resource/dsc_script_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/shell_out'
-require 'chef/mixin/windows_architecture_helper'
+require "spec_helper"
+require "chef/mixin/shell_out"
+require "chef/mixin/windows_architecture_helper"
+require "support/shared/integration/integration_helper"
 
 describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
   include Chef::Mixin::WindowsArchitectureHelper
@@ -34,10 +35,10 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
 
   def create_config_script_from_code(code, configuration_name, data = false)
     script_code = data ? code : "Configuration '#{configuration_name}'\n{\n\t#{code}\n}\n"
-    data_suffix = data ? '_config_data' : ''
-    extension = data ? 'psd1' : 'ps1'
+    data_suffix = data ? "_config_data" : ""
+    extension = data ? "psd1" : "ps1"
     script_path = "#{@temp_dir}/dsc_functional_test#{data_suffix}.#{extension}"
-    ::File.open(script_path, 'wt') do | script |
+    ::File.open(script_path, "wt") do |script|
       script.write(script_code)
     end
     script_path
@@ -60,30 +61,29 @@ describe Chef::Resource::DscScript, :windows_powershell_dsc_only do
     end
   end
 
-  let(:dsc_env_variable) { 'chefenvtest' }
-  let(:dsc_env_value1) { 'value1' }
-  let(:env_value2) { 'value2' }
+  let(:dsc_env_variable) { "chefenvtest" }
+  let(:dsc_env_value1) { "value1" }
+  let(:env_value2) { "value2" }
   let(:dsc_test_run_context) {
     node = Chef::Node.new
-    node.automatic['platform'] = 'windows'
-    node.automatic['platform_version'] = '6.1'
-    node.automatic['kernel'][:machine] =
-      is_i386_process_on_x86_64_windows? ? :x86_64 : :i386
-    node.automatic[:languages][:powershell][:version] = '4.0'
+    node.automatic["platform"] = "windows"
+    node.automatic["platform_version"] = "6.1"
+    node.automatic["kernel"][:machine] = :x86_64 # Only 64-bit architecture is supported
+    node.automatic[:languages][:powershell][:version] = "4.0"
     empty_events = Chef::EventDispatch::Dispatcher.new
     Chef::RunContext.new(node, {}, empty_events)
   }
-  let(:dsc_test_resource_name) { 'DSCTest' }
+  let(:dsc_test_resource_name) { "DSCTest" }
   let(:dsc_test_resource_base) {
     Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
   }
   let(:test_registry_key) { 'HKEY_LOCAL_MACHINE\Software\Chef\Spec\Functional\Resource\dsc_script_spec' }
-  let(:test_registry_value) { 'Registration' }
-  let(:test_registry_data1) { 'LL927' }
-  let(:test_registry_data2) { 'LL928' }
-  let(:reg_key_name_param_name) { 'testregkeyname' }
-  let(:reg_key_value_param_name) { 'testregvaluename' }
-  let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'"}
+  let(:test_registry_value) { "Registration" }
+  let(:test_registry_data1) { "LL927" }
+  let(:test_registry_data2) { "LL928" }
+  let(:reg_key_name_param_name) { "testregkeyname" }
+  let(:reg_key_value_param_name) { "testregvaluename" }
+  let(:registry_embedded_parameters) { "$#{reg_key_name_param_name} = '#{test_registry_key}';$#{reg_key_value_param_name} = '#{test_registry_value}'" }
   let(:dsc_reg_code) { <<-EOH
   #{registry_embedded_parameters}
   Registry "ChefRegKey"
@@ -101,21 +101,21 @@ EOH
   param($testregkeyname, $testregvaluename)
   #{dsc_reg_code}
 EOH
-      }
-
-  let(:dsc_user_prefix) { 'dsc' }
-  let(:dsc_user_suffix) { 'chefx' }
-  let(:dsc_user) {"#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
-  let(:dsc_user_prefix_env_var_name) { 'dsc_user_env_prefix' }
-  let(:dsc_user_suffix_env_var_name) { 'dsc_user_env_suffix' }
-  let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}"}
-  let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}"}
-  let(:dsc_user_prefix_param_name) { 'dsc_user_prefix_param' }
-  let(:dsc_user_suffix_param_name) { 'dsc_user_suffix_param' }
-  let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}"}
-  let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}"}
-  let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\""}
-  let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\""}
+  }
+
+  let(:dsc_user_prefix) { "dsc" }
+  let(:dsc_user_suffix) { "chefx" }
+  let(:dsc_user) { "#{dsc_user_prefix}_usr_#{dsc_user_suffix}" }
+  let(:dsc_user_prefix_env_var_name) { "dsc_user_env_prefix" }
+  let(:dsc_user_suffix_env_var_name) { "dsc_user_env_suffix" }
+  let(:dsc_user_prefix_env_code) { "$env:#{dsc_user_prefix_env_var_name}" }
+  let(:dsc_user_suffix_env_code) { "$env:#{dsc_user_suffix_env_var_name}" }
+  let(:dsc_user_prefix_param_name) { "dsc_user_prefix_param" }
+  let(:dsc_user_suffix_param_name) { "dsc_user_suffix_param" }
+  let(:dsc_user_prefix_param_code) { "$#{dsc_user_prefix_param_name}" }
+  let(:dsc_user_suffix_param_code) { "$#{dsc_user_suffix_param_name}" }
+  let(:dsc_user_env_code) { "\"$(#{dsc_user_prefix_env_code})_usr_$(#{dsc_user_suffix_env_code})\"" }
+  let(:dsc_user_param_code) { "\"$(#{dsc_user_prefix_param_code})_usr_$(#{dsc_user_suffix_param_code})\"" }
 
   let(:config_flags) { nil }
   let(:config_params) { <<-EOH
@@ -129,7 +129,7 @@ EOH
 EOH
   }
 
-  let(:config_param_section) { '' }
+  let(:config_param_section) { "" }
   let(:dsc_user_code) { "'#{dsc_user}'" }
   let(:dsc_user_prefix_code) { dsc_user_prefix }
   let(:dsc_user_suffix_code) { dsc_user_suffix }
@@ -157,7 +157,7 @@ EOH
   }
 
   let(:dsc_user_config_data) {
-<<-EOH
+    <<-EOH
 @{
     AllNodes = @(
         @{
@@ -170,10 +170,10 @@ EOH
 EOH
   }
 
-  let(:dsc_environment_env_var_name) { 'dsc_test_cwd' }
+  let(:dsc_environment_env_var_name) { "dsc_test_cwd" }
   let(:dsc_environment_no_fail_not_etc_directory) { "#{ENV['systemroot']}\\system32" }
   let(:dsc_environment_fail_etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
-  let(:exception_message_signature) { 'LL927-LL928' }
+  let(:exception_message_signature) { "LL927-LL928" }
   let(:dsc_environment_config) {<<-EOH
 if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}')))
 {
@@ -186,7 +186,7 @@ environment "whatsmydir"
     Ensure = 'Present'
 }
 EOH
-}
+  }
 
   let(:dsc_config_name) {
     dsc_test_resource_base.name
@@ -214,19 +214,19 @@ EOH
     test_key_resource.run_action(:delete_key)
   end
 
-  shared_examples_for 'a dsc_script resource with specified PowerShell configuration code' do
+  shared_examples_for "a dsc_script resource with specified PowerShell configuration code" do
     let(:test_registry_data) { test_registry_data1 }
-    it 'should create a registry key with a specific registry value and data' do
+    it "should create a registry key with a specific registry value and data" do
       expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
       dsc_test_resource.run_action(:run)
       expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
-      expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+      expect(dsc_test_resource.registry_value_exists?(test_registry_key, { :name => test_registry_value, :type => :string, :data => test_registry_data })).to eq(true)
     end
 
-    it_should_behave_like 'a dsc_script resource with configuration affected by cwd'
+    it_should_behave_like "a dsc_script resource with configuration affected by cwd"
   end
 
-  shared_examples_for 'a dsc_script resource with configuration affected by cwd' do
+  shared_examples_for "a dsc_script resource with configuration affected by cwd" do
     after(:each) do
       removal_resource = Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
       removal_resource.code <<-EOH
@@ -239,16 +239,16 @@ EOH
       removal_resource.run_action(:run)
     end
 
-    describe 'when the DSC configuration contains code that raises an exception if cwd has a specific value' do
+    describe "when the DSC configuration contains code that raises an exception if cwd has a specific value" do
       let(:dsc_code) { dsc_environment_config }
-      it 'should not raise an exception if the cwd is not etc' do
+      it "should not raise an exception if the cwd is not etc" do
         dsc_test_resource.cwd(dsc_environment_no_fail_not_etc_directory)
-        expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+        expect { dsc_test_resource.run_action(:run) }.not_to raise_error
       end
 
-      it 'should raise an exception if the cwd is etc' do
+      it "should raise an exception if the cwd is etc" do
         dsc_test_resource.cwd(dsc_environment_fail_etc_directory)
-        expect {dsc_test_resource.run_action(:run)}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+        expect { dsc_test_resource.run_action(:run) }.to raise_error(Chef::Exceptions::PowershellCmdletException)
         begin
           dsc_test_resource.run_action(:run)
         rescue Chef::Exceptions::PowershellCmdletException => e
@@ -258,14 +258,14 @@ EOH
     end
   end
 
-  shared_examples_for 'a parameterized DSC configuration script' do
+  shared_examples_for "a parameterized DSC configuration script" do
     let(:dsc_user_prefix_code) { dsc_user_prefix_env_code }
     let(:dsc_user_suffix_code) { dsc_user_suffix_env_code }
-    it_behaves_like 'a dsc_script with configuration that uses environment variables'
+    it_behaves_like "a dsc_script with configuration that uses environment variables"
   end
 
-  shared_examples_for 'a dsc_script without configuration data that takes parameters' do
-    context 'when configuration data is not specified' do
+  shared_examples_for "a dsc_script without configuration data that takes parameters" do
+    context "when configuration data is not specified" do
 
       before(:each) do
         test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context)
@@ -280,103 +280,190 @@ EOH
       end
 
       let(:test_registry_data) { test_registry_data1 }
-      let(:dsc_parameterized_env_param_value) { "val" + Random::rand.to_s  }
+      let(:dsc_parameterized_env_param_value) { "val" + Random::rand.to_s }
 
-      it 'should have a default value of nil for the configuration_data attribute' do
+      it "should have a default value of nil for the configuration_data attribute" do
         expect(dsc_test_resource.configuration_data).to eql(nil)
       end
 
-      it 'should have a default value of nil for the configuration_data_path attribute' do
+      it "should have a default value of nil for the configuration_data_path attribute" do
         expect(dsc_test_resource.configuration_data_script).to eql(nil)
       end
 
       let(:dsc_test_resource) { dsc_resource_from_path }
-      let(:registry_embedded_parameters) { '' }
+      let(:registry_embedded_parameters) { "" }
       let(:dsc_code) { dsc_reg_script }
 
-      it 'should set a registry key according to parameters passed to the configuration' do
+      it "should set a registry key according to parameters passed to the configuration" do
         dsc_test_resource.configuration_name(config_name_value)
-      dsc_test_resource.flags({:"#{reg_key_name_param_name}" => test_registry_key, :"#{reg_key_value_param_name}" => test_registry_value})
+        dsc_test_resource.flags({ :"#{reg_key_name_param_name}" => test_registry_key, :"#{reg_key_value_param_name}" => test_registry_value })
         expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(false)
         dsc_test_resource.run_action(:run)
         expect(dsc_test_resource.registry_key_exists?(test_registry_key)).to eq(true)
-        expect(dsc_test_resource.registry_value_exists?(test_registry_key, {:name => test_registry_value, :type => :string, :data => test_registry_data})).to eq(true)
+        expect(dsc_test_resource.registry_value_exists?(test_registry_key, { :name => test_registry_value, :type => :string, :data => test_registry_data })).to eq(true)
       end
     end
   end
 
-  shared_examples_for 'a dsc_script with configuration data' do
-    let(:configuration_data_attribute) { 'configuration_data' }
-    it_behaves_like 'a dsc_script with configuration data set via an attribute'
+  shared_examples_for "a dsc_script with configuration data" do
+    let(:configuration_data_attribute) { "configuration_data" }
+    it_behaves_like "a dsc_script with configuration data set via an attribute"
 
-    let(:configuration_data_attribute) { 'configuration_data_script' }
-    it_behaves_like 'a dsc_script with configuration data set via an attribute'
+    let(:configuration_data_attribute) { "configuration_data_script" }
+    it_behaves_like "a dsc_script with configuration data set via an attribute"
   end
 
-  shared_examples_for 'a dsc_script with configuration data set via an attribute' do
-    it 'should run a configuration script that creates a user' do
+  shared_examples_for "a dsc_script with configuration data set via an attribute" do
+    it "should run a configuration script that creates a user" do
       config_data_value = dsc_user_config_data
       dsc_test_resource.configuration_name(config_name_value)
-      if configuration_data_attribute == 'configuration_data_script'
-        config_data_value = create_config_script_from_code(dsc_user_config_data, '', true)
+      if configuration_data_attribute == "configuration_data_script"
+        config_data_value = create_config_script_from_code(dsc_user_config_data, "", true)
       end
-      dsc_test_resource.environment({dsc_user_prefix_env_var_name => dsc_user_prefix,
-                                      dsc_user_suffix_env_var_name => dsc_user_suffix})
+      dsc_test_resource.environment({ dsc_user_prefix_env_var_name => dsc_user_prefix,
+                                      dsc_user_suffix_env_var_name => dsc_user_suffix })
       dsc_test_resource.send(configuration_data_attribute, config_data_value)
       dsc_test_resource.flags(config_flags)
       expect(user_exists?(dsc_user)).to eq(false)
-      expect {dsc_test_resource.run_action(:run)}.not_to raise_error
+      expect { dsc_test_resource.run_action(:run) }.not_to raise_error
       expect(user_exists?(dsc_user)).to eq(true)
     end
   end
 
-  shared_examples_for 'a dsc_script with configuration data that takes parameters' do
+  shared_examples_for "a dsc_script with configuration data that takes parameters" do
     let(:dsc_user_code) { dsc_user_param_code }
     let(:config_param_section) { config_params }
-    let(:config_flags) {{:"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}"}}
-    it 'does not directly contain the user name' do
-      configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+    let(:config_flags) { { :"#{dsc_user_prefix_param_name}" => "#{dsc_user_prefix}", :"#{dsc_user_suffix_param_name}" => "#{dsc_user_suffix}" } }
+    it "does not directly contain the user name" do
+      configuration_script_content = ::File.open(dsc_test_resource.command) do |file|
         file.read
       end
       expect(configuration_script_content.include?(dsc_user)).to be(false)
     end
-    it_behaves_like 'a dsc_script with configuration data'
+    it_behaves_like "a dsc_script with configuration data"
   end
 
-  shared_examples_for 'a dsc_script with configuration data that uses environment variables' do
+  shared_examples_for "a dsc_script with configuration data that uses environment variables" do
     let(:dsc_user_code) { dsc_user_env_code }
 
-    it 'does not directly contain the user name' do
-      configuration_script_content = ::File.open(dsc_test_resource.command) do | file |
+    it "does not directly contain the user name" do
+      configuration_script_content = ::File.open(dsc_test_resource.command) do |file|
         file.read
       end
       expect(configuration_script_content.include?(dsc_user)).to be(false)
     end
-    it_behaves_like 'a dsc_script with configuration data'
+    it_behaves_like "a dsc_script with configuration data"
   end
 
-  context 'when supplying configuration through the configuration attribute' do
+  context "when supplying configuration through the configuration attribute" do
     let(:dsc_test_resource) { dsc_resource_from_code }
-    it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+    it_behaves_like "a dsc_script resource with specified PowerShell configuration code"
   end
 
-  context 'when supplying configuration using the path attribute' do
+  context "when supplying configuration using the path attribute" do
     let(:dsc_test_resource) { dsc_resource_from_path }
-    it_behaves_like 'a dsc_script resource with specified PowerShell configuration code'
+    it_behaves_like "a dsc_script resource with specified PowerShell configuration code"
   end
 
-  context 'when running a configuration that manages users' do
+  context "when running a configuration that manages users" do
     before(:each) do
       delete_user(dsc_user)
     end
 
     let(:dsc_code) { dsc_user_resources_code }
-    let(:config_name_value) { 'DSCTestConfig' }
+    let(:config_name_value) { "DSCTestConfig" }
     let(:dsc_test_resource) { dsc_resource_from_path }
 
-    it_behaves_like 'a dsc_script with configuration data'
-    it_behaves_like 'a dsc_script with configuration data that uses environment variables'
-    it_behaves_like 'a dsc_script with configuration data that takes parameters'
-    it_behaves_like 'a dsc_script without configuration data that takes parameters'
+    it_behaves_like "a dsc_script with configuration data"
+    it_behaves_like "a dsc_script with configuration data that uses environment variables"
+    it_behaves_like "a dsc_script with configuration data that takes parameters"
+    it_behaves_like "a dsc_script without configuration data that takes parameters"
+  end
+
+  context "when using ps_credential" do
+    include IntegrationSupport
+
+    before(:each) do
+      delete_user(dsc_user)
+      dsc_test_run_context.node.consume_external_attrs(OHAI_SYSTEM.data, {})
+    end
+
+    let(:configuration_data_path) { 'C:\\configurationdata.psd1' }
+
+    let(:self_signed_cert_path) do
+      File.join(CHEF_SPEC_DATA, "dsc_lcm.pfx")
+    end
+
+    let(:dsc_configuration_script) do
+      <<-MYCODE
+cd c:\\
+configuration LCM
+{
+  param ($thumbprint)
+  localconfigurationmanager
+  {
+    RebootNodeIfNeeded = $false
+    ConfigurationMode = 'ApplyOnly'
+    CertificateID = $thumbprint
+  }
+}
+$cert = ls Cert:\\LocalMachine\\My\\ |
+  Where-Object {$_.Subject -match "ChefTest"} |
+  Select -first 1
+
+if($cert -eq $null) {
+  $pfxpath = '#{self_signed_cert_path}'
+  $password = ''
+  $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($pfxpath, $password, ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeyset))
+  $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "My", ([System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)
+  $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
+  $store.Add($cert)
+  $store.Close()
+}
+
+lcm -thumbprint $cert.thumbprint
+set-dsclocalconfigurationmanager -path ./LCM
+$ConfigurationData = @"
+@{
+AllNodes = @(
+  @{
+  NodeName = "localhost";
+  CertificateID = '$($cert.thumbprint)';
+  };
+);
+}
+"@
+$ConfigurationData | out-file '#{configuration_data_path}' -force
+  MYCODE
+    end
+
+    let(:powershell_script_resource) do
+      Chef::Resource::PowershellScript.new("configure-lcm", dsc_test_run_context).tap do |r|
+        r.code(dsc_configuration_script)
+        r.architecture(:x86_64)
+      end
+    end
+
+    let(:dsc_script_resource) do
+      dsc_test_resource_base.tap do |r|
+        r.code <<-EOF
+User dsctestusercreate
+{
+    UserName = '#{dsc_user}'
+    Password = #{r.ps_credential('jf9a8m49jrajf4#')}
+    Ensure = "Present"
+}
+EOF
+        r.configuration_data_script(configuration_data_path)
+      end
+    end
+
+    it "allows the use of ps_credential" do
+      expect(user_exists?(dsc_user)).to eq(false)
+      powershell_script_resource.run_action(:run)
+      expect(File).to exist(configuration_data_path)
+      dsc_script_resource.run_action(:run)
+      expect(user_exists?(dsc_user)).to eq(true)
+    end
   end
 end
diff --git a/spec/functional/resource/env_spec.rb b/spec/functional/resource/env_spec.rb
index b9dcd7b..83328a6 100755
--- a/spec/functional/resource/env_spec.rb
+++ b/spec/functional/resource/env_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,27 +16,27 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Env, :windows_only do
-  context 'when running on Windows' do
-    let(:chef_env_test_lower_case) { 'chefenvtest' }
-    let(:chef_env_test_mixed_case) { 'chefENVtest' }
-    let(:env_dne_key) { 'env_dne_key' }
-    let(:env_value1) { 'value1' }
-    let(:env_value2) { 'value2' }
-
-    let(:env_value_expandable) { '%SystemRoot%' }
+  context "when running on Windows" do
+    let(:chef_env_test_lower_case) { "chefenvtest" }
+    let(:chef_env_test_mixed_case) { "chefENVtest" }
+    let(:env_dne_key) { "env_dne_key" }
+    let(:env_value1) { "value1" }
+    let(:env_value2) { "value2" }
+
+    let(:env_value_expandable) { "%SystemRoot%" }
     let(:test_run_context) {
       node = Chef::Node.new
-      node.default['os'] = 'windows'
-      node.default['platform'] = 'windows'
-      node.default['platform_version'] = '6.1'
+      node.default["os"] = "windows"
+      node.default["platform"] = "windows"
+      node.default["platform_version"] = "6.1"
       empty_events = Chef::EventDispatch::Dispatcher.new
       Chef::RunContext.new(node, {}, empty_events)
     }
     let(:test_resource) {
-      Chef::Resource::Env.new('unknown', test_run_context)
+      Chef::Resource::Env.new("unknown", test_run_context)
     }
 
     before(:each) do
@@ -47,7 +47,7 @@ describe Chef::Resource::Env, :windows_only do
     end
 
     context "when the create action is invoked" do
-      it 'should create an environment variable for action create' do
+      it "should create an environment variable for action create" do
         expect(ENV[chef_env_test_lower_case]).to eq(nil)
         test_resource.key_name(chef_env_test_lower_case)
         test_resource.value(env_value1)
@@ -76,7 +76,7 @@ describe Chef::Resource::Env, :windows_only do
         expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
       end
 
-      it 'should not expand environment variables if the variable is not PATH' do
+      it "should not expand environment variables if the variable is not PATH" do
         expect(ENV[chef_env_test_lower_case]).to eq(nil)
         test_resource.key_name(chef_env_test_lower_case)
         test_resource.value(env_value_expandable)
@@ -90,7 +90,7 @@ describe Chef::Resource::Env, :windows_only do
         expect(ENV[chef_env_test_lower_case]).to eq(nil)
         test_resource.key_name(chef_env_test_lower_case)
         test_resource.value(env_value1)
-        expect {test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
+        expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
       end
 
       it "should modify an existing variable's value to a new value" do
@@ -115,7 +115,7 @@ describe Chef::Resource::Env, :windows_only do
         expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
       end
 
-      it 'should not expand environment variables if the variable is not PATH' do
+      it "should not expand environment variables if the variable is not PATH" do
         test_resource.key_name(chef_env_test_lower_case)
         test_resource.value(env_value1)
         test_resource.run_action(:create)
@@ -125,27 +125,27 @@ describe Chef::Resource::Env, :windows_only do
         expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
       end
 
-      context 'when using PATH' do
+      context "when using PATH" do
         let(:random_name) { Time.now.to_i }
-        let(:env_val) { "#{env_value_expandable}_#{random_name}"}
-        let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value('PATH') || '' }
-        let!(:env_path_before) { ENV['PATH'] }
+        let(:env_val) { "#{env_value_expandable}_#{random_name}" }
+        let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
+        let!(:env_path_before) { ENV["PATH"] }
 
-        it 'should expand PATH' do
+        it "should expand PATH" do
           expect(path_before).not_to include(env_val)
-          test_resource.key_name('PATH')
+          test_resource.key_name("PATH")
           test_resource.value("#{path_before};#{env_val}")
           test_resource.run_action(:create)
-          expect(ENV['PATH']).not_to include(env_val)
-          expect(ENV['PATH']).to include("#{random_name}")
+          expect(ENV["PATH"]).not_to include(env_val)
+          expect(ENV["PATH"]).to include("#{random_name}")
         end
 
         after(:each) do
           # cleanup so we don't flood the path
-          test_resource.key_name('PATH')
+          test_resource.key_name("PATH")
           test_resource.value(path_before)
           test_resource.run_action(:create)
-          ENV['PATH'] = env_path_before
+          ENV["PATH"] = env_path_before
         end
       end
 
@@ -165,7 +165,7 @@ describe Chef::Resource::Env, :windows_only do
         expect(ENV[chef_env_test_lower_case]).to eq(nil)
         test_resource.key_name(chef_env_test_lower_case)
         test_resource.value(env_value1)
-        expect{test_resource.run_action(:delete)}.not_to raise_error
+        expect { test_resource.run_action(:delete) }.not_to raise_error
         expect(ENV[chef_env_test_lower_case]).to eq(nil)
       end
 
diff --git a/spec/functional/resource/execute_spec.rb b/spec/functional/resource/execute_spec.rb
index ffa4628..1ceeb70 100644
--- a/spec/functional/resource/execute_spec.rb
+++ b/spec/functional/resource/execute_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'timeout'
+require "spec_helper"
+require "functional/resource/base"
+require "timeout"
 
 describe Chef::Resource::Execute do
   let(:resource) {
@@ -89,7 +89,7 @@ describe Chef::Resource::Execute do
       resource.environment({
         "SAWS_SECRET"  => "supersecret",
         "SAWS_KEY"     => "qwerty",
-      })
+      },)
     end
 
     it "guard inherits :environment value from resource and runs" do
@@ -106,7 +106,7 @@ describe Chef::Resource::Execute do
 
     it "guard adds additional values in its :environment and runs" do
       resource.only_if %{ruby -e 'exit 1 if ENV["SGCE_SECRET"] != "regularsecret"'}, {
-        :environment => { 'SGCE_SECRET' => "regularsecret" }
+        :environment => { "SGCE_SECRET" => "regularsecret" }
       }
       resource.run_action(:run)
       expect(resource).to be_updated_by_last_action
@@ -114,7 +114,7 @@ describe Chef::Resource::Execute do
 
     it "guard adds additional values in its :environment and does not run" do
       resource.only_if %{ruby -e 'exit 1 if ENV["SGCE_SECRET"] == "regularsecret"'}, {
-        :environment => { 'SGCE_SECRET' => "regularsecret" }
+        :environment => { "SGCE_SECRET" => "regularsecret" }
       }
       resource.run_action(:run)
       expect(resource).not_to be_updated_by_last_action
@@ -122,7 +122,7 @@ describe Chef::Resource::Execute do
 
     it "guard overwrites value with its :environment and runs" do
       resource.only_if %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] != "regularsecret"'}, {
-        :environment => { 'SAWS_SECRET' => "regularsecret" }
+        :environment => { "SAWS_SECRET" => "regularsecret" }
       }
       resource.run_action(:run)
       expect(resource).to be_updated_by_last_action
@@ -130,16 +130,23 @@ describe Chef::Resource::Execute do
 
     it "guard overwrites value with its :environment and does not runs" do
       resource.only_if %{ruby -e 'exit 1 if ENV["SAWS_SECRET"] == "regularsecret"'}, {
-        :environment => { 'SAWS_SECRET' => "regularsecret" }
+        :environment => { "SAWS_SECRET" => "regularsecret" }
       }
       resource.run_action(:run)
       expect(resource).not_to be_updated_by_last_action
     end
   end
 
+  # Ensure that CommandTimeout is raised, and is caused by resource.timeout really expiring.
+  # https://github.com/chef/chef/issues/2985
+  #
+  # resource.timeout should be short, this is what we're testing
+  # resource.command ruby sleep timer should be longer than resource.timeout to give us something to timeout
+  # Timeout::timeout should be longer than resource.timeout, but less than the resource.command ruby sleep timer,
+  #   so we fail if we finish on resource.command instead of resource.timeout, but raise CommandTimeout anyway (#2175).
   it "times out when a timeout is set on the resource" do
-    Timeout::timeout(5) do
-      resource.command %{ruby -e 'sleep 600'}
+    Timeout::timeout(30) do
+      resource.command %{ruby -e 'sleep 300'}
       resource.timeout 0.1
       expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::CommandTimeout)
     end
diff --git a/spec/functional/resource/file_spec.rb b/spec/functional/resource/file_spec.rb
index f1a290d..0fa1317 100644
--- a/spec/functional/resource/file_spec.rb
+++ b/spec/functional/resource/file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 describe Chef::Resource::File do
   include_context Chef::Resource::File
@@ -25,17 +25,17 @@ describe Chef::Resource::File do
   let(:file_base) { "file_spec" }
   let(:expected_content) { "Don't fear the ruby." }
 
-  def create_resource(opts={})
+  def create_resource(opts = {})
     events = Chef::EventDispatch::Dispatcher.new
     node = Chef::Node.new
     run_context = Chef::RunContext.new(node, {}, events)
 
     use_path = if opts[:use_relative_path]
-      Dir.chdir(Dir.tmpdir)
-      File.basename(path)
-    else
-      path
-    end
+                 Dir.chdir(Dir.tmpdir)
+                 File.basename(path)
+               else
+                 path
+               end
 
     Chef::Resource::File.new(use_path, run_context)
   end
@@ -86,6 +86,30 @@ describe Chef::Resource::File do
     end
   end
 
+  describe "when using backup" do
+    before do
+      Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
+      resource_without_content.backup(1)
+      resource_without_content.run_action(:create)
+    end
+
+    let(:backup_glob) { File.join(CHEF_SPEC_BACKUP_PATH, test_file_dir.sub(/^([A-Za-z]:)/, ""), "#{file_base}*") }
+
+    let(:path) do
+      # Use native system path
+      ChefConfig::PathHelper.canonical_path(File.join(test_file_dir, make_tmpname(file_base)), false)
+    end
+
+    it "only stores the number of requested backups" do
+      resource_without_content.content("foo")
+      resource_without_content.run_action(:create)
+      resource_without_content.content("bar")
+      resource_without_content.run_action(:create)
+      expect(Dir.glob(backup_glob).length).to eq(1)
+    end
+
+  end
+
   # github issue 1842.
   describe "when running action :create on a relative path" do
     before do
diff --git a/spec/functional/resource/git_spec.rb b/spec/functional/resource/git_spec.rb
index 9d3b82f..7174a99 100644
--- a/spec/functional/resource/git_spec.rb
+++ b/spec/functional/resource/git_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/shell_out'
-require 'tmpdir'
-require 'shellwords'
+require "spec_helper"
+require "chef/mixin/shell_out"
+require "tmpdir"
+require "shellwords"
 
 # Deploy relies heavily on symlinks, so it doesn't work on windows.
 describe Chef::Resource::Git do
@@ -62,7 +62,7 @@ describe Chef::Resource::Git do
   let(:v1_tag) { "9b73fb5e316bfaff7b822b0ccb3e1e08f9885085" }
   let(:rev_foo) { "ed181b3419b6f489bedab282348162a110d6d3a1" }
   let(:rev_testing) { "972d153654503bccec29f630c5dd369854a561e8" }
-  let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f"}
+  let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f" }
 
   let(:git_user_config) do
     <<-E
@@ -76,7 +76,7 @@ E
     Chef::Log.level = :warn # silence git command live streams
     @old_file_cache_path = Chef::Config[:file_cache_path]
     shell_out!("git clone \"#{git_bundle_repo}\" example", :cwd => origin_repo_dir)
-    File.open("#{origin_repo}/.git/config", "a+") {|f| f.print(git_user_config) }
+    File.open("#{origin_repo}/.git/config", "a+") { |f| f.print(git_user_config) }
     Chef::Config[:file_cache_path] = file_cache_path
   end
 
@@ -129,10 +129,10 @@ E
 
     it "checks out the revision pointed to by the tag commit, not the tag commit itself" do
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(v1_commit)
       # also verify the tag commit itself is what we expect as an extra sanity check
-      rev = shell_out!('git rev-parse v1.0.0', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      rev = shell_out!("git rev-parse v1.0.0", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(rev).to eq(v1_tag)
     end
 
@@ -140,7 +140,7 @@ E
       # this used to fail because we didn't resolve the annotated tag
       # properly to the pointed to commit.
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(v1_commit)
 
       copy_git_resource.run_action(:sync)
@@ -166,14 +166,14 @@ E
     it "checks out the expected revision ed18" do
       basic_git_resource.revision rev_foo
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_foo)
     end
 
     it "doesn't update if up-to-date" do
       basic_git_resource.revision rev_foo
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_foo)
 
       copy_git_resource.revision rev_foo
@@ -184,7 +184,7 @@ E
     it "checks out the expected revision 972d" do
       basic_git_resource.revision rev_testing
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_testing)
     end
   end
@@ -193,13 +193,13 @@ E
     let(:basic_git_resource) do
       Chef::Resource::Git.new(deploy_directory, run_context).tap do |r|
         r.repository origin_repo
-        r.revision 'HEAD'
+        r.revision "HEAD"
       end
     end
 
     it "checks out the expected revision" do
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_head)
     end
   end
@@ -214,7 +214,7 @@ E
 
     it "checks out HEAD as the default revision" do
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip
+      head_rev = shell_out!("git rev-parse HEAD", :cwd => deploy_directory, :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_head)
     end
   end
@@ -228,7 +228,7 @@ E
     let(:basic_git_resource) do
       Chef::Resource::Git.new(deploy_directory, run_context).tap do |r|
         r.repository origin_repo
-        r.revision 'HEAD'
+        r.revision "HEAD"
       end
     end
 
@@ -241,7 +241,7 @@ E
 
     it "checks out the (master) HEAD revision and ignores the tag" do
       basic_git_resource.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD',
+      head_rev = shell_out!("git rev-parse HEAD",
                             :cwd => deploy_directory,
                             :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_head)
@@ -249,7 +249,7 @@ E
 
     it "checks out the (master) HEAD revision when no revision is specified (ignores tag)" do
       git_resource_default_rev.run_action(:sync)
-      head_rev = shell_out!('git rev-parse HEAD',
+      head_rev = shell_out!("git rev-parse HEAD",
                             :cwd => deploy_directory,
                             :returns => [0]).stdout.strip
       expect(head_rev).to eq(rev_head)
diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb
index 6676aa3..063b5d9 100644
--- a/spec/functional/resource/group_spec.rb
+++ b/spec/functional/resource/group_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Chirag Jog (<chirag at clogeny.com>)
 # Author:: Siddheshwar More (<siddheshwar.more at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 # Chef::Resource::Group are turned off on Mac OS X 10.6 due to caching
 # issues around Etc.getgrnam() not picking up the group membership
@@ -58,7 +58,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
     when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch"
       expect { Etc::getgrnam(group) }.to raise_error(ArgumentError, "can't find group for #{group}")
     when "windows"
-      expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.to raise_error(ArgumentError, "The group name could not be found.")
+      expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.to raise_error(ArgumentError, /The group name could not be found./)
     end
   end
 
@@ -79,8 +79,8 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
   def windows_domain_user?(user_name)
     domain, user = user_name.split('\\')
 
-    if user && domain != '.'
-      computer_name = ENV['computername']
+    if user && domain != "."
+      computer_name = ENV["computername"]
       domain.downcase != computer_name.downcase
     end
   end
@@ -95,7 +95,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
 
   def create_user(username)
     user(username).run_action(:create) if ! windows_domain_user?(username)
-    # TODO: User shouldn't exist
+    # TODO: User should exist
   end
 
   def remove_user(username)
@@ -135,45 +135,76 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
       group_should_not_exist(group_name)
     end
 
-    describe "when append is not set" do
-      let(:included_members) { [spec_members[1]] }
+    # dscl doesn't perform any error checking and will let you add users that don't exist.
+    describe "when no users exist", :not_supported_on_mac_osx do
+      describe "when append is not set" do
+        # excluded_members can only be used when append is set.  It is ignored otherwise.
+        let(:excluded_members) { [] }
 
-      before do
-        create_user(spec_members[1])
-        create_user(spec_members[0])
-        add_members_to_group([spec_members[0]])
-      end
-
-      after do
-        remove_user(spec_members[1])
-        remove_user(spec_members[0])
+        it "should raise an error" do
+          expect { group_resource.run_action(tested_action) }.to raise_error()
+        end
       end
 
-      it "should remove the existing users and add the new users to the group" do
-        group_resource.run_action(tested_action)
+      describe "when append is set" do
+        before do
+          group_resource.append(true)
+        end
 
-        expect(user_exist_in_group?(spec_members[1])).to eq(true)
-        expect(user_exist_in_group?(spec_members[0])).to eq(false)
+        it "should raise an error" do
+          expect { group_resource.run_action(tested_action) }.to raise_error()
+        end
       end
     end
 
-    describe "when append is set" do
-      before(:each) do
-        group_resource.append(true)
+    describe "when the users exist" do
+      before do
+        (spec_members).each do |member|
+          create_user(member)
+        end
       end
 
-      describe "when the users exist" do
-        before do
-          (included_members + excluded_members).each do |member|
-            create_user(member)
+      after do
+        (spec_members).each do |member|
+          remove_user(member)
+        end
+      end
+
+      describe "when append is not set" do
+        it "should set the group to to contain given members" do
+          group_resource.run_action(tested_action)
+
+          included_members.each do |member|
+            expect(user_exist_in_group?(member)).to eq(true)
+          end
+          (spec_members - included_members).each do |member|
+            expect(user_exist_in_group?(member)).to eq(false)
           end
         end
 
-        after do
-          (included_members + excluded_members).each do |member|
-            remove_user(member)
+        describe "when group already contains some users" do
+          before do
+            add_members_to_group([included_members[0]])
+            add_members_to_group(spec_members - included_members)
+          end
+
+          it "should remove all existing users and only add the new users to the group" do
+            group_resource.run_action(tested_action)
+
+            included_members.each do |member|
+              expect(user_exist_in_group?(member)).to eq(true)
+            end
+            (spec_members - included_members).each do |member|
+              expect(user_exist_in_group?(member)).to eq(false)
+            end
           end
         end
+      end
+
+      describe "when append is set" do
+        before(:each) do
+          group_resource.append(true)
+        end
 
         it "should add included members to the group" do
           group_resource.run_action(tested_action)
@@ -186,9 +217,9 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
           end
         end
 
-        describe "when group contains some users" do
+        describe "when group already contains some users" do
           before(:each) do
-            add_members_to_group([ spec_members[0], spec_members[2] ])
+            add_members_to_group([included_members[0], excluded_members[0]])
           end
 
           it "should add the included users and remove excluded users" do
@@ -203,20 +234,6 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
           end
         end
       end
-
-      describe "when the users doesn't exist" do
-        describe "when append is not set" do
-          it "should raise an error" do
-            expect { @grp_resource.run_action(tested_action) }.to raise_error
-          end
-        end
-
-        describe "when append is set" do
-          it "should raise an error" do
-            expect { @grp_resource.run_action(tested_action) }.to raise_error
-          end
-        end
-      end
     end
   end
 
@@ -231,6 +248,12 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
       group_should_exist(group_name)
     end
 
+    after(:each) do
+      group_resource.run_action(:remove)
+    end
+
+    # TODO: The ones below might actually return ArgumentError now - but I don't have
+    # a way to verify that.  Change it and delete this comment if that's the case.
     describe "when updating membership" do
       it "raises an error for a non well-formed domain name" do
         group_resource.members [invalid_domain_user_name]
@@ -256,7 +279,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
     end
   end
 
-  let(:group_name) { "t-#{SecureRandom.random_number(9999)}" }
+  let(:group_name) { "group#{SecureRandom.random_number(9999)}" }
   let(:included_members) { nil }
   let(:excluded_members) { nil }
   let(:group_resource) {
@@ -300,7 +323,7 @@ theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\
 downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
 
       it "should not create a group" do
-        expect { group_resource.run_action(:create) }.to raise_error
+        expect { group_resource.run_action(:create) }.to raise_error(ArgumentError)
         group_should_not_exist(group_name)
       end
     end
@@ -311,7 +334,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
         invalid_resource = group_resource.dup
         invalid_resource.members(["Jack"])
         invalid_resource.excluded_members(["Jack"])
-        expect { invalid_resource.run_action(:create)}.to raise_error(Chef::Exceptions::ConflictingMembersInGroup)
+        expect { invalid_resource.run_action(:create) }.to raise_error(Chef::Exceptions::ConflictingMembersInGroup)
       end
     end
   end
@@ -338,7 +361,7 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
   end
 
   describe "group modify action", :not_supported_on_solaris do
-    let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
+    let(:spec_members) { ["mnou5sdz", "htulrvwq", "x4c3g1lu"] }
     let(:included_members) { [spec_members[0], spec_members[1]] }
     let(:excluded_members) { [spec_members[2]] }
     let(:tested_action) { :modify }
@@ -355,8 +378,8 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
 
     describe "when running on Windows", :windows_only do
       describe "when members are Active Directory domain identities", :windows_domain_joined_only do
-        let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
-        let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
+        let(:computer_domain) { ohai[:kernel]["cs_info"]["domain"].split(".")[0] }
+        let(:spec_members) { ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
 
         include_examples "correct group management"
       end
@@ -366,12 +389,17 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
   end
 
   describe "group manage action", :not_supported_on_solaris do
-    let(:spec_members){ ["Gordon", "Eric", "Anthony"] }
+    let(:spec_members) { ["mnou5sdz", "htulrvwq", "x4c3g1lu"] }
     let(:included_members) { [spec_members[0], spec_members[1]] }
     let(:excluded_members) { [spec_members[2]] }
     let(:tested_action) { :manage }
 
     describe "when there is no group" do
+      before(:each) do
+        group_resource.run_action(:remove)
+        group_should_not_exist(group_name)
+      end
+
       it "raises an error on modify" do
         expect { group_resource.run_action(:modify) }.to raise_error
       end
@@ -387,8 +415,8 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
 
     describe "running on windows", :windows_only do
       describe "when members are Windows domain identities", :windows_domain_joined_only do
-        let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
-        let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
+        let(:computer_domain) { ohai[:kernel]["cs_info"]["domain"].split(".")[0] }
+        let(:spec_members) { ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
 
         include_examples "correct group management"
       end
@@ -399,34 +427,34 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
 
   describe "group resource with Usermod provider", :solaris_only do
     describe "when excluded_members is set" do
-      let(:excluded_members) { ["Anthony"] }
+      let(:excluded_members) { ["x4c3g1lu"] }
 
       it ":manage should raise an error" do
-        expect {group_resource.run_action(:manage) }.to raise_error
+        expect { group_resource.run_action(:manage) }.to raise_error
       end
 
       it ":modify should raise an error" do
-        expect {group_resource.run_action(:modify) }.to raise_error
+        expect { group_resource.run_action(:modify) }.to raise_error
       end
 
       it ":create should raise an error" do
-        expect {group_resource.run_action(:create) }.to raise_error
+        expect { group_resource.run_action(:create) }.to raise_error
       end
     end
 
     describe "when append is not set" do
-      let(:included_members) { ["Gordon", "Eric"] }
+      let(:included_members) { ["gordon", "eric"] }
 
       before(:each) do
         group_resource.append(false)
       end
 
       it ":manage should raise an error" do
-        expect {group_resource.run_action(:manage) }.to raise_error
+        expect { group_resource.run_action(:manage) }.to raise_error
       end
 
       it ":modify should raise an error" do
-        expect {group_resource.run_action(:modify) }.to raise_error
+        expect { group_resource.run_action(:modify) }.to raise_error
       end
     end
   end
diff --git a/spec/functional/resource/ifconfig_spec.rb b/spec/functional/resource/ifconfig_spec.rb
index 9c61354..cac6d96 100644
--- a/spec/functional/resource/ifconfig_spec.rb
+++ b/spec/functional/resource/ifconfig_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,19 @@
 # limitations under the License.
 #
 
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 # run this test only for following platforms.
-include_flag = !(['ubuntu', 'centos', 'aix'].include?(ohai[:platform]))
+include_flag = !(["ubuntu", "centos", "aix"].include?(ohai[:platform]))
+
+describe Chef::Resource::Ifconfig, :requires_root, :skip_travis, :external => include_flag do
+  # This test does not work in travis because there is no eth0
 
-describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
   include Chef::Mixin::ShellOut
 
   let(:new_resource) do
-    new_resource = Chef::Resource::Ifconfig.new('10.10.0.1', run_context)
+    new_resource = Chef::Resource::Ifconfig.new("10.10.0.1", run_context)
     new_resource
   end
 
@@ -43,9 +45,9 @@ describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
     # use loopback interface for tests
     case ohai[:platform]
     when "aix"
-      'lo0'
+      "lo0"
     else
-      'lo'
+      "lo"
     end
   end
 
@@ -53,9 +55,9 @@ describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
   def en0_interface_for_test
     case ohai[:platform]
     when "aix"
-      'en0'
+      "en0"
     else
-      'eth0'
+      "eth0"
     end
   end
 
@@ -105,14 +107,14 @@ describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do
   # Actual tests
 
   describe "#load_current_resource" do
-    it 'should load given interface' do
+    it "should load given interface" do
       new_resource.device lo_interface_for_test
       expect(current_resource.device).to eql(lo_interface_for_test)
       expect(current_resource.inet_addr).to match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
     end
   end
 
-  exclude_test = ohai[:platform] != 'ubuntu'
+  exclude_test = ohai[:platform] != "ubuntu"
   describe "#action_add", :external => exclude_test do
     after do
       new_resource.run_action(:delete)
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index d39a0c2..9b9d696 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 if windows?
-  require 'chef/win32/file' #probably need this in spec_helper
+  require "chef/win32/file" #probably need this in spec_helper
 end
 
 describe Chef::Resource::Link do
   let(:file_base) { "file_spec" }
 
-  let(:expect_updated?) {true}
+  let(:expect_updated?) { true }
 
   # We create the files in a different directory than tmp to exercise
   # different file deployment strategies more completely.
   let(:test_file_dir) do
     if windows?
-      File.join(ENV['systemdrive'], "test-dir")
+      File.join(ENV["systemdrive"], "test-dir")
     else
       File.join(CHEF_SPEC_DATA, "test-dir")
     end
@@ -73,7 +73,7 @@ describe Chef::Resource::Link do
   end
 
   def canonicalize(path)
-    windows? ? path.gsub('/', '\\') : path
+    windows? ? path.gsub("/", '\\') : path
   end
 
   def symlink(a, b)
@@ -83,6 +83,7 @@ describe Chef::Resource::Link do
       File.symlink(a, b)
     end
   end
+
   def symlink?(file)
     if windows?
       Chef::ReservedNames::Win32::File.symlink?(file)
@@ -90,6 +91,7 @@ describe Chef::Resource::Link do
       File.symlink?(file)
     end
   end
+
   def readlink(file)
     if windows?
       Chef::ReservedNames::Win32::File.readlink(file)
@@ -97,6 +99,7 @@ describe Chef::Resource::Link do
       File.readlink(file)
     end
   end
+
   def link(a, b)
     if windows?
       Chef::ReservedNames::Win32::File.link(a, b)
@@ -121,142 +124,142 @@ describe Chef::Resource::Link do
   end
 
   describe "when supported on platform", :not_supported_on_win2k3 do
-    shared_examples_for 'delete errors out' do
-      it 'delete errors out' do
+    shared_examples_for "delete errors out" do
+      it "delete errors out" do
         expect { resource.run_action(:delete) }.to raise_error(Chef::Exceptions::Link)
         expect(File.exist?(target_file) || symlink?(target_file)).to be_truthy
       end
     end
 
-    shared_context 'delete is noop' do
-      describe 'the :delete action' do
+    shared_context "delete is noop" do
+      describe "the :delete action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:delete)
         end
 
-        it 'leaves the file deleted' do
+        it "leaves the file deleted" do
           expect(File.exist?(target_file)).to be_falsey
           expect(symlink?(target_file)).to be_falsey
         end
-        it 'does not mark the resource updated' do
+        it "does not mark the resource updated" do
           expect(resource).not_to be_updated
         end
-        it 'does not log that it deleted' do
+        it "does not log that it deleted" do
           expect(@info.include?("link[#{target_file}] deleted")).to be_falsey
         end
       end
     end
 
-    shared_context 'delete succeeds' do
-      describe 'the :delete action' do
+    shared_context "delete succeeds" do
+      describe "the :delete action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:delete)
         end
 
-        it 'deletes the file' do
+        it "deletes the file" do
           expect(File.exist?(target_file)).to be_falsey
           expect(symlink?(target_file)).to be_falsey
         end
-        it 'marks the resource updated' do
+        it "marks the resource updated" do
           expect(resource).to be_updated
         end
-        it 'logs that it deleted' do
+        it "logs that it deleted" do
           expect(@info.include?("link[#{target_file}] deleted")).to be_truthy
         end
       end
     end
 
-    shared_context 'create symbolic link succeeds' do
-      describe 'the :create action' do
+    shared_context "create symbolic link succeeds" do
+      describe "the :create action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:create)
         end
 
-        it 'links to the target file' do
+        it "links to the target file" do
           expect(symlink?(target_file)).to be_truthy
           expect(readlink(target_file)).to eq(canonicalize(to))
         end
-        it 'marks the resource updated' do
+        it "marks the resource updated" do
           expect(resource).to be_updated
         end
-        it 'logs that it created' do
+        it "logs that it created" do
           expect(@info.include?("link[#{target_file}] created")).to be_truthy
         end
       end
     end
 
-    shared_context 'create symbolic link is noop' do
-      describe 'the :create action' do
+    shared_context "create symbolic link is noop" do
+      describe "the :create action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:create)
         end
 
-        it 'leaves the file linked' do
+        it "leaves the file linked" do
           expect(symlink?(target_file)).to be_truthy
           expect(readlink(target_file)).to eq(canonicalize(to))
         end
-        it 'does not mark the resource updated' do
+        it "does not mark the resource updated" do
           expect(resource).not_to be_updated
         end
-        it 'does not log that it created' do
+        it "does not log that it created" do
           expect(@info.include?("link[#{target_file}] created")).to be_falsey
         end
       end
     end
 
-    shared_context 'create hard link succeeds' do
-      describe 'the :create action' do
+    shared_context "create hard link succeeds" do
+      describe "the :create action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:create)
         end
-        it 'preserves the hard link' do
+        it "preserves the hard link" do
           expect(File.exists?(target_file)).to be_truthy
           expect(symlink?(target_file)).to be_falsey
           # Writing to one hardlinked file should cause both
           # to have the new value.
           expect(IO.read(to)).to eq(IO.read(target_file))
-          File.open(to, "w") { |file| file.write('wowzers') }
-          expect(IO.read(target_file)).to eq('wowzers')
+          File.open(to, "w") { |file| file.write("wowzers") }
+          expect(IO.read(target_file)).to eq("wowzers")
         end
-        it 'marks the resource updated' do
+        it "marks the resource updated" do
           expect(resource).to be_updated
         end
-        it 'logs that it created' do
+        it "logs that it created" do
           expect(@info.include?("link[#{target_file}] created")).to be_truthy
         end
       end
     end
 
-    shared_context 'create hard link is noop' do
-      describe 'the :create action' do
+    shared_context "create hard link is noop" do
+      describe "the :create action" do
         before(:each) do
           @info = []
           allow(Chef::Log).to receive(:info) { |msg| @info << msg }
           resource.run_action(:create)
         end
-        it 'links to the target file' do
+        it "links to the target file" do
           expect(File.exists?(target_file)).to be_truthy
           expect(symlink?(target_file)).to be_falsey
           # Writing to one hardlinked file should cause both
           # to have the new value.
           expect(IO.read(to)).to eq(IO.read(target_file))
-          File.open(to, "w") { |file| file.write('wowzers') }
-          expect(IO.read(target_file)).to eq('wowzers')
+          File.open(to, "w") { |file| file.write("wowzers") }
+          expect(IO.read(target_file)).to eq("wowzers")
         end
-        it 'does not mark the resource updated' do
+        it "does not mark the resource updated" do
           expect(resource).not_to be_updated
         end
-        it 'does not log that it created' do
+        it "does not log that it created" do
           expect(@info.include?("link[#{target_file}] created")).to be_falsey
         end
       end
@@ -264,34 +267,34 @@ describe Chef::Resource::Link do
 
     context "is symbolic" do
 
-      context 'when the link destination is a file' do
+      context "when the link destination is a file" do
         before(:each) do
           File.open(to, "w") do |file|
-            file.write('woohoo')
+            file.write("woohoo")
           end
         end
-        context 'and the link does not yet exist' do
-          include_context 'create symbolic link succeeds'
-          include_context 'delete is noop'
+        context "and the link does not yet exist" do
+          include_context "create symbolic link succeeds"
+          include_context "delete is noop"
         end
-        context 'and the link already exists and is a symbolic link' do
-          context 'pointing at the target' do
+        context "and the link already exists and is a symbolic link" do
+          context "pointing at the target" do
             before(:each) do
               symlink(to, target_file)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(to))
             end
-            include_context 'create symbolic link is noop'
-            include_context 'delete succeeds'
-            it 'the :delete action does not delete the target file' do
+            include_context "create symbolic link is noop"
+            include_context "delete succeeds"
+            it "the :delete action does not delete the target file" do
               resource.run_action(:delete)
               expect(File.exists?(to)).to be_truthy
             end
           end
-          context 'pointing somewhere else' do
+          context "pointing somewhere else" do
             before(:each) do
-              @other_target = File.join(test_file_dir, make_tmpname('other_spec'))
-              File.open(@other_target, 'w') { |file| file.write('eek') }
+              @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
+              File.open(@other_target, "w") { |file| file.write("eek") }
               symlink(@other_target, target_file)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(@other_target))
@@ -299,45 +302,45 @@ describe Chef::Resource::Link do
             after(:each) do
               File.delete(@other_target)
             end
-            include_context 'create symbolic link succeeds'
-            include_context 'delete succeeds'
-            it 'the :delete action does not delete the target file' do
+            include_context "create symbolic link succeeds"
+            include_context "delete succeeds"
+            it "the :delete action does not delete the target file" do
               resource.run_action(:delete)
               expect(File.exists?(to)).to be_truthy
             end
           end
-          context 'pointing nowhere' do
+          context "pointing nowhere" do
             before(:each) do
-              nonexistent = File.join(test_file_dir, make_tmpname('nonexistent_spec'))
+              nonexistent = File.join(test_file_dir, make_tmpname("nonexistent_spec"))
               symlink(nonexistent, target_file)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(nonexistent))
             end
-            include_context 'create symbolic link succeeds'
-            include_context 'delete succeeds'
+            include_context "create symbolic link succeeds"
+            include_context "delete succeeds"
           end
         end
-        context 'and the link already exists and is a hard link to the file' do
+        context "and the link already exists and is a hard link to the file" do
           before(:each) do
             link(to, target_file)
             expect(File.exists?(target_file)).to be_truthy
             expect(symlink?(target_file)).to be_falsey
           end
-          include_context 'create symbolic link succeeds'
-          it_behaves_like 'delete errors out'
+          include_context "create symbolic link succeeds"
+          it_behaves_like "delete errors out"
         end
-        context 'and the link already exists and is a file' do
+        context "and the link already exists and is a file" do
           before(:each) do
-            File.open(target_file, 'w') { |file| file.write('eek') }
+            File.open(target_file, "w") { |file| file.write("eek") }
           end
-          include_context 'create symbolic link succeeds'
-          it_behaves_like 'delete errors out'
+          include_context "create symbolic link succeeds"
+          it_behaves_like "delete errors out"
         end
-        context 'and the link already exists and is a directory' do
+        context "and the link already exists and is a directory" do
           before(:each) do
             Dir.mkdir(target_file)
           end
-          it 'create errors out' do
+          it "create errors out" do
             if windows?
               expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
             elsif os_x? or solaris? or freebsd? or aix?
@@ -346,48 +349,49 @@ describe Chef::Resource::Link do
               expect { resource.run_action(:create) }.to raise_error(Errno::EISDIR)
             end
           end
-          it_behaves_like 'delete errors out'
-        end
-        context 'and the link already exists and is not writeable to this user', :skip => true do
+          it_behaves_like "delete errors out"
         end
-        it_behaves_like 'a securable resource without existing target' do
+
+        it_behaves_like "a securable resource without existing target" do
           let(:path) { target_file }
           def allowed_acl(sid, expected_perms)
             [ ACE.access_allowed(sid, expected_perms[:specific]) ]
           end
+
           def denied_acl(sid, expected_perms)
             [ ACE.access_denied(sid, expected_perms[:specific]) ]
           end
+
           def parent_inheritable_acls
             dummy_file_path = File.join(test_file_dir, "dummy_file")
-            dummy_file = FileUtils.touch(dummy_file_path)
+            FileUtils.touch(dummy_file_path)
             dummy_desc = get_security_descriptor(dummy_file_path)
             FileUtils.rm_rf(dummy_file_path)
             dummy_desc
           end
         end
       end
-      context 'when the link destination is a directory' do
+      context "when the link destination is a directory" do
         before(:each) do
           Dir.mkdir(to)
         end
         # On Windows, readlink fails to open the link.  FILE_FLAG_OPEN_REPARSE_POINT
         # might help, from http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
-        context 'and the link does not yet exist' do
-          include_context 'create symbolic link succeeds'
-          include_context 'delete is noop'
+        context "and the link does not yet exist" do
+          include_context "create symbolic link succeeds"
+          include_context "delete is noop"
         end
-        context 'and the link already exists and points to a different directory' do
+        context "and the link already exists and points to a different directory" do
           before(:each) do
             other_dir = File.join(test_file_dir, make_tmpname("other_dir"))
             Dir.mkdir(other_dir)
             symlink(other_dir, target_file)
           end
-          include_context 'create symbolic link succeeds'
+          include_context "create symbolic link succeeds"
         end
       end
       context "when the link destination is a symbolic link" do
-        context 'to a file that exists' do
+        context "to a file that exists" do
           before(:each) do
             @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
             File.open(@other_target, "w") { |file| file.write("eek") }
@@ -398,34 +402,32 @@ describe Chef::Resource::Link do
           after(:each) do
             File.delete(@other_target)
           end
-          context 'and the link does not yet exist' do
-            include_context 'create symbolic link succeeds'
-            include_context 'delete is noop'
+          context "and the link does not yet exist" do
+            include_context "create symbolic link succeeds"
+            include_context "delete is noop"
           end
         end
-        context 'to a file that does not exist' do
+        context "to a file that does not exist" do
           before(:each) do
             @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
             symlink(@other_target, to)
             expect(symlink?(to)).to be_truthy
             expect(readlink(to)).to eq(canonicalize(@other_target))
           end
-          context 'and the link does not yet exist' do
-            include_context 'create symbolic link succeeds'
-            include_context 'delete is noop'
+          context "and the link does not yet exist" do
+            include_context "create symbolic link succeeds"
+            include_context "delete is noop"
           end
         end
       end
-      context "when the link destination is not readable to this user", :skip => true do
-      end
       context "when the link destination does not exist" do
-        include_context 'create symbolic link succeeds'
-        include_context 'delete is noop'
+        include_context "create symbolic link succeeds"
+        include_context "delete is noop"
       end
 
       {
-        '../' => 'with a relative link destination',
-        '' => 'with a bare filename for the link destination'
+        "../" => "with a relative link destination",
+        "" => "with a bare filename for the link destination",
       }.each do |prefix, desc|
         context desc do
           let(:to) { "#{prefix}#{File.basename(absolute_to)}" }
@@ -433,27 +435,27 @@ describe Chef::Resource::Link do
           before(:each) do
             resource.to(to)
           end
-          context 'when the link does not yet exist' do
-            include_context 'create symbolic link succeeds'
-            include_context 'delete is noop'
+          context "when the link does not yet exist" do
+            include_context "create symbolic link succeeds"
+            include_context "delete is noop"
           end
-          context 'when the link already exists and points at the target' do
+          context "when the link already exists and points at the target" do
             before(:each) do
               symlink(to, target_file)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(to))
             end
-            include_context 'create symbolic link is noop'
-            include_context 'delete succeeds'
+            include_context "create symbolic link is noop"
+            include_context "delete succeeds"
           end
-          context 'when the link already exists and points at the target with an absolute path' do
+          context "when the link already exists and points at the target with an absolute path" do
             before(:each) do
               symlink(absolute_to, target_file)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(absolute_to))
             end
-            include_context 'create symbolic link succeeds'
-            include_context 'delete succeeds'
+            include_context "create symbolic link succeeds"
+            include_context "delete succeeds"
           end
         end
       end
@@ -467,12 +469,12 @@ describe Chef::Resource::Link do
       context "when the link destination is a file" do
         before(:each) do
           File.open(to, "w") do |file|
-            file.write('woohoo')
+            file.write("woohoo")
           end
         end
         context "and the link does not yet exist" do
-          include_context 'create hard link succeeds'
-          include_context 'delete is noop'
+          include_context "create hard link succeeds"
+          include_context "delete is noop"
         end
         context "and the link already exists and is a symbolic link pointing at the same file" do
           before(:each) do
@@ -480,34 +482,34 @@ describe Chef::Resource::Link do
             expect(symlink?(target_file)).to be_truthy
             expect(readlink(target_file)).to eq(canonicalize(to))
           end
-          include_context 'create hard link succeeds'
-          it_behaves_like 'delete errors out'
+          include_context "create hard link succeeds"
+          it_behaves_like "delete errors out"
         end
-        context 'and the link already exists and is a hard link to the file' do
+        context "and the link already exists and is a hard link to the file" do
           before(:each) do
             link(to, target_file)
             expect(File.exists?(target_file)).to be_truthy
             expect(symlink?(target_file)).to be_falsey
           end
-          include_context 'create hard link is noop'
-          include_context 'delete succeeds'
-          it 'the :delete action does not delete the target file' do
+          include_context "create hard link is noop"
+          include_context "delete succeeds"
+          it "the :delete action does not delete the target file" do
             resource.run_action(:delete)
             expect(File.exists?(to)).to be_truthy
           end
         end
         context "and the link already exists and is a file" do
           before(:each) do
-            File.open(target_file, 'w') { |file| file.write('tomfoolery') }
+            File.open(target_file, "w") { |file| file.write("tomfoolery") }
           end
-          include_context 'create hard link succeeds'
-          it_behaves_like 'delete errors out'
+          include_context "create hard link succeeds"
+          it_behaves_like "delete errors out"
         end
         context "and the link already exists and is a directory" do
           before(:each) do
             Dir.mkdir(target_file)
           end
-          it 'errors out' do
+          it "errors out" do
             if windows?
               expect { resource.run_action(:create) }.to raise_error(Errno::EACCES)
             elsif os_x? or solaris? or freebsd? or aix?
@@ -516,20 +518,18 @@ describe Chef::Resource::Link do
               expect { resource.run_action(:create) }.to raise_error(Errno::EISDIR)
             end
           end
-          it_behaves_like 'delete errors out'
-        end
-        context "and the link already exists and is not writeable to this user", :skip => true do
+          it_behaves_like "delete errors out"
         end
         context "and specifies security attributes" do
           before(:each) do
-            resource.owner(windows? ? 'Guest' : 'nobody')
+            resource.owner(windows? ? "Guest" : "nobody")
           end
-          it 'ignores them' do
+          it "ignores them" do
             resource.run_action(:create)
             if windows?
               expect(Chef::ReservedNames::Win32::Security.get_named_security_info(target_file).owner).not_to eq(SID.Guest)
             else
-              expect(File.lstat(target_file).uid).not_to eq(Etc.getpwnam('nobody').uid)
+              expect(File.lstat(target_file).uid).not_to eq(Etc.getpwnam("nobody").uid)
             end
           end
         end
@@ -538,15 +538,15 @@ describe Chef::Resource::Link do
         before(:each) do
           Dir.mkdir(to)
         end
-        context 'and the link does not yet exist' do
-          it 'create errors out' do
+        context "and the link does not yet exist" do
+          it "create errors out" do
             expect { resource.run_action(:create) }.to raise_error(windows? ? Chef::Exceptions::Win32APIError : Errno::EPERM)
           end
-          include_context 'delete is noop'
+          include_context "delete is noop"
         end
       end
       context "when the link destination is a symbolic link" do
-        context 'to a real file' do
+        context "to a real file" do
           before(:each) do
             @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
             File.open(@other_target, "w") { |file| file.write("eek") }
@@ -557,28 +557,28 @@ describe Chef::Resource::Link do
           after(:each) do
             File.delete(@other_target)
           end
-          context 'and the link does not yet exist' do
-            it 'links to the target file' do
+          context "and the link does not yet exist" do
+            it "links to the target file" do
+              skip("OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks") if (os_x? or freebsd? or aix?)
               resource.run_action(:create)
               expect(File.exists?(target_file)).to be_truthy
               # OS X gets angry about this sort of link.  Bug in OS X, IMO.
-              pending('OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks') if (os_x? or freebsd? or aix?)
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(@other_target))
             end
-            include_context 'delete is noop'
+            include_context "delete is noop"
           end
         end
-        context 'to a nonexistent file' do
+        context "to a nonexistent file" do
           before(:each) do
             @other_target = File.join(test_file_dir, make_tmpname("other_spec"))
             symlink(@other_target, to)
             expect(symlink?(to)).to be_truthy
             expect(readlink(to)).to eq(canonicalize(@other_target))
           end
-          context 'and the link does not yet exist' do
-            it 'links to the target file' do
-              pending('OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks') if (os_x? or freebsd? or aix?)
+          context "and the link does not yet exist" do
+            it "links to the target file" do
+              skip("OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks") if (os_x? or freebsd? or aix?)
               resource.run_action(:create)
               # Windows and Unix have different definitions of exists? here, and that's OK.
               if windows?
@@ -589,18 +589,17 @@ describe Chef::Resource::Link do
               expect(symlink?(target_file)).to be_truthy
               expect(readlink(target_file)).to eq(canonicalize(@other_target))
             end
-            include_context 'delete is noop'
+            include_context "delete is noop"
           end
         end
       end
-      context "when the link destination is not readable to this user", :skip => true do
-      end
+
       context "when the link destination does not exist" do
-        context 'and the link does not yet exist' do
-          it 'create errors out' do
+        context "and the link does not yet exist" do
+          it "create errors out" do
             expect { resource.run_action(:create) }.to raise_error(Errno::ENOENT)
           end
-          include_context 'delete is noop'
+          include_context "delete is noop"
         end
       end
     end
@@ -608,7 +607,7 @@ describe Chef::Resource::Link do
 
   describe "when not supported on platform", :win2k3_only do
     it "raises error" do
-      expect {resource}.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented)
+      expect { resource }.to raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented)
     end
   end
 end
diff --git a/spec/functional/resource/mount_spec.rb b/spec/functional/resource/mount_spec.rb
index a016d12..7f08889 100644
--- a/spec/functional/resource/mount_spec.rb
+++ b/spec/functional/resource/mount_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,17 @@
 # limitations under the License.
 #
 
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
-require 'tmpdir'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
+require "tmpdir"
 
 # run this test only for following platforms.
-include_flag = !(['ubuntu', 'centos', 'aix', 'solaris2'].include?(ohai[:platform]))
+include_flag = !(["ubuntu", "centos", "aix", "solaris2"].include?(ohai[:platform]))
 
-describe Chef::Resource::Mount, :requires_root, :external => include_flag do
+describe Chef::Resource::Mount, :requires_root, :skip_travis, :external => include_flag do
+  # Disabled in travis because it refuses to let us mount a ramdisk. /dev/ramX does not
+  # exist even after loading the kernel module
 
   include Chef::Mixin::ShellOut
 
@@ -34,13 +37,11 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
     # This can cleaner if we have chef resource/provider for ramdisk.
     case ohai[:platform]
     when "aix"
-      ramdisk = shell_out!("mkramdisk 16M").stdout
-
-      # identify device, for /dev/rramdisk0 it is /dev/ramdisk0
-      device = ramdisk.tr("\n","").gsub(/\/rramdisk/, '/ramdisk')
-
-      fstype = "jfs2"
-      shell_out!("mkfs  -V #{fstype} #{device}")
+      # On AIX, we can't create a ramdisk inside a WPAR, so we use
+      # a "namefs" mount against / to test
+      # https://www-304.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.performance/namefs_file_sys.htm
+      device = "/"
+      fstype = "namefs"
     when "ubuntu", "centos"
       device = "/dev/ram1"
       shell_out("ls -1 /dev/ram*").stdout.each_line do |d|
@@ -60,15 +61,6 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
     [device, fstype]
   end
 
-  def cleanup_device(device)
-    case ohai[:platform]
-    when "aix"
-      ramdisk = device.gsub(/\/ramdisk/, '/rramdisk')
-      shell_out("rmramdisk #{ramdisk}")
-    else
-    end
-  end
-
   def cleanup_mount(mount_point)
     shell_out("umount #{mount_point}")
   end
@@ -87,9 +79,9 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
 
   def unix_mount_config_file
     case ohai[:platform]
-    when 'aix'
+    when "aix"
       mount_config = "/etc/filesystems"
-    when 'solaris2'
+    when "solaris2"
       mount_config = "/etc/vfstab"
     else
       mount_config = "/etc/fstab"
@@ -98,7 +90,7 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
 
   def mount_should_be_enabled(mount_point, device)
     case ohai[:platform]
-    when 'aix'
+    when "aix"
       expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}:\" ").exitstatus).to eq(0)
     else
       expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}\" | grep \"#{device}\" ").exitstatus).to eq(0)
@@ -114,7 +106,7 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
     new_resource.device      @device
     new_resource.name        @mount_point
     new_resource.fstype      @fstype
-    new_resource.options     "log=NULL" if ohai[:platform] == 'aix'
+    new_resource.options     "log=NULL" if ohai[:platform] == "aix"
     new_resource
   end
 
@@ -146,7 +138,6 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
 
   after(:all) do
     Dir.rmdir(@mount_point)
-    cleanup_device(@device)
   end
 
   after(:each) do
@@ -172,10 +163,10 @@ describe Chef::Resource::Mount, :requires_root, :external => include_flag do
       mount_should_exist(new_resource.mount_point, new_resource.device)
 
       new_resource.supports[:remount] = true
-      new_resource.options "rw,log=NULL" if ohai[:platform] == 'aix'
+      new_resource.options "rw" if ohai[:platform] == "aix"
       new_resource.run_action(:remount)
 
-      mount_should_exist(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == 'aix') ? new_resource.options : nil)
+      mount_should_exist(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == "aix") ? new_resource.options : nil)
     end
   end
 
diff --git a/spec/functional/resource/ohai_spec.rb b/spec/functional/resource/ohai_spec.rb
index da47b9e..9ce989d 100644
--- a/spec/functional/resource/ohai_spec.rb
+++ b/spec/functional/resource/ohai_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Ohai do
   let(:ohai) {
-    o = Ohai::System.new
-    o.all_plugins
-    o
+    OHAI_SYSTEM
   }
 
   let(:node) { Chef::Node.new }
@@ -47,7 +45,7 @@ describe Chef::Resource::Ohai do
   end
 
   describe "when reloading all plugins" do
-    let(:ohai_resource) { Chef::Resource::Ohai.new("reload all", run_context)}
+    let(:ohai_resource) { Chef::Resource::Ohai.new("reload all", run_context) }
 
     it_behaves_like "reloaded :uptime"
   end
@@ -59,7 +57,6 @@ describe Chef::Resource::Ohai do
       r
     }
 
-
     it_behaves_like "reloaded :uptime"
   end
 end
diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb
index 5c17ca0..36b106b 100644
--- a/spec/functional/resource/package_spec.rb
+++ b/spec/functional/resource/package_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'webrick'
+require "spec_helper"
+require "webrick"
 
 module AptServer
   def enable_testing_apt_source
@@ -54,7 +54,7 @@ module AptServer
       :DocumentRoot => apt_data_dir + "/var/www/apt",
       # Make WEBrick quiet, comment out for debug.
       :Logger       => Logger.new(StringIO.new),
-      :AccessLog    => [ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ]
+      :AccessLog    => [ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
     )
   end
 
@@ -87,9 +87,9 @@ module AptServer
 end
 
 metadata = { :unix_only => true,
-  :requires_root => true,
-  :provider => {:package => Chef::Provider::Package::Apt},
-  :arch => "x86_64" # test packages are 64bit
+             :requires_root => true,
+             :provider => { :package => Chef::Provider::Package::Apt },
+             :arch => "x86_64" # test packages are 64bit
 }
 
 describe Chef::Resource::Package, metadata do
@@ -112,7 +112,6 @@ describe Chef::Resource::Package, metadata do
       shell_out!("apt-get clean")
     end
 
-
     after do
       shell_out!("dpkg -r chef-integration-test")
       shell_out("dpkg --clear-avail")
@@ -239,7 +238,7 @@ describe Chef::Resource::Package, metadata do
             it "does not update the package configuration" do
               package_resource.run_action(:install)
               cmd = shell_out!("debconf-show chef-integration-test")
-              expect(cmd.stdout).to include('chef-integration-test/sample-var: INVALID')
+              expect(cmd.stdout).to include("chef-integration-test/sample-var: INVALID")
               expect(package_resource).to be_updated_by_last_action
             end
 
@@ -276,7 +275,7 @@ describe Chef::Resource::Package, metadata do
               r = base_resource
               r.cookbook_name = "preseed"
               r.response_file("preseed-template-variables.seed")
-              r.response_file_variables({ :template_variable => 'SUPPORTS VARIABLES' })
+              r.response_file_variables({ :template_variable => "SUPPORTS VARIABLES" })
               r
             end
 
@@ -325,14 +324,13 @@ describe Chef::Resource::Package, metadata do
       # un  chef-integration-test             <none>                                    (no description available)
       def pkg_should_be_removed
         # will raise if exit code != 0,1
-        pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0,1])
+        pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0, 1])
 
         if pkg_check.exitstatus == 0
           expect(pkg_check.stdout).to match(/un[\s]+chef-integration-test/)
         end
       end
 
-
       it "removes the package for action :remove" do
         package_resource.run_action(:remove)
         pkg_should_be_removed
@@ -386,5 +384,3 @@ describe Chef::Resource::Package, metadata do
   end
 
 end
-
-
diff --git a/spec/functional/resource/powershell_script_spec.rb b/spec/functional/resource/powershell_script_spec.rb
new file mode 100644
index 0000000..7a7f7a2
--- /dev/null
+++ b/spec/functional/resource/powershell_script_spec.rb
@@ -0,0 +1,601 @@
+#
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/platform/query_helpers"
+require "spec_helper"
+
+describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
+
+  include_context Chef::Resource::WindowsScript
+
+  let (:architecture_command) { "echo $env:PROCESSOR_ARCHITECTURE" }
+  let (:output_command) { " | out-file -encoding ASCII " }
+
+  it_behaves_like "a Windows script running on Windows"
+
+  let(:successful_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
+  let(:failed_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe /badargument" }
+  let(:processor_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTURE" }
+  let(:native_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTUREW6432" }
+  let(:cmdlet_exit_code_not_found_content) { "get-item '.\\thisdoesnotexist'" }
+  let(:cmdlet_exit_code_success_content) { "get-item ." }
+  let(:windows_process_exit_code_success_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
+  let(:windows_process_exit_code_not_found_content) { "findstr /notavalidswitch" }
+  # Note that process exit codes on 32-bit Win2k3 cannot
+  # exceed maximum value of signed integer
+  let(:arbitrary_nonzero_process_exit_code) { 4193 }
+  let(:arbitrary_nonzero_process_exit_code_content) { "exit #{arbitrary_nonzero_process_exit_code}" }
+  let(:invalid_powershell_interpreter_flag) { "/thisflagisinvalid" }
+  let(:valid_powershell_interpreter_flag) { "-Sta" }
+
+  let!(:resource) do
+    r = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context)
+    r.code(successful_executable_script_content)
+    r
+  end
+
+  describe "when the run action is invoked on Windows" do
+    it "successfully executes a non-cmdlet Windows binary as the last command of the script" do
+      resource.code(successful_executable_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "returns the exit status 27 for a powershell script that exits with 27" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      file = Tempfile.new(["foo", ".ps1"])
+      begin
+        file.write "exit 27"
+        file.close
+        resource.code(". \"#{file.path}\"")
+        resource.returns(27)
+        resource.run_action(:run)
+      ensure
+        file.close
+        file.unlink
+      end
+    end
+
+    let (:negative_exit_status) { -27 }
+    let (:unsigned_exit_status) { (-negative_exit_status ^ 65535) + 1 }
+    it "returns the exit status -27 as a signed integer or an unsigned 16-bit 2's complement value of 65509 for a powershell script that exits with -27" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      # Versions of PowerShell prior to 4.0 return a 16-bit unsigned value --
+      # PowerShell 4.0 and later versions return a 32-bit signed value.
+      file = Tempfile.new(["foo", ".ps1"])
+      begin
+        file.write "exit #{negative_exit_status}"
+        file.close
+        resource.code(". \"#{file.path}\"")
+
+        # PowerShell earlier than 4.0 takes negative exit codes
+        # and returns them as the underlying unsigned 16-bit
+        # 2's complement representation. We cover multiple versions
+        # of PowerShell in this example by including both the signed
+        # exit code and its converted counterpart as permitted return values.
+        # See http://support.microsoft.com/en-us/kb/2646183/zh-cn
+        resource.returns([negative_exit_status, unsigned_exit_status])
+        expect { resource.run_action(:run) }.not_to raise_error
+      ensure
+        file.close
+        file.unlink
+      end
+    end
+
+    it "returns the process exit code" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code(arbitrary_nonzero_process_exit_code_content)
+      resource.returns(arbitrary_nonzero_process_exit_code)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 if the last command was a cmdlet that succeeded" do
+      resource.code(cmdlet_exit_code_success_content)
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 if the last command was a cmdlet that succeeded and was preceded by a non-cmdlet Windows binary that failed" do
+      resource.code([windows_process_exit_code_not_found_content, cmdlet_exit_code_success_content].join(";"))
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "returns 1 if the last command was a cmdlet that failed" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code(cmdlet_exit_code_not_found_content)
+      resource.returns(1)
+      resource.run_action(:run)
+    end
+
+    it "returns 1 if the last command was a cmdlet that failed and was preceded by a successfully executed non-cmdlet Windows binary" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(";"))
+      resource.returns(1)
+      expect { resource.run_action(:run) }.not_to raise_error
+    end
+
+    it "raises a Mixlib::ShellOut::ShellCommandFailed error if the script is not syntactically correct" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code("if({)")
+      resource.returns(0)
+      expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+    end
+
+    it "raises an error if the script is not syntactically correct even if returns is set to 1 which is what powershell.exe returns for syntactically invalid scripts" do
+      # This test fails because shell_out expects the exit status to be 1, but it is actually 0
+      # The error is a false-positive.
+      skip "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code("if({)")
+      resource.returns(1)
+      expect { resource.run_action(:run) }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+    end
+
+    # This somewhat ambiguous case, two failures of different types,
+    # seems to violate the principle of returning the status of the
+    # last line executed -- in this case, we return the status of the
+    # second to last line. This happens because Powershell gives no
+    # way for us to determine whether the last operation was a cmdlet
+    # or Windows process. Because the latter gives more specific
+    # errors than 0 or 1, we return that instead, which is acceptable
+    # since callers can test for nonzero rather than testing for 1.
+    it "returns 1 if the last command was a cmdlet that failed and was preceded by an unsuccessfully executed non-cmdlet Windows binary" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code([arbitrary_nonzero_process_exit_code_content, cmdlet_exit_code_not_found_content].join(";"))
+      resource.returns(arbitrary_nonzero_process_exit_code)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 if the last command was a non-cmdlet Windows binary that succeeded and was preceded by a failed cmdlet" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(";"))
+      resource.returns(arbitrary_nonzero_process_exit_code)
+      resource.run_action(:run)
+    end
+
+    it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that succeeded" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(";"))
+      resource.returns(arbitrary_nonzero_process_exit_code)
+      resource.run_action(:run)
+    end
+
+    it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that failed" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code([cmdlet_exit_code_not_found_content, arbitrary_nonzero_process_exit_code_content].join(";"))
+      resource.returns(arbitrary_nonzero_process_exit_code)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 for $false as the last line of the script when convert_boolean_return is false" do
+      resource.code "$false"
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 for $true as the last line of the script when convert_boolean_return is false" do
+      resource.code "$true"
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "returns 1 for $false as the last line of the script when convert_boolean_return is true" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.convert_boolean_return true
+      resource.code "$false"
+      resource.returns(1)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 for $true as the last line of the script when convert_boolean_return is true" do
+      resource.convert_boolean_return true
+      resource.code "$true"
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "executes a script with a 64-bit process on a 64-bit OS, otherwise a 32-bit process" do
+      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      resource.returns(0)
+      resource.run_action(:run)
+
+      is_64_bit = (ENV["PROCESSOR_ARCHITECTURE"] == "AMD64") || (ENV["PROCESSOR_ARCHITEW6432"] == "AMD64")
+
+      detected_64_bit = source_contains_case_insensitive_content?( get_script_output, "AMD64" )
+
+      expect(is_64_bit).to eq(detected_64_bit)
+    end
+
+    it "returns 1 if an invalid flag is passed to the interpreter" do
+      pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+      resource.code(cmdlet_exit_code_success_content)
+      resource.flags(invalid_powershell_interpreter_flag)
+      resource.returns(1)
+      resource.run_action(:run)
+    end
+
+    it "returns 0 if a valid flag is passed to the interpreter" do
+      resource.code(cmdlet_exit_code_success_content)
+      resource.flags(valid_powershell_interpreter_flag)
+      resource.returns(0)
+      resource.run_action(:run)
+    end
+
+    it "raises an error when given a block and a guard_interpreter" do
+      resource.guard_interpreter :sh
+      resource.only_if { true }
+      expect { resource.should_skip?(:run) }.to raise_error(ArgumentError, /guard_interpreter does not support blocks/)
+    end
+
+    context "when dsc is supported", :windows_powershell_dsc_only do
+      it "can execute LCM configuration code" do
+        resource.code <<-EOF
+configuration LCM
+{
+  param ($thumbprint)
+  localconfigurationmanager
+  {
+    RebootNodeIfNeeded = $false
+    ConfigurationMode = 'ApplyOnly'
+  }
+}
+        EOF
+        expect { resource.run_action(:run) }.not_to raise_error
+      end
+    end
+  end
+
+  context "when running on a 32-bit version of Ruby", :ruby32_only do
+    it "executes a script with a 32-bit process if process architecture :i386 is specified" do
+      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      resource.architecture(:i386)
+      resource.returns(0)
+      resource.run_action(:run)
+
+      expect(source_contains_case_insensitive_content?( get_script_output, "x86" )).to eq(true)
+    end
+
+    context "when running on a 64-bit version of Windows", :windows64_only do
+      it "executes a script with a 64-bit process if :x86_64 arch is specified" do
+        resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+        resource.architecture(:x86_64)
+        resource.returns(0)
+        resource.run_action(:run)
+
+        expect(source_contains_case_insensitive_content?( get_script_output, "AMD64" )).to eq(true)
+      end
+    end
+
+    context "when running on a 32-bit version of Windows", :windows32_only do
+      it "raises an exception if :x86_64 process architecture is specified" do
+        begin
+          expect(resource.architecture(:x86_64)).to raise_error Chef::Exceptions::Win32ArchitectureIncorrect
+        rescue Chef::Exceptions::Win32ArchitectureIncorrect
+        end
+      end
+    end
+  end
+
+  context "when running on a 64-bit version of Ruby", :ruby64_only do
+    it "executes a script with a 64-bit process if :x86_64 arch is specified" do
+      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      resource.architecture(:x86_64)
+      resource.returns(0)
+      resource.run_action(:run)
+
+      expect(source_contains_case_insensitive_content?( get_script_output, "AMD64" )).to eq(true)
+    end
+
+    it "executes a script with a 32-bit process if :i386 arch is specified", :not_supported_on_nano do
+      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      resource.architecture(:i386)
+      resource.returns(0)
+      resource.run_action(:run)
+
+      expect(source_contains_case_insensitive_content?( get_script_output, "x86" )).to eq(true)
+    end
+
+    it "raises an error when executing a script with a 32-bit process on Windows Nano Server", :windows_nano_only do
+      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
+      expect { resource.architecture(:i386) }.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect,
+        "cannot execute script with requested architecture 'i386' on Windows Nano Server")
+    end
+  end
+
+  describe "when executing guards" do
+    before(:each) do
+      resource.not_if.clear
+      resource.only_if.clear
+    end
+
+    context "when the guard_interpreter's default value of :powershell_script is overridden to :default" do
+      before(:each) do
+        resource.guard_interpreter :default
+      end
+
+      it "evaluates a succeeding not_if block using cmd.exe as false by default" do
+        resource.not_if "exit /b 0"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a failing not_if block using cmd.exe as true by default" do
+        resource.not_if "exit /b 2"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates an succeeding only_if block using cmd.exe as true by default" do
+        resource.only_if "exit /b 0"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a failing only_if block using cmd.exe as false by default" do
+        resource.only_if "exit /b 2"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+    end
+
+    context "the only_if is specified before the guard" do
+      before do
+        resource.guard_interpreter :default
+      end
+
+      it "evaluates a powershell $true for a only_if block as true" do
+        resource.only_if "$true"
+        resource.guard_interpreter :powershell_script
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+    end
+
+    context "with powershell_script as the guard_interpreter" do
+
+      it "has a guard_interpreter attribute set to :powershell_script" do
+        expect(resource.guard_interpreter).to eq(:powershell_script)
+      end
+
+      it "evaluates a powershell $false for a not_if block as true" do
+        pending "powershell.exe always exits with $true on nano" if Chef::Platform.windows_nano_server?
+
+        resource.not_if "$false"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a powershell $true for a not_if block as false" do
+        resource.not_if "$true"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a powershell $false for an only_if block as false" do
+        pending "powershell.exe always exits with $true on nano" if Chef::Platform.windows_nano_server?
+
+        resource.only_if "$false"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a powershell $true for a only_if block as true" do
+        resource.only_if "$true"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a not_if block using powershell.exe" do
+        resource.not_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates an only_if block using powershell.exe" do
+        resource.only_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a non-zero powershell exit status for not_if as true" do
+        pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+        resource.not_if "exit 37"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a zero powershell exit status for not_if as false" do
+        resource.not_if "exit 0"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a failed executable exit status for not_if as false" do
+        pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
+
+        resource.not_if windows_process_exit_code_not_found_content
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a successful executable exit status for not_if as true" do
+        resource.not_if windows_process_exit_code_success_content
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a failed executable exit status for only_if as false" do
+        pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
+
+        resource.only_if windows_process_exit_code_not_found_content
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a successful executable exit status for only_if as true" do
+        resource.only_if windows_process_exit_code_success_content
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a failed cmdlet exit status for not_if as true" do
+        pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
+
+        resource.not_if "throw 'up'"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a successful cmdlet exit status for not_if as true" do
+        resource.not_if  "cd ."
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a failed cmdlet exit status for only_if as false" do
+        pending "powershell.exe always exits with success on nano" if Chef::Platform.windows_nano_server?
+
+        resource.only_if "throw 'up'"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a successful cmdlet exit status for only_if as true" do
+        resource.only_if "cd ."
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a not_if block using the cwd guard parameter" do
+        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
+        resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates an only_if block using the cwd guard parameter" do
+        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
+        resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "inherits cwd from the parent resource for only_if" do
+        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
+        resource.cwd custom_cwd
+        resource.only_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "inherits cwd from the parent resource for not_if" do
+        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
+        resource.cwd custom_cwd
+        resource.not_if "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a 64-bit resource with a 64-bit guard and interprets boolean false as zero status code", :windows64_only do
+        resource.architecture :x86_64
+        resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'AMD64')"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a 64-bit resource with a 64-bit guard and interprets boolean true as nonzero status code", :windows64_only do
+        pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+        resource.architecture :x86_64
+        resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'AMD64')"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code", :not_supported_on_nano do
+        resource.architecture :i386
+        resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'X86')"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code", :not_supported_on_nano do
+        resource.architecture :i386
+        resource.only_if "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'X86')"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a simple boolean false as nonzero status code when convert_boolean_return is true for only_if" do
+        pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+        resource.convert_boolean_return true
+        resource.only_if "$false"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a simple boolean false as nonzero status code when convert_boolean_return is true for not_if" do
+        pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
+        resource.convert_boolean_return true
+        resource.not_if "$false"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for only_if" do
+        resource.convert_boolean_return true
+        resource.only_if "$true"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for not_if" do
+        resource.convert_boolean_return true
+        resource.not_if "$true"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for only_if", :not_supported_on_nano do
+        resource.convert_boolean_return true
+        resource.architecture :i386
+        resource.only_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for not_if", :not_supported_on_nano do
+        resource.convert_boolean_return true
+        resource.architecture :i386
+        resource.not_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
+        expect(resource.should_skip?(:run)).to be_falsey
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for only_if", :not_supported_on_nano do
+        resource.convert_boolean_return true
+        resource.architecture :i386
+        resource.only_if "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for not_if", :not_supported_on_nano do
+        resource.convert_boolean_return true
+        resource.architecture :i386
+        resource.not_if "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
+        expect(resource.should_skip?(:run)).to be_truthy
+      end
+
+      it "raises an error when a 32-bit guard is used on Windows Nano Server", :windows_nano_only do
+        resource.only_if "$true", :architecture => :i386
+        expect { resource.run_action(:run) }.to raise_error(
+          Chef::Exceptions::Win32ArchitectureIncorrect,
+          /cannot execute script with requested architecture 'i386' on Windows Nano Server/)
+      end
+    end
+  end
+
+  def get_script_output
+    script_output = File.read(script_output_path)
+  end
+
+  def source_contains_case_insensitive_content?( source, content )
+    source.downcase.include?(content.downcase)
+  end
+end
diff --git a/spec/functional/resource/powershell_spec.rb b/spec/functional/resource/powershell_spec.rb
deleted file mode 100644
index 56a905e..0000000
--- a/spec/functional/resource/powershell_spec.rb
+++ /dev/null
@@ -1,477 +0,0 @@
-#
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-
-describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do
-
-  include_context Chef::Resource::WindowsScript
-
-  let (:architecture_command) { 'echo $env:PROCESSOR_ARCHITECTURE' }
-  let (:output_command) { ' | out-file -encoding ASCII ' }
-
-  it_behaves_like "a Windows script running on Windows"
-
-
-  let(:successful_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
-  let(:failed_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe /badargument" }
-  let(:processor_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTURE" }
-  let(:native_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTUREW6432" }
-  let(:cmdlet_exit_code_not_found_content) { "get-item '.\\thisdoesnotexist'" }
-  let(:cmdlet_exit_code_success_content) { "get-item ." }
-  let(:windows_process_exit_code_success_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" }
-  let(:windows_process_exit_code_not_found_content) { "findstr /notavalidswitch" }
-  # Note that process exit codes on 32-bit Win2k3 cannot
-  # exceed maximum value of signed integer
-  let(:arbitrary_nonzero_process_exit_code) { 4193 }
-  let(:arbitrary_nonzero_process_exit_code_content) { "exit #{arbitrary_nonzero_process_exit_code}" }
-  let(:invalid_powershell_interpreter_flag) { "/thisflagisinvalid" }
-  let(:valid_powershell_interpreter_flag) { "-Sta" }
-
-  let!(:resource) do
-    r = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context)
-    r.code(successful_executable_script_content)
-    r
-  end
-
-  describe "when the run action is invoked on Windows" do
-    it "successfully executes a non-cmdlet Windows binary as the last command of the script" do
-      resource.code(successful_executable_script_content + " | out-file -encoding ASCII #{script_output_path}")
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "returns the -27 for a powershell script that exits with -27", :windows_powershell_dsc_only do
-      # This is broken on Powershell < 4.0
-      file = Tempfile.new(['foo', '.ps1'])
-      begin
-        file.write "exit -27"
-        file.close
-        resource.code(". \"#{file.path}\"")
-        resource.returns(-27)
-        resource.run_action(:run)
-      ensure
-        file.close
-        file.unlink
-      end
-    end
-
-
-    it "returns the process exit code" do
-      resource.code(arbitrary_nonzero_process_exit_code_content)
-      resource.returns(arbitrary_nonzero_process_exit_code)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 if the last command was a cmdlet that succeeded" do
-      resource.code(cmdlet_exit_code_success_content)
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 if the last command was a cmdlet that succeeded and was preceded by a non-cmdlet Windows binary that failed" do
-      resource.code([windows_process_exit_code_not_found_content, cmdlet_exit_code_success_content].join(';'))
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "returns 1 if the last command was a cmdlet that failed" do
-      resource.code(cmdlet_exit_code_not_found_content)
-      resource.returns(1)
-      resource.run_action(:run)
-    end
-
-    it "returns 1 if the last command was a cmdlet that failed and was preceded by a successfully executed non-cmdlet Windows binary" do
-      resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(';'))
-      resource.returns(1)
-      resource.run_action(:run)
-    end
-
-    # This somewhat ambiguous case, two failures of different types,
-    # seems to violate the principle of returning the status of the
-    # last line executed -- in this case, we return the status of the
-    # second to last line. This happens because Powershell gives no
-    # way for us to determine whether the last operation was a cmdlet
-    # or Windows process. Because the latter gives more specific
-    # errors than 0 or 1, we return that instead, which is acceptable
-    # since callers can test for nonzero rather than testing for 1.
-    it "returns 1 if the last command was a cmdlet that failed and was preceded by an unsuccessfully executed non-cmdlet Windows binary" do
-      resource.code([arbitrary_nonzero_process_exit_code_content,cmdlet_exit_code_not_found_content].join(';'))
-      resource.returns(arbitrary_nonzero_process_exit_code)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 if the last command was a non-cmdlet Windows binary that succeeded and was preceded by a failed cmdlet" do
-      resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';'))
-      resource.returns(arbitrary_nonzero_process_exit_code)
-      resource.run_action(:run)
-    end
-
-    it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that succeeded" do
-      resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';'))
-      resource.returns(arbitrary_nonzero_process_exit_code)
-      resource.run_action(:run)
-    end
-
-    it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that failed" do
-      resource.code([cmdlet_exit_code_not_found_content, arbitrary_nonzero_process_exit_code_content].join(';'))
-      resource.returns(arbitrary_nonzero_process_exit_code)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 for $false as the last line of the script when convert_boolean_return is false" do
-      resource.code "$false"
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 for $true as the last line of the script when convert_boolean_return is false" do
-      resource.code "$true"
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "returns 1 for $false as the last line of the script when convert_boolean_return is true" do
-      resource.convert_boolean_return true
-      resource.code "$false"
-      resource.returns(1)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 for $true as the last line of the script when convert_boolean_return is true" do
-      resource.convert_boolean_return true
-      resource.code "$true"
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "executes a script with a 64-bit process on a 64-bit OS, otherwise a 32-bit process" do
-      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
-      resource.returns(0)
-      resource.run_action(:run)
-
-      is_64_bit = (ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64') || (ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64')
-
-      detected_64_bit = source_contains_case_insensitive_content?( get_script_output, 'AMD64' )
-
-      expect(is_64_bit).to eq(detected_64_bit)
-    end
-
-    it "returns 1 if an invalid flag is passed to the interpreter" do
-      resource.code(cmdlet_exit_code_success_content)
-      resource.flags(invalid_powershell_interpreter_flag)
-      resource.returns(1)
-      resource.run_action(:run)
-    end
-
-    it "returns 0 if a valid flag is passed to the interpreter" do
-      resource.code(cmdlet_exit_code_success_content)
-      resource.flags(valid_powershell_interpreter_flag)
-      resource.returns(0)
-      resource.run_action(:run)
-    end
-
-    it "raises an error when given a block and a guard_interpreter" do
-      resource.guard_interpreter :sh
-      resource.only_if { true }
-      expect { resource.should_skip?(:run) }.to raise_error(ArgumentError, /guard_interpreter does not support blocks/)
-    end
-
-  end
-
-  context "when running on a 32-bit version of Windows", :windows32_only do
-
-    it "executes a script with a 32-bit process if process architecture :i386 is specified" do
-      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
-      resource.architecture(:i386)
-      resource.returns(0)
-      resource.run_action(:run)
-
-      expect(source_contains_case_insensitive_content?( get_script_output, 'x86' )).to eq(true)
-    end
-
-    it "raises an exception if :x86_64 process architecture is specified" do
-      begin
-        expect(resource.architecture(:x86_64)).to raise_error Chef::Exceptions::Win32ArchitectureIncorrect
-      rescue Chef::Exceptions::Win32ArchitectureIncorrect
-      end
-    end
-  end
-
-  context "when running on a 64-bit version of Windows", :windows64_only do
-    it "executes a script with a 64-bit process if :x86_64 arch is specified" do
-      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
-      resource.architecture(:x86_64)
-      resource.returns(0)
-      resource.run_action(:run)
-
-      expect(source_contains_case_insensitive_content?( get_script_output, 'AMD64' )).to eq(true)
-    end
-
-    it "executes a script with a 32-bit process if :i386 arch is specified" do
-      resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}")
-      resource.architecture(:i386)
-      resource.returns(0)
-      resource.run_action(:run)
-
-      expect(source_contains_case_insensitive_content?( get_script_output, 'x86' )).to eq(true)
-    end
-  end
-
-  describe "when executing guards" do
-    before(:each) do
-      resource.not_if.clear
-      resource.only_if.clear
-    end
-
-    context "when the guard_interpreter's default value of :powershell_script is overridden to :default" do
-      before(:each) do
-        resource.guard_interpreter :default
-      end
-
-      it "evaluates a succeeding not_if block using cmd.exe as false by default" do
-        resource.not_if  "exit /b 0"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a failing not_if block using cmd.exe as true by default" do
-        resource.not_if  "exit /b 2"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates an succeeding only_if block using cmd.exe as true by default" do
-        resource.only_if  "exit /b 0"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a failing only_if block using cmd.exe as false by default" do
-        resource.only_if  "exit /b 2"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-    end
-
-    context "the only_if is specified before the guard" do
-      before do
-        resource.guard_interpreter :default
-      end
-
-      it "evaluates a powershell $true for a only_if block as true" do
-        resource.only_if "$true"
-        resource.guard_interpreter :powershell_script
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-    end
-
-    context "with powershell_script as the guard_interpreter" do
-
-      it "has a guard_interpreter attribute set to :powershell_script" do
-        expect(resource.guard_interpreter).to eq(:powershell_script)
-      end
-
-      it "evaluates a powershell $false for a not_if block as true" do
-        resource.not_if  "$false"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a powershell $true for a not_if block as false" do
-        resource.not_if  "$true"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a powershell $false for an only_if block as false" do
-        resource.only_if  "$false"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a powershell $true for a only_if block as true" do
-        resource.only_if  "$true"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a not_if block using powershell.exe" do
-        resource.not_if  "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates an only_if block using powershell.exe" do
-        resource.only_if  "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a non-zero powershell exit status for not_if as true" do
-        resource.not_if  "exit 37"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a zero powershell exit status for not_if as false" do
-        resource.not_if  "exit 0"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a failed executable exit status for not_if as false" do
-        resource.not_if  windows_process_exit_code_not_found_content
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a successful executable exit status for not_if as true" do
-        resource.not_if  windows_process_exit_code_success_content
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a failed executable exit status for only_if as false" do
-        resource.only_if  windows_process_exit_code_not_found_content
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a successful executable exit status for only_if as true" do
-        resource.only_if  windows_process_exit_code_success_content
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a failed cmdlet exit status for not_if as true" do
-        resource.not_if  "throw 'up'"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a successful cmdlet exit status for not_if as true" do
-        resource.not_if  "cd ."
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a failed cmdlet exit status for only_if as false" do
-        resource.only_if  "throw 'up'"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a successful cmdlet exit status for only_if as true" do
-        resource.only_if  "cd ."
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a not_if block using the cwd guard parameter" do
-        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
-        resource.not_if  "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates an only_if block using the cwd guard parameter" do
-        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
-        resource.only_if  "exit ! [int32]($pwd.path -eq '#{custom_cwd}')", :cwd => custom_cwd
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "inherits cwd from the parent resource for only_if" do
-        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
-        resource.cwd custom_cwd
-        resource.only_if  "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "inherits cwd from the parent resource for not_if" do
-        custom_cwd = "#{ENV['SystemRoot']}\\system32\\drivers\\etc"
-        resource.cwd custom_cwd
-        resource.not_if  "exit ! [int32]($pwd.path -eq '#{custom_cwd}')"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a 64-bit resource with a 64-bit guard and interprets boolean false as zero status code", :windows64_only do
-        resource.architecture :x86_64
-        resource.only_if  "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'AMD64')"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a 64-bit resource with a 64-bit guard and interprets boolean true as nonzero status code", :windows64_only do
-        resource.architecture :x86_64
-        resource.only_if  "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'AMD64')"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code" do
-        resource.architecture :i386
-        resource.only_if  "exit [int32]($env:PROCESSOR_ARCHITECTURE -ne 'X86')"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code" do
-        resource.architecture :i386
-        resource.only_if  "exit [int32]($env:PROCESSOR_ARCHITECTURE -eq 'X86')"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a simple boolean false as nonzero status code when convert_boolean_return is true for only_if" do
-        resource.convert_boolean_return true
-        resource.only_if  "$false"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a simple boolean false as nonzero status code when convert_boolean_return is true for not_if" do
-        resource.convert_boolean_return true
-        resource.not_if  "$false"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for only_if" do
-        resource.convert_boolean_return true
-        resource.only_if  "$true"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a simple boolean true as 0 status code when convert_boolean_return is true for not_if" do
-        resource.convert_boolean_return true
-        resource.not_if  "$true"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for only_if" do
-        resource.convert_boolean_return true
-        resource.architecture :i386
-        resource.only_if  "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean false as zero status code using convert_boolean_return for not_if" do
-        resource.convert_boolean_return true
-        resource.architecture :i386
-        resource.not_if  "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
-        expect(resource.should_skip?(:run)).to be_falsey
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for only_if" do
-        resource.convert_boolean_return true
-        resource.architecture :i386
-        resource.only_if  "$env:PROCESSOR_ARCHITECTURE -ne 'X86'"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-
-      it "evaluates a 32-bit resource with a 32-bit guard and interprets boolean true as nonzero status code using convert_boolean_return for not_if" do
-        resource.convert_boolean_return true
-        resource.architecture :i386
-        resource.not_if  "$env:PROCESSOR_ARCHITECTURE -eq 'X86'"
-        expect(resource.should_skip?(:run)).to be_truthy
-      end
-    end
-  end
-
-  def get_script_output
-    script_output = File.read(script_output_path)
-  end
-
-  def source_contains_case_insensitive_content?( source, content )
-    source.downcase.include?(content.downcase)
-  end
-end
diff --git a/spec/functional/resource/reboot_spec.rb b/spec/functional/resource/reboot_spec.rb
index 99de136..3cf7f58 100644
--- a/spec/functional/resource/reboot_spec.rb
+++ b/spec/functional/resource/reboot_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Chris Doherty <cdoherty at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef, Inc.
+# Author:: Chris Doherty <cdoherty at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Reboot do
 
@@ -24,7 +24,7 @@ describe Chef::Resource::Reboot do
     {
       :delay_mins => 5,
       :requested_by => "reboot resource functional test",
-      :reason => "reboot resource spec test"
+      :reason => "reboot resource spec test",
     }
   end
 
@@ -42,7 +42,7 @@ describe Chef::Resource::Reboot do
     create_resource
   end
 
-  shared_context 'testing run context modification' do
+  shared_context "testing run context modification" do
     def test_reboot_action(resource)
       reboot_info = resource.run_context.reboot_info
       expect(reboot_info.keys.sort).to eq([:delay_mins, :reason, :requested_by, :timestamp])
@@ -55,8 +55,8 @@ describe Chef::Resource::Reboot do
   end
 
   # the currently defined behavior for multiple calls to this resource is "last one wins."
-  describe 'the request_reboot_on_successful_run action' do
-    include_context 'testing run context modification'
+  describe "the request_reboot_on_successful_run action" do
+    include_context "testing run context modification"
 
     before do
       resource.run_action(:request_reboot)
@@ -66,19 +66,19 @@ describe Chef::Resource::Reboot do
       resource.run_context.cancel_reboot
     end
 
-    it 'should have modified the run context correctly' do
+    it "should have modified the run context correctly" do
       test_reboot_action(resource)
     end
   end
 
-  describe 'the reboot_interrupt_run action' do
-    include_context 'testing run context modification'
+  describe "the reboot_interrupt_run action" do
+    include_context "testing run context modification"
 
     after do
       resource.run_context.cancel_reboot
     end
 
-    it 'should have modified the run context correctly' do
+    it "should have modified the run context correctly" do
       # this doesn't actually test the flow of Chef::Client#do_run, unfortunately.
       expect {
         resource.run_action(:reboot_now)
@@ -94,7 +94,7 @@ describe Chef::Resource::Reboot do
       resource.run_action(:cancel)
     end
 
-    it 'should have cleared the reboot request' do
+    it "should have cleared the reboot request" do
       # arguably we shouldn't be querying RunContext's internal data directly.
       expect(resource.run_context.reboot_info).to eq({})
       expect(resource.run_context.reboot_requested?).to be_falsey
diff --git a/spec/functional/resource/registry_spec.rb b/spec/functional/resource/registry_spec.rb
index f112ad9..6cf8524 100644
--- a/spec/functional/resource/registry_spec.rb
+++ b/spec/functional/resource/registry_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,15 +27,15 @@ describe Chef::Resource::RegistryKey, :unix_only do
     node = Chef::Node.new
     ohai = Ohai::System.new
     ohai.all_plugins
-    node.consume_external_attrs(ohai.data,{})
+    node.consume_external_attrs(ohai.data, {})
     run_context = Chef::RunContext.new(node, {}, events)
     @resource = Chef::Resource::RegistryKey.new("HKCU\\Software", run_context)
   end
   context "when load_current_resource is run on a non-windows node" do
     it "throws an exception because you don't have a windows registry (derp)" do
       @resource.key("HKCU\\Software\\Opscode")
-      @resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
-      expect{@resource.run_action(:create)}.to raise_error(Chef::Exceptions::Win32NotWindows)
+      @resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
+      expect { @resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32NotWindows)
     end
   end
 end
@@ -43,8 +43,8 @@ end
 describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
   # parent and key must be single keys, not paths
-  let(:parent) { 'Opscode' }
-  let(:child) { 'Whatever' }
+  let(:parent) { "Opscode" }
+  let(:child) { "Whatever" }
   let(:key_parent) { "SOFTWARE\\" + parent }
   let(:key_child) { "SOFTWARE\\" + parent + "\\" + child }
   # must be under HKLM\SOFTWARE for WOW64 redirection to work
@@ -98,7 +98,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     @node = Chef::Node.new
     ohai = Ohai::System.new
     ohai.all_plugins
-    @node.consume_external_attrs(ohai.data,{})
+    @node.consume_external_attrs(ohai.data, {})
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
     @new_resource = Chef::Resource::RegistryKey.new(resource_name, @run_context)
@@ -111,10 +111,10 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
   before do
     @node.name("windowsbox")
 
-    @rest_client = double("Chef::REST (mock)")
+    @rest_client = double("Chef::ServerAPI (mock)")
     allow(@rest_client).to receive(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}");
-    allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
-    allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/windowsbox/runs/#{@run_id}"});
+    allow(@rest_client).to receive(:raw_http_request).and_return({ "result" => "ok" });
+    allow(@rest_client).to receive(:post_rest).and_return({ "uri" => "https://example.com/reports/nodes/windowsbox/runs/#{@run_id}" });
 
     @resource_reporter = Chef::ResourceReporter.new(@rest_client)
     @events.register(@resource_reporter)
@@ -122,7 +122,6 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     @resource_reporter.run_started(@run_status)
     @run_id = @resource_reporter.run_id
 
-
     @new_resource.cookbook_name = "monkey"
     @cookbook_version = double("Cookbook::Version", :version => "1.2.3")
     allow(@new_resource).to receive(:cookbook_version).and_return(@cookbook_version)
@@ -138,76 +137,76 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     end
     it "creates registry key, value if the key is missing" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+      @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
       @new_resource.run_action(:create)
 
       expect(@registry.key_exists?(reg_child)).to eq(true)
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
     end
 
     it "does not create the key if it already exists with same value, type and data" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+      @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
       @new_resource.run_action(:create)
 
       expect(@registry.key_exists?(reg_child)).to eq(true)
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
     end
 
     it "creates a value if it does not exist" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}])
+      @new_resource.values([{ :name => "Mango", :type => :string, :data => "Yellow" }])
       @new_resource.run_action(:create)
 
-      expect(@registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Mango", :type => :string, :data => "Yellow" })).to eq(true)
     end
 
     it "modifies the data if the key and value exist and type matches" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"}])
+      @new_resource.values([{ :name => "Color", :type => :string, :data => "Not just Orange - OpscodeOrange!" }])
       @new_resource.run_action(:create)
 
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Not just Orange - OpscodeOrange!" })).to eq(true)
     end
 
     it "modifys the type if the key and value exist and the type does not match" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]}])
+      @new_resource.values([{ :name => "Color", :type => :multi_string, :data => ["Not just Orange - OpscodeOrange!"] }])
       @new_resource.run_action(:create)
 
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :multi_string, :data => ["Not just Orange - OpscodeOrange!"] })).to eq(true)
     end
 
     it "creates subkey if parent exists" do
       @new_resource.key(reg_child + '\OpscodeTest')
-      @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}])
+      @new_resource.values([{ :name => "Chef", :type => :multi_string, :data => ["OpscodeOrange", "Rules"] }])
       @new_resource.recursive(false)
       @new_resource.run_action(:create)
 
       expect(@registry.key_exists?(reg_child + '\OpscodeTest')).to eq(true)
-      expect(@registry.value_exists?(reg_child + '\OpscodeTest', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]})).to eq(true)
+      expect(@registry.value_exists?(reg_child + '\OpscodeTest', { :name => "Chef", :type => :multi_string, :data => ["OpscodeOrange", "Rules"] })).to eq(true)
     end
 
     it "gives error if action create and parent does not exist and recursive is set to false" do
       @new_resource.key(reg_child + '\Missing1\Missing2')
-      @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+      @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
       @new_resource.recursive(false)
-      expect{@new_resource.run_action(:create)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+      expect { @new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
     end
 
     it "creates missing keys if action create and parent does not exist and recursive is set to true" do
       @new_resource.key(reg_child + '\Missing1\Missing2')
-      @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+      @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create)
 
       expect(@registry.key_exists?(reg_child + '\Missing1\Missing2')).to eq(true)
-      expect(@registry.value_exists?(reg_child + '\Missing1\Missing2', {:name=>"OC", :type=>:string, :data=>"MissingData"})).to eq(true)
+      expect(@registry.value_exists?(reg_child + '\Missing1\Missing2', { :name => "OC", :type => :string, :data => "MissingData" })).to eq(true)
     end
 
     it "creates key with multiple value as specified" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}])
+      @new_resource.values([{ :name => "one", :type => :string, :data => "1" }, { :name => "two", :type => :string, :data => "2" }, { :name => "three", :type => :string, :data => "3" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create)
 
@@ -226,12 +225,12 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       end
       it "creates a key in a 32-bit registry that is not viewable in 64-bit" do
         @new_resource.key(reg_child + '\Atraxi' )
-        @new_resource.values([{:name=>"OC", :type=>:string, :data=>"Data"}])
+        @new_resource.values([{ :name => "OC", :type => :string, :data => "Data" }])
         @new_resource.recursive(true)
         @new_resource.architecture(:i386)
         @new_resource.run_action(:create)
         @registry.architecture = :i386
-        expect(@registry.data_exists?(reg_child + '\Atraxi', {:name=>"OC", :type=>:string, :data=>"Data"})).to eq(true)
+        expect(@registry.data_exists?(reg_child + '\Atraxi', { :name => "OC", :type => :string, :data => "Data" })).to eq(true)
         @registry.architecture = :x86_64
         expect(@registry.key_exists?(reg_child + '\Atraxi')).to eq(false)
       end
@@ -239,7 +238,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
     it "prepares the reporting data for action :create" do
       @new_resource.key(reg_child + '\Ood')
-      @new_resource.values([{:name=>"ReportingVal1", :type=>:string, :data=>"report1"},{:name=>"ReportingVal2", :type=>:string, :data=>"report2"}])
+      @new_resource.values([{ :name => "ReportingVal1", :type => :string, :data => "report1" }, { :name => "ReportingVal2", :type => :string, :data => "report2" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create)
       @report = @resource_reporter.prepare_run_data
@@ -248,8 +247,8 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       expect(@report["resources"][0]["type"]).to eq("registry_key")
       expect(@report["resources"][0]["name"]).to eq(resource_name)
       expect(@report["resources"][0]["id"]).to eq(reg_child + '\Ood')
-      expect(@report["resources"][0]["after"][:values]).to eq([{:name=>"ReportingVal1", :type=>:string, :data=>"report1"},
-                                                           {:name=>"ReportingVal2", :type=>:string, :data=>"report2"}])
+      expect(@report["resources"][0]["after"][:values]).to eq([{ :name => "ReportingVal1", :type => :string, :data => "report1" },
+                                                           { :name => "ReportingVal2", :type => :string, :data => "report2" }])
       expect(@report["resources"][0]["before"][:values]).to eq([])
       expect(@report["resources"][0]["result"]).to eq("create")
       expect(@report["status"]).to eq("success")
@@ -263,7 +262,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
       it "does not throw an exception if the keys do not exist but recursive is set to false" do
         @new_resource.key(reg_child + '\Slitheen\Raxicoricofallapatorius')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:create) # should not raise_error
         expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
@@ -271,7 +270,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       end
       it "does not create key if the action is create" do
         @new_resource.key(reg_child + '\Slitheen')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:create)
         expect(@registry.key_exists?(reg_child + '\Slitheen')).to eq(false)
@@ -286,61 +285,61 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
     it "creates registry key, value if the key is missing" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+      @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
       @new_resource.run_action(:create_if_missing)
 
       expect(@registry.key_exists?(reg_parent)).to eq(true)
       expect(@registry.key_exists?(reg_child)).to eq(true)
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
     end
 
     it "does not create the key if it already exists with same value, type and data" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
+      @new_resource.values([{ :name => "Color", :type => :string, :data => "Orange" }])
       @new_resource.run_action(:create_if_missing)
 
       expect(@registry.key_exists?(reg_child)).to eq(true)
-      expect(@registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
     end
 
     it "creates a value if it does not exist" do
       @new_resource.key(reg_child)
-      @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}])
+      @new_resource.values([{ :name => "Mango", :type => :string, :data => "Yellow" }])
       @new_resource.run_action(:create_if_missing)
 
-      expect(@registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"})).to eq(true)
+      expect(@registry.data_exists?(reg_child, { :name => "Mango", :type => :string, :data => "Yellow" })).to eq(true)
     end
 
     it "creates subkey if parent exists" do
       @new_resource.key(reg_child + '\Pyrovile')
-      @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}])
+      @new_resource.values([{ :name => "Chef", :type => :multi_string, :data => ["OpscodeOrange", "Rules"] }])
       @new_resource.recursive(false)
       @new_resource.run_action(:create_if_missing)
 
       expect(@registry.key_exists?(reg_child + '\Pyrovile')).to eq(true)
-      expect(@registry.value_exists?(reg_child + '\Pyrovile', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]})).to eq(true)
+      expect(@registry.value_exists?(reg_child + '\Pyrovile', { :name => "Chef", :type => :multi_string, :data => ["OpscodeOrange", "Rules"] })).to eq(true)
     end
 
     it "gives error if action create and parent does not exist and recursive is set to false" do
       @new_resource.key(reg_child + '\Sontaran\Sontar')
-      @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+      @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
       @new_resource.recursive(false)
-      expect{@new_resource.run_action(:create_if_missing)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+      expect { @new_resource.run_action(:create_if_missing) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
     end
 
     it "creates missing keys if action create and parent does not exist and recursive is set to true" do
       @new_resource.key(reg_child + '\Sontaran\Sontar')
-      @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}])
+      @new_resource.values([{ :name => "OC", :type => :string, :data => "MissingData" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create_if_missing)
 
       expect(@registry.key_exists?(reg_child + '\Sontaran\Sontar')).to eq(true)
-      expect(@registry.value_exists?(reg_child + '\Sontaran\Sontar', {:name=>"OC", :type=>:string, :data=>"MissingData"})).to eq(true)
+      expect(@registry.value_exists?(reg_child + '\Sontaran\Sontar', { :name => "OC", :type => :string, :data => "MissingData" })).to eq(true)
     end
 
     it "creates key with multiple value as specified" do
       @new_resource.key(reg_child + '\Adipose')
-      @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}])
+      @new_resource.values([{ :name => "one", :type => :string, :data => "1" }, { :name => "two", :type => :string, :data => "2" }, { :name => "three", :type => :string, :data => "3" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create_if_missing)
 
@@ -351,7 +350,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
     it "prepares the reporting data for :create_if_missing" do
       @new_resource.key(reg_child + '\Judoon')
-      @new_resource.values([{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}])
+      @new_resource.values([{ :name => "ReportingVal3", :type => :string, :data => "report3" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:create_if_missing)
       @report = @resource_reporter.prepare_run_data
@@ -360,7 +359,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       expect(@report["resources"][0]["type"]).to eq("registry_key")
       expect(@report["resources"][0]["name"]).to eq(resource_name)
       expect(@report["resources"][0]["id"]).to eq(reg_child + '\Judoon')
-      expect(@report["resources"][0]["after"][:values]).to eq([{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}])
+      expect(@report["resources"][0]["after"][:values]).to eq([{ :name => "ReportingVal3", :type => :string, :data => "report3" }])
       expect(@report["resources"][0]["before"][:values]).to eq([])
       expect(@report["resources"][0]["result"]).to eq("create_if_missing")
       expect(@report["status"]).to eq("success")
@@ -374,7 +373,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
       it "does not throw an exception if the keys do not exist but recursive is set to false" do
         @new_resource.key(reg_child + '\Zygons\Zygor')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:create_if_missing) # should not raise_error
         expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
@@ -382,7 +381,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       end
       it "does nothing if the action is create_if_missing" do
         @new_resource.key(reg_child + '\Zygons')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:create_if_missing)
         expect(@registry.key_exists?(reg_child + '\Zygons')).to eq(false)
@@ -399,7 +398,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     it "takes no action if the specified key path does not exist in the system" do
       expect(@registry.key_exists?(reg_parent + '\Osirian')).to eq(false)
 
-      @new_resource.key(reg_parent+ '\Osirian')
+      @new_resource.key(reg_parent + '\Osirian')
       @new_resource.recursive(false)
       @new_resource.run_action(:delete)
 
@@ -407,53 +406,53 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     end
 
     it "takes no action if the key exists but the value does not" do
-      expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
 
       @new_resource.key(reg_parent + '\Opscode')
-      @new_resource.values([{:name=>"LooksLike", :type=>:multi_string, :data=>["SeattleGrey", "OCOrange"]}])
+      @new_resource.values([{ :name => "LooksLike", :type => :multi_string, :data => ["SeattleGrey", "OCOrange"] }])
       @new_resource.recursive(false)
       @new_resource.run_action(:delete)
 
-      expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
+      expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
     end
 
     it "deletes only specified values under a key path" do
       @new_resource.key(reg_parent + '\Opscode')
-      @new_resource.values([{:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]}, {:name=>"AKA", :type=>:string, :data=>"OC"}])
+      @new_resource.values([{ :name => "Opscode", :type => :multi_string, :data => ["Seattle", "Washington"] }, { :name => "AKA", :type => :string, :data => "OC" }])
       @new_resource.recursive(false)
       @new_resource.run_action(:delete)
 
-      expect(@registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(true)
-      expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"AKA", :type=>:string, :data=>"OC"})).to eq(false)
-      expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]})).to eq(false)
+      expect(@registry.data_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(true)
+      expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "AKA", :type => :string, :data => "OC" })).to eq(false)
+      expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "Opscode", :type => :multi_string, :data => ["Seattle", "Washington"] })).to eq(false)
     end
 
     it "it deletes the values with the same name irrespective of it type and data" do
       @new_resource.key(reg_parent + '\Opscode')
-      @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Black", "Orange"]}])
+      @new_resource.values([{ :name => "Color", :type => :multi_string, :data => ["Black", "Orange"] }])
       @new_resource.recursive(false)
       @new_resource.run_action(:delete)
 
-      expect(@registry.value_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"})).to eq(false)
+      expect(@registry.value_exists?(reg_parent + '\Opscode', { :name => "Color", :type => :string, :data => "Orange" })).to eq(false)
     end
 
     it "prepares the reporting data for action :delete" do
       @new_resource.key(reg_parent + '\ReportKey')
-      @new_resource.values([{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}])
+      @new_resource.values([{ :name => "ReportVal4", :type => :string, :data => "report4" }, { :name => "ReportVal5", :type => :string, :data => "report5" }])
       @new_resource.recursive(true)
       @new_resource.run_action(:delete)
 
       @report = @resource_reporter.prepare_run_data
 
-      expect(@registry.value_exists?(reg_parent + '\ReportKey', [{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}])).to eq(false)
+      expect(@registry.value_exists?(reg_parent + '\ReportKey', [{ :name => "ReportVal4", :type => :string, :data => "report4" }, { :name => "ReportVal5", :type => :string, :data => "report5" }])).to eq(false)
 
       expect(@report["action"]).to eq("end")
       expect(@report["resources"].count).to eq(1)
       expect(@report["resources"][0]["type"]).to eq("registry_key")
       expect(@report["resources"][0]["name"]).to eq(resource_name)
       expect(@report["resources"][0]["id"]).to eq(reg_parent + '\ReportKey')
-      expect(@report["resources"][0]["before"][:values]).to eq([{:name=>"ReportVal4", :type=>:string, :data=>"report4"},
-                                                            {:name=>"ReportVal5", :type=>:string, :data=>"report5"}])
+      expect(@report["resources"][0]["before"][:values]).to eq([{ :name => "ReportVal4", :type => :string, :data => "report4" },
+                                                            { :name => "ReportVal5", :type => :string, :data => "report5" }])
       #Not testing for after values to match since after -> new_resource values.
       expect(@report["resources"][0]["result"]).to eq("delete")
       expect(@report["status"]).to eq("success")
@@ -466,7 +465,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
       end
       it "does nothing if the action is delete" do
         @new_resource.key(reg_parent + '\OpscodeWhyRun')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:delete)
 
@@ -502,7 +501,7 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
     it "raises an exception if the key has subkeys and recursive == false" do
       @new_resource.key(reg_parent)
       @new_resource.recursive(false)
-      expect{@new_resource.run_action(:delete_key)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+      expect { @new_resource.run_action(:delete_key) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
     end
 
     it "ignores the values under a key" do
@@ -544,13 +543,13 @@ describe Chef::Resource::RegistryKey, :windows_only, :broken => true do
 
       it "does not throw an exception if the key has subkeys but recursive is set to false" do
         @new_resource.key(reg_parent + '\OpscodeWhyRun')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:delete_key)
       end
       it "does nothing if the action is delete_key" do
         @new_resource.key(reg_parent + '\OpscodeWhyRun')
-        @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}])
+        @new_resource.values([{ :name => "BriskWalk", :type => :string, :data => "is good for health" }])
         @new_resource.recursive(false)
         @new_resource.run_action(:delete_key)
 
diff --git a/spec/functional/resource/remote_directory_spec.rb b/spec/functional/resource/remote_directory_spec.rb
index 37ffbbc..c25e51c 100644
--- a/spec/functional/resource/remote_directory_spec.rb
+++ b/spec/functional/resource/remote_directory_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::RemoteDirectory do
   include_context Chef::Resource::Directory
@@ -36,14 +36,14 @@ describe Chef::Resource::RemoteDirectory do
 
     resource = Chef::Resource::RemoteDirectory.new(path, run_context)
     resource.source "remotedir"
-    resource.cookbook('openldap')
+    resource.cookbook("openldap")
     resource
   end
 
   def create_extraneous_files
-    FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
-    @existing1 = File.join(path, 'marked_for_death.txt')
-    @existing2 = File.join(path, 'remotesubdir', 'marked_for_death_again.txt')
+    FileUtils.mkdir_p(File.join(path, "remotesubdir"))
+    @existing1 = File.join(path, "marked_for_death.txt")
+    @existing2 = File.join(path, "remotesubdir", "marked_for_death_again.txt")
     FileUtils.touch(@existing1)
     FileUtils.touch(@existing2)
   end
@@ -59,12 +59,12 @@ describe Chef::Resource::RemoteDirectory do
   # See spec/data/cookbooks/openldap/files/default
   let(:expected_files) do
     [
-      File.join(path, 'remote_dir_file1.txt'),
-      File.join(path, 'remote_dir_file2.txt'),
-      File.join(path, 'remotesubdir', 'remote_subdir_file1.txt'),
-      File.join(path, 'remotesubdir', 'remote_subdir_file2.txt'),
-      File.join(path, 'remotesubdir', '.a_dotfile'),
-      File.join(path, '.a_dotdir', '.a_dotfile_in_a_dotdir')
+      File.join(path, "remote_dir_file1.txt"),
+      File.join(path, "remote_dir_file2.txt"),
+      File.join(path, "remotesubdir", "remote_subdir_file1.txt"),
+      File.join(path, "remotesubdir", "remote_subdir_file2.txt"),
+      File.join(path, "remotesubdir", ".a_dotfile"),
+      File.join(path, ".a_dotdir", ".a_dotfile_in_a_dotdir"),
     ]
   end
 
@@ -133,11 +133,11 @@ describe Chef::Resource::RemoteDirectory do
       end
 
       it "leaves modifications alone" do
-        FileUtils.mkdir_p(File.join(path, 'remotesubdir'))
-        modified_file = File.join(path, 'remote_dir_file1.txt')
-        modified_subdir_file = File.join(path, 'remotesubdir', 'remote_subdir_file1.txt')
-        File.open(modified_file, 'a') {|f| f.puts "santa is real"}
-        File.open(modified_subdir_file, 'a') {|f| f.puts "so is rudolph"}
+        FileUtils.mkdir_p(File.join(path, "remotesubdir"))
+        modified_file = File.join(path, "remote_dir_file1.txt")
+        modified_subdir_file = File.join(path, "remotesubdir", "remote_subdir_file1.txt")
+        File.open(modified_file, "a") { |f| f.puts "santa is real" }
+        File.open(modified_subdir_file, "a") { |f| f.puts "so is rudolph" }
         modified_file_checksum = sha256_checksum(modified_file)
         modified_subdir_file_checksum = sha256_checksum(modified_subdir_file)
 
@@ -190,11 +190,11 @@ describe Chef::Resource::RemoteDirectory do
 
     context "and there are deeply nested extraneous files in the directory" do
       before do
-        FileUtils.mkdir_p(File.join(path, 'a', 'multiply', 'nested', 'directory'))
-        @existing1 = File.join(path, 'a', 'foo.txt')
-        @existing2 = File.join(path, 'a', 'multiply', 'bar.txt')
-        @existing3 = File.join(path, 'a', 'multiply', 'nested', 'baz.txt')
-        @existing4 = File.join(path, 'a', 'multiply', 'nested', 'directory', 'qux.txt')
+        FileUtils.mkdir_p(File.join(path, "a", "multiply", "nested", "directory"))
+        @existing1 = File.join(path, "a", "foo.txt")
+        @existing2 = File.join(path, "a", "multiply", "bar.txt")
+        @existing3 = File.join(path, "a", "multiply", "nested", "baz.txt")
+        @existing4 = File.join(path, "a", "multiply", "nested", "directory", "qux.txt")
         FileUtils.touch(@existing1)
         FileUtils.touch(@existing2)
         FileUtils.touch(@existing3)
diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb
index 4fbcd2d..b394bd0 100644
--- a/spec/functional/resource/remote_file_spec.rb
+++ b/spec/functional/resource/remote_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
 
 describe Chef::Resource::RemoteFile do
   include ChefHTTPShared
@@ -64,10 +64,10 @@ describe Chef::Resource::RemoteFile do
     end
 
     describe "when redownload isn't necessary" do
-      let(:source) { 'http://localhost:9000/seattle_capo.png' }
+      let(:source) { "http://localhost:9000/seattle_capo.png" }
 
       before do
-        @api.get("/seattle_capo.png", 304, "", { 'Etag' => 'abcdef' } )
+        @api.get("/seattle_capo.png", 304, "", { "Etag" => "abcdef" } )
       end
 
       it "does not fetch the file" do
@@ -76,7 +76,7 @@ describe Chef::Resource::RemoteFile do
     end
 
     context "when using normal encoding" do
-      let(:source) { 'http://localhost:9000/nyan_cat.png' }
+      let(:source) { "http://localhost:9000/nyan_cat.png" }
       let(:expected_content) { binread(nyan_uncompressed_filename) }
 
       it_behaves_like "a file resource"
@@ -85,7 +85,7 @@ describe Chef::Resource::RemoteFile do
     end
 
     context "when using gzip encoding" do
-      let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
+      let(:source) { "http://localhost:9000/nyan_cat.png.gz" }
       let(:expected_content) { binread(nyan_compressed_filename) }
 
       it_behaves_like "a file resource"
@@ -115,7 +115,7 @@ describe Chef::Resource::RemoteFile do
       stop_tiny_server
     end
 
-    let(:source) { 'https://localhost:9000/nyan_cat.png' }
+    let(:source) { "https://localhost:9000/nyan_cat.png" }
 
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
@@ -134,7 +134,7 @@ describe Chef::Resource::RemoteFile do
 
     context "when downloading compressed data" do
       let(:expected_content) { binread(nyan_uncompressed_filename) }
-      let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+      let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
 
       before do
         expect(File).not_to exist(path)
@@ -156,7 +156,7 @@ describe Chef::Resource::RemoteFile do
 
     context "when downloding uncompressed data" do
       let(:expected_content) { binread(nyan_uncompressed_filename) }
-      let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
+      let(:source) { "http://localhost:9000/nyan_cat_content_length.png" }
 
       before do
         expect(File).not_to exist(path)
@@ -177,7 +177,7 @@ describe Chef::Resource::RemoteFile do
     end
 
     context "when downloading truncated compressed data" do
-      let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' }
+      let(:source) { "http://localhost:9000/nyan_cat_truncated_compressed.png" }
 
       before do
         expect(File).not_to exist(path)
@@ -190,7 +190,7 @@ describe Chef::Resource::RemoteFile do
     end
 
     context "when downloding truncated uncompressed data" do
-      let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' }
+      let(:source) { "http://localhost:9000/nyan_cat_truncated.png" }
 
       before do
         expect(File).not_to exist(path)
@@ -204,7 +204,7 @@ describe Chef::Resource::RemoteFile do
 
     context "when downloding data with transfer-encoding set" do
       let(:expected_content) { binread(nyan_uncompressed_filename) }
-      let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
+      let(:source) { "http://localhost:9000/nyan_cat_transfer_encoding.png" }
 
       before do
         expect(File).not_to exist(path)
@@ -225,14 +225,14 @@ describe Chef::Resource::RemoteFile do
     end
 
     describe "when the download of the source raises an exception" do
-      let(:source) { 'http://localhost:0000/seattle_capo.png' }
+      let(:source) { "http://localhost:0000/seattle_capo.png" }
 
       before do
         expect(File).not_to exist(path)
       end
 
       it "should not create the file" do
-        expect{ resource.run_action(:create) }.to raise_error
+        expect { resource.run_action(:create) }.to raise_error
         expect(File).not_to exist(path)
       end
     end
diff --git a/spec/functional/resource/rpm_spec.rb b/spec/functional/resource/rpm_spec.rb
index b37ee78..5e68c70 100644
--- a/spec/functional/resource/rpm_spec.rb
+++ b/spec/functional/resource/rpm_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Prabhu Das (<prabhu.das at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 # run this test only for following platforms.
-exclude_test = !['aix', 'centos', 'redhat', 'suse'].include?(ohai[:platform])
+exclude_test = !["aix", "centos", "redhat", "suse"].include?(ohai[:platform])
 describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do
   include Chef::Mixin::ShellOut
 
@@ -60,13 +60,13 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
     when "aix"
       @pkg_name = "dummy"
       @pkg_version = "1-0"
-      @pkg_path = "/tmp/dummy-1-0.aix6.1.noarch.rpm"
-      FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-1-0.aix6.1.noarch.rpm') , @pkg_path)
+      @pkg_path = "#{Dir.tmpdir}/dummy-1-0.aix6.1.noarch.rpm"
+      FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "dummy-1-0.aix6.1.noarch.rpm") , @pkg_path)
     when "centos", "redhat", "suse"
       @pkg_name = "mytest"
       @pkg_version = "1.0-1"
-      @pkg_path = "/tmp/mytest-1.0-1.noarch.rpm"
-      FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-1.0-1.noarch.rpm') , @pkg_path)
+      @pkg_path = "#{Dir.tmpdir}/mytest-1.0-1.noarch.rpm"
+      FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "mytest-1.0-1.noarch.rpm") , @pkg_path)
     end
   end
 
@@ -99,14 +99,14 @@ describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test d
   context "package upgrade action" do
     before(:each) do
       shell_out("rpm -i #{@pkg_path}")
-      if ohai[:platform] == 'aix'
+      if ohai[:platform] == "aix"
         @pkg_version = "2-0"
-        @pkg_path = "/tmp/dummy-2-0.aix6.1.noarch.rpm"
-        FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'dummy-2-0.aix6.1.noarch.rpm') , @pkg_path)
+        @pkg_path = "#{Dir.tmpdir}/dummy-2-0.aix6.1.noarch.rpm"
+        FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "dummy-2-0.aix6.1.noarch.rpm") , @pkg_path)
       else
         @pkg_version = "2.0-1"
-        @pkg_path = "/tmp/mytest-2.0-1.noarch.rpm"
-        FileUtils.cp(File.join(CHEF_SPEC_ASSETS, 'mytest-2.0-1.noarch.rpm') , @pkg_path)
+        @pkg_path = "#{Dir.tmpdir}/mytest-2.0-1.noarch.rpm"
+        FileUtils.cp(File.join(CHEF_SPEC_ASSETS, "mytest-2.0-1.noarch.rpm") , @pkg_path)
       end
     end
 
diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb
index 35c5166..da8cbfc 100644
--- a/spec/functional/resource/template_spec.rb
+++ b/spec/functional/resource/template_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Template do
 
   def binread(file)
-    File.open(file,"rb") {|f| f.read }
+    File.open(file, "rb") { |f| f.read }
   end
 
   include_context Chef::Resource::File
@@ -44,8 +44,8 @@ describe Chef::Resource::Template do
     events = Chef::EventDispatch::Dispatcher.new
     run_context = Chef::RunContext.new(node, cookbook_collection, events)
     resource = Chef::Resource::Template.new(path, run_context)
-    resource.source('openldap_stuff.conf.erb')
-    resource.cookbook('openldap')
+    resource.source("openldap_stuff.conf.erb")
+    resource.cookbook("openldap")
 
     # NOTE: partials rely on `cookbook_name` getting set by chef internals and
     # ignore the user-set `cookbook` attribute.
@@ -66,14 +66,14 @@ describe Chef::Resource::Template do
 
   context "when the target file does not exist" do
     it "creates the template with the rendered content using the variable attribute when the :create action is run" do
-      resource.source('openldap_variable_stuff.conf.erb')
+      resource.source("openldap_variable_stuff.conf.erb")
       resource.variables(:secret => "nutella")
       resource.run_action(:create)
       expect(IO.read(path)).to eq("super secret is nutella")
     end
 
     it "creates the template with the rendered content using a local erb file when the :create action is run" do
-      resource.source(File.expand_path(File.join(CHEF_SPEC_DATA,'cookbooks','openldap','templates','default','openldap_stuff.conf.erb')))
+      resource.source(File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks", "openldap", "templates", "default", "openldap_stuff.conf.erb")))
       resource.cookbook(nil)
       resource.local(true)
       resource.run_action(:create)
diff --git a/spec/functional/resource/user/dscl_spec.rb b/spec/functional/resource/user/dscl_spec.rb
index 5d960da..37f6047 100644
--- a/spec/functional/resource/user/dscl_spec.rb
+++ b/spec/functional/resource/user/dscl_spec.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "chef/mixin/shell_out"
 
 metadata = {
   :mac_osx_only => true,
diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb
index 3e4e4e7..84757cc 100644
--- a/spec/functional/resource/user/useradd_spec.rb
+++ b/spec/functional/resource/user/useradd_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'functional/resource/base'
-require 'chef/mixin/shell_out'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/mixin/shell_out"
 
 def user_provider_for_platform
   case ohai[:platform]
@@ -31,26 +31,25 @@ def user_provider_for_platform
 end
 
 metadata = { :unix_only => true,
-  :requires_root => true,
-  :not_supported_on_mac_osx => true,
-  :provider => {:user => user_provider_for_platform}
+             :requires_root => true,
+             :not_supported_on_mac_osx => true,
+             :provider => { :user => user_provider_for_platform },
 }
 
 describe Chef::Provider::User::Useradd, metadata do
 
   include Chef::Mixin::ShellOut
 
-
   # Utility code for /etc/passwd interaction, avoid any caching of user records:
   PwEntry = Struct.new(:name, :passwd, :uid, :gid, :gecos, :home, :shell)
 
   class UserNotFound < StandardError; end
 
   def pw_entry
-    passwd_file = File.open("/etc/passwd", "rb") {|f| f.read}
+    passwd_file = File.open("/etc/passwd", "rb") { |f| f.read }
     matcher = /^#{Regexp.escape(username)}.+$/
     if passwd_entry = passwd_file.scan(matcher).first
-      PwEntry.new(*passwd_entry.split(':'))
+      PwEntry.new(*passwd_entry.split(":"))
     else
       raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd"
     end
@@ -59,14 +58,18 @@ describe Chef::Provider::User::Useradd, metadata do
   def etc_shadow
     case ohai[:platform]
     when "aix"
-      File.open("/etc/security/passwd") {|f| f.read }
+      File.open("/etc/security/passwd") { |f| f.read }
     else
-      File.open("/etc/shadow") {|f| f.read }
+      File.open("/etc/shadow") { |f| f.read }
     end
   end
 
-  def supports_quote_in_username?
-    OHAI_SYSTEM["platform_family"] == "debian"
+  def self.quote_in_username_unsupported?
+    if OHAI_SYSTEM["platform_family"] == "debian"
+      false
+    else
+      "Only debian family systems support quotes in username"
+    end
   end
 
   def password_should_be_set
@@ -78,13 +81,13 @@ describe Chef::Provider::User::Useradd, metadata do
   end
 
   def try_cleanup
-    ['/home/cheftestfoo', '/home/cheftestbar'].each do |f|
+    ["/home/cheftestfoo", "/home/cheftestbar"].each do |f|
       FileUtils.rm_rf(f) if File.exists? f
     end
 
-    ['cf-test'].each do |u|
+    ["cf-test"].each do |u|
       r = Chef::Resource::User.new("DELETE USER", run_context)
-      r.username('cf-test')
+      r.username("cf-test")
       r.run_action(:remove)
     end
   end
@@ -100,7 +103,7 @@ describe Chef::Provider::User::Useradd, metadata do
     while max_retries > 0
       begin
         pw_entry # will raise if the user doesn't exist
-        status = shell_out!("userdel", "-r", username, :returns => [0,8,12])
+        status = shell_out!("userdel", "-r", username, :returns => [0, 8, 12])
 
         # Error code 8 during userdel indicates that the user is logged in.
         # This occurs randomly because the accounts daemon holds a lock due to which userdel fails.
@@ -108,7 +111,7 @@ describe Chef::Provider::User::Useradd, metadata do
         break if status.exitstatus != 8
 
         sleep 1
-        max_retries = max_retries -1
+        max_retries = max_retries - 1
       rescue UserNotFound
         break
       end
@@ -156,26 +159,20 @@ describe Chef::Provider::User::Useradd, metadata do
 
   let(:expected_shadow) do
     if ohai[:platform] == "aix"
-      expected_shadow = "cf-test"  # For aix just check user entry in shadow file
+      expected_shadow = "cf-test" # For aix just check user entry in shadow file
     else
       expected_shadow = "cf-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/"
     end
   end
 
-  let(:skip) { false }
-
   describe "action :create" do
 
     context "when the user does not exist beforehand" do
       before do
-        if reason = skip
-          pending(reason)
-        end
         user_resource.run_action(:create)
         expect(user_resource).to be_updated_by_last_action
       end
 
-
       it "ensures the user exists" do
         expect(pw_entry.name).to eq(username)
       end
@@ -186,14 +183,7 @@ describe Chef::Provider::User::Useradd, metadata do
       #  tabulation: '\t', etc.). Note that using a slash ('/') may break the
       #  default algorithm for the definition of the user's home directory.
 
-      context "and the username contains a single quote" do
-        let(:skip) do
-          if supports_quote_in_username?
-            false
-          else
-            "Platform #{OHAI_SYSTEM["platform"]} not expected to support username w/ quote"
-          end
-        end
+      context "and the username contains a single quote", skip: quote_in_username_unsupported? do
 
         let(:username) { "t'bilisi" }
 
@@ -202,7 +192,6 @@ describe Chef::Provider::User::Useradd, metadata do
         end
       end
 
-
       context "when uid is set" do
         # Should verify uid not in use...
         let(:uid) { 1999 }
@@ -250,17 +239,17 @@ describe Chef::Provider::User::Useradd, metadata do
         let(:home) { "/home/#{username}" }
 
         it "ensures the user's home is set to the given path" do
-          expect(pw_entry.home).to eq("/home/#{username}")
+          expect(pw_entry.home).to eq(home)
         end
 
-        if %w{rhel fedora}.include?(OHAI_SYSTEM["platform_family"])
+        if %w{rhel fedora wrlinux}.include?(OHAI_SYSTEM["platform_family"])
           # Inconsistent behavior. See: CHEF-2205
           it "creates the home dir when not explicitly asked to on RHEL (XXX)" do
-            expect(File).to exist("/home/#{username}")
+            expect(File).to exist(home)
           end
         else
           it "does not create the home dir without `manage_home'" do
-            expect(File).not_to exist("/home/#{username}")
+            expect(File).not_to exist(home)
           end
         end
 
@@ -268,7 +257,7 @@ describe Chef::Provider::User::Useradd, metadata do
           let(:manage_home) { true }
 
           it "ensures the user's home directory exists" do
-            expect(File).to exist("/home/#{username}")
+            expect(File).to exist(home)
           end
         end
       end
@@ -295,16 +284,16 @@ describe Chef::Provider::User::Useradd, metadata do
         let(:uid_min) do
           case ohai[:platform]
           when "aix"
-            # UIDs and GIDs below 100 are typically reserved for system accounts and services
-            # http://www.ibm.com/developerworks/aix/library/au-satuidgid/
-            100
+            # UIDs and GIDs below 200 are typically reserved for system accounts and services
+            # https://abcofaix.wordpress.com/tag/usermod/
+            200
           else
             # from `man useradd`, login user means uid will be between
             # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my
             # Ubuntu 13.04 system, these are commented out, so we'll look at
             # UID_MIN to find the lower limit of the non-system-user range, and
             # use that value in our assertions.
-            login_defs = File.open("/etc/login.defs", "rb") {|f| f.read }
+            login_defs = File.open("/etc/login.defs", "rb") { |f| f.read }
             uid_min_scan = /^UID_MIN\s+(\d+)/
             login_defs.match(uid_min_scan)[1]
           end
@@ -342,7 +331,7 @@ describe Chef::Provider::User::Useradd, metadata do
 
       before do
         if reason = skip
-          pending(reason)
+          skip(reason)
         end
         existing_user.run_action(:create)
         expect(existing_user).to be_updated_by_last_action
@@ -463,7 +452,6 @@ describe Chef::Provider::User::Useradd, metadata do
           end
         end
 
-
         it "ensures the password is set" do
           password_should_be_set
           expect(etc_shadow).to include(expected_shadow)
@@ -492,7 +480,6 @@ describe Chef::Provider::User::Useradd, metadata do
           end
         end
 
-
         it "ensures the password is set to the desired value" do
           password_should_be_set
           expect(etc_shadow).to include(expected_shadow)
@@ -526,16 +513,16 @@ describe Chef::Provider::User::Useradd, metadata do
     let(:user_locked_context?) { false }
 
     def shadow_entry
-      etc_shadow.lines.select {|l| l.include?(username) }.first
+      etc_shadow.lines.select { |l| l.include?(username) }.first
     end
 
     def shadow_password
-      shadow_entry.split(':')[1]
+      shadow_entry.split(":")[1]
     end
 
     def aix_user_lock_status
       lock_info = shell_out!("lsuser -a account_locked #{username}")
-      status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)[1]
+      /\S+\s+account_locked=(\S+)/.match(lock_info.stdout)[1]
     end
 
     def user_account_should_be_locked
@@ -604,7 +591,6 @@ describe Chef::Provider::User::Useradd, metadata do
           end
         end
 
-
         it "locks the user's password" do
           user_account_should_be_locked
         end
@@ -652,7 +638,7 @@ describe Chef::Provider::User::Useradd, metadata do
       context "and has no password" do
 
         # TODO: platform_family should be setup in spec_helper w/ tags
-        if %w[suse opensuse].include?(OHAI_SYSTEM["platform_family"])
+        if %w{suse opensuse}.include?(OHAI_SYSTEM["platform_family"])
           # suse gets this right:
           it "errors out trying to unlock the user" do
             expect(@error).to be_a(Mixlib::ShellOut::ShellCommandFailed)
@@ -673,10 +659,10 @@ describe Chef::Provider::User::Useradd, metadata do
             # DEBUG: Ran usermod -U chef-functional-test returned 0
             expect(@error).to be_nil
             if ohai[:platform] == "aix"
-              expect(pw_entry.passwd).to eq('*')
+              expect(pw_entry.passwd).to eq("*")
               user_account_should_be_unlocked
             else
-              expect(pw_entry.passwd).to eq('x')
+              expect(pw_entry.passwd).to eq("x")
               expect(shadow_password).to include("!")
             end
           end
diff --git a/spec/functional/resource/user/windows_spec.rb b/spec/functional/resource/user/windows_spec.rb
new file mode 100644
index 0000000..f61a51c
--- /dev/null
+++ b/spec/functional/resource/user/windows_spec.rb
@@ -0,0 +1,133 @@
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/shell_out"
+
+describe Chef::Provider::User::Windows, :windows_only do
+  include Chef::Mixin::ShellOut
+
+  let(:username) { "ChefFunctionalTest" }
+  let(:password) { SecureRandom.uuid }
+
+  let(:node) do
+    n = Chef::Node.new
+    n.consume_external_attrs(OHAI_SYSTEM.data.dup, {})
+    n
+  end
+
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:new_resource) do
+    Chef::Resource::User.new(username, run_context).tap do |r|
+      r.provider(Chef::Provider::User::Windows)
+      r.password(password)
+    end
+  end
+
+  def delete_user(u)
+    shell_out("net user #{u} /delete")
+  end
+
+  before do
+    delete_user(username)
+  end
+
+  describe "action :create" do
+    it "creates a user when a username and password are given" do
+      new_resource.run_action(:create)
+      expect(new_resource).to be_updated_by_last_action
+      expect(shell_out("net user #{username}").exitstatus).to eq(0)
+    end
+
+    it "reports no changes if there are no changes needed" do
+      new_resource.run_action(:create)
+      new_resource.run_action(:create)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "allows chaning the password" do
+      new_resource.run_action(:create)
+      new_resource.password(SecureRandom.uuid)
+      new_resource.run_action(:create)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    context "with a gid specified" do
+      it "warns unsupported" do
+        expect(Chef::Log).to receive(:warn).with(/not implemented/)
+        new_resource.gid("agroup")
+        new_resource.run_action(:create)
+      end
+    end
+  end
+
+  describe "action :remove" do
+    before do
+      new_resource.run_action(:create)
+    end
+
+    it "deletes the user" do
+      new_resource.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
+      expect(shell_out("net user #{username}").exitstatus).to eq(2)
+    end
+
+    it "is idempotent" do
+      new_resource.run_action(:remove)
+      new_resource.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+  end
+
+  describe "action :lock" do
+    before do
+      new_resource.run_action(:create)
+    end
+
+    it "locks the user account" do
+      new_resource.run_action(:lock)
+      expect(new_resource).to be_updated_by_last_action
+      expect(shell_out("net user #{username}").stdout).to match(/Account active\s*No/)
+    end
+
+    it "is idempotent" do
+      new_resource.run_action(:lock)
+      new_resource.run_action(:lock)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+  end
+
+  describe "action :unlock" do
+    before do
+      new_resource.run_action(:create)
+      new_resource.run_action(:lock)
+    end
+
+    it "unlocks the user account" do
+      new_resource.run_action(:unlock)
+      expect(new_resource).to be_updated_by_last_action
+      expect(shell_out("net user #{username}").stdout).to match(/Account active\s*Yes/)
+    end
+
+    it "is idempotent" do
+      new_resource.run_action(:unlock)
+      new_resource.run_action(:unlock)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+  end
+end
diff --git a/spec/functional/resource/windows_package_spec.rb b/spec/functional/resource/windows_package_spec.rb
new file mode 100644
index 0000000..bc508dc
--- /dev/null
+++ b/spec/functional/resource/windows_package_spec.rb
@@ -0,0 +1,168 @@
+#
+# Author:: Matt Wrock (<matt at mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "functional/resource/base"
+
+describe Chef::Resource::WindowsPackage, :windows_only, :volatile do
+  let(:pkg_name) { nil }
+  let(:pkg_path) { nil }
+  let(:pkg_checksum) { nil }
+  let(:pkg_version) { nil }
+  let(:pkg_type) { nil }
+  let(:pkg_options) { nil }
+
+  subject do
+    new_resource = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+    new_resource.source pkg_path if pkg_path
+    new_resource.version pkg_version
+    new_resource.installer_type pkg_type
+    new_resource.options pkg_options
+    new_resource.checksum pkg_checksum
+    new_resource
+  end
+
+  describe "install package" do
+    let(:pkg_name) { "Microsoft Visual C++ 2005 Redistributable" }
+    let(:pkg_checksum) { "d6832398e3bc9156a660745f427dc1c2392ce4e9a872e04f41f62d0c6bae07a8" }
+    let(:pkg_path) { "https://download.microsoft.com/download/6/B/B/6BB661D6-A8AE-4819-B79F-236472F6070C/vcredist_x86.exe" }
+    let(:pkg_checksum) { nil }
+    let(:pkg_type) { :custom }
+    let(:pkg_options) { "/Q" }
+
+    it "updates resource on first install" do
+      subject.run_action(:install)
+      expect(subject).to be_updated_by_last_action
+    end
+
+    it "does not update resource when already installed" do
+      subject.run_action(:install)
+      expect(subject).not_to be_updated_by_last_action
+    end
+
+    context "installing additional version" do
+      let(:pkg_path) { "https://download.microsoft.com/download/e/1/c/e1c773de-73ba-494a-a5ba-f24906ecf088/vcredist_x86.exe" }
+      let(:pkg_checksum) { "eb00f891919d4f894ab725b158459db8834470c382dc60cd3c3ee2c6de6da92c" }
+      let(:pkg_version) { "8.0.56336" }
+
+      it "installs older version" do
+        subject.run_action(:install)
+        expect(subject).to be_updated_by_last_action
+      end
+    end
+
+    describe "removing package" do
+      subject { Chef::Resource::WindowsPackage.new(pkg_name, run_context) }
+
+      context "multiple versions and a version given to remove" do
+        before { subject.version("8.0.56336") }
+
+        it "removes specified version" do
+          subject.run_action(:remove)
+          expect(subject).to be_updated_by_last_action
+          prov = subject.provider_for_action(:remove)
+          prov.load_current_resource
+          expect(prov.current_version_array).to eq([["8.0.59193"]])
+        end
+      end
+
+      context "single version installed and no version given to remove" do
+        it "removes last remaining version" do
+          subject.run_action(:remove)
+          expect(subject).to be_updated_by_last_action
+          prov = subject.provider_for_action(:remove)
+          prov.load_current_resource
+          expect(prov.current_version_array).to eq([nil])
+        end
+      end
+
+      describe "removing multiple versions at once" do
+        let(:pkg_version) { nil }
+        before do
+          install1 = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+          install1.source pkg_path
+          install1.version pkg_version
+          install1.installer_type pkg_type
+          install1.options pkg_options
+          install1.run_action(:install)
+
+          install2 = Chef::Resource::WindowsPackage.new(pkg_name, run_context)
+          install2.source "https://download.microsoft.com/download/e/1/c/e1c773de-73ba-494a-a5ba-f24906ecf088/vcredist_x86.exe"
+          install2.version "8.0.56336"
+          install2.installer_type pkg_type
+          install2.options pkg_options
+          install2.run_action(:install)
+        end
+
+        it "removes all versions" do
+          subject.run_action(:remove)
+          expect(subject).to be_updated_by_last_action
+          prov = subject.provider_for_action(:remove)
+          prov.load_current_resource
+          expect(prov.current_version_array).to eq([nil])
+        end
+      end
+    end
+  end
+
+  describe "package version and installer type" do
+    after { subject.run_action(:remove) }
+
+    context "null soft" do
+      let(:pkg_name) { "Ultra Defragmenter" }
+      let(:pkg_path) { "http://iweb.dl.sourceforge.net/project/ultradefrag/stable-release/6.1.1/ultradefrag-6.1.1.bin.amd64.exe" }
+      let(:pkg_checksum) { "11d53ed4c426c8c867ad43f142b7904226ffd9938c02e37086913620d79e3c09" }
+
+      it "finds the correct installer type" do
+        subject.run_action(:install)
+        expect(subject.provider_for_action(:install).installer_type).to eq(:nsis)
+      end
+    end
+
+    context "inno" do
+      let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+      let(:pkg_path) { "http://mercurial.selenic.com/release/windows/Mercurial-3.6.1-x64.exe" }
+      let(:pkg_checksum) { "febd29578cb6736163d232708b834a2ddd119aa40abc536b2c313fc5e1b5831d" }
+
+      it "finds the correct installer type" do
+        subject.run_action(:install)
+        expect(subject.provider_for_action(:install).installer_type).to eq(:inno)
+      end
+    end
+  end
+
+  describe "install from local file" do
+    let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+    let(:pkg_path) { ::File.join(Chef::Config[:file_cache_path], "package", "Mercurial-3.6.1-x64.exe") }
+    let(:pkg_checksum) { "febd29578cb6736163d232708b834a2ddd119aa40abc536b2c313fc5e1b5831d" }
+
+    it "installs the app" do
+      subject.run_action(:install)
+      expect(subject).to be_updated_by_last_action
+    end
+  end
+
+  describe "uninstall exe without source" do
+    let(:pkg_name) { "Mercurial 3.6.1 (64-bit)" }
+
+    it "uninstalls the app" do
+      subject.run_action(:remove)
+      expect(subject).to be_updated_by_last_action
+    end
+  end
+end
diff --git a/spec/functional/resource/windows_service_spec.rb b/spec/functional/resource/windows_service_spec.rb
index 29d1fc4..80faaec 100644
--- a/spec/functional/resource/windows_service_spec.rb
+++ b/spec/functional/resource/windows_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Chris Doherty (<cdoherty at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only do
+describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_gem_only, :appveyor_only, :broken => true do
+  # Marking as broken. This test is causing appveyor tests to exit with 116.
 
   include_context "using Win32::Service"
 
-  let(:username) { "service_spec_user"}
-  let(:qualified_username) { ".\\#{username}"}
-  let(:password) { "1a2b3c4X!&narf"}
+  let(:username) { "service_spec_user" }
+  let(:qualified_username) { "#{ENV['COMPUTERNAME']}\\#{username}" }
+  let(:password) { "1a2b3c4X!&narf" }
 
   let(:user_resource) {
     r = Chef::Resource::User.new(username, run_context)
@@ -49,7 +50,7 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
       service_display_name: "windows_service spec #{id}}",
       service_description: "Test service for running the windows_service functional spec.",
       service_file_path: global_service_file_path,
-      } )
+      }, )
   }
 
   let(:manager) {
@@ -93,6 +94,9 @@ describe Chef::Resource::WindowsService, :windows_only, :system_windows_service_
       service_resource.run_action(:start)
     end
 
-    it "raises an exception when it can't grant the logon privilege"
+    it "grants the user the log on as service right" do
+      service_resource.run_action(:start)
+      expect(Chef::ReservedNames::Win32::Security.get_account_right(qualified_username)).to include("SeServiceLogonRight")
+    end
   end
 end
diff --git a/spec/functional/rest_spec.rb b/spec/functional/rest_spec.rb
index 7c6b187..adafc18 100644
--- a/spec/functional/rest_spec.rb
+++ b/spec/functional/rest_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
-require 'support/shared/functional/http'
+require "spec_helper"
+require "tiny_server"
+require "support/shared/functional/http"
 
 describe Chef::REST do
   include ChefHTTPShared
@@ -80,6 +80,7 @@ describe Chef::REST do
   before do
     Chef::Config[:node_name]  = "webmonkey.example.com"
     Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
+    Chef::Config[:treat_deprecation_warnings_as_errors] = false
   end
 
   before(:all) do
diff --git a/spec/functional/run_lock_spec.rb b/spec/functional/run_lock_spec.rb
index 0cb8635..d380b19 100644
--- a/spec/functional/run_lock_spec.rb
+++ b/spec/functional/run_lock_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/client'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/client"
 
 describe Chef::RunLock do
 
@@ -28,217 +28,239 @@ describe Chef::RunLock do
 
     let(:random_temp_root) do
       Kernel.srand(Time.now.to_i + Process.pid)
-      "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}"
+      "#{Dir.tmpdir}/#{Kernel.rand(Time.now.to_i + Process.pid)}"
     end
 
-    let(:lockfile){ "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
+    let(:lockfile) { "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" }
 
     # make sure to start with a clean slate.
-    before(:each){ FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
-    after(:each){ FileUtils.rm_r(random_temp_root) }
+    before(:each) { log_event("rm -rf before"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
+    after(:each) { log_event("rm -rf after"); FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) }
 
-    def wait_on_lock
-      tries = 0
-      until File.exist?(lockfile)
-        raise "Lockfile never created, abandoning test" if tries > 10
-        tries += 1
-        sleep 0.1
-      end
+    def log_event(message, time = Time.now.strftime("%H:%M:%S.%L"))
+      events << [ message, time ]
     end
 
-    ##
-    # Side channel via a pipe allows child processes to send errors to the parent
-
-    # Don't lazy create the pipe or else we might not share it with subprocesses
-    let!(:error_pipe) do
-      r,w = IO.pipe
-      w.sync = true
-      [r,w]
+    def events
+      @events ||= []
     end
 
-    let(:error_read) { error_pipe[0] }
-    let(:error_write) { error_pipe[1] }
-
-    after do
-      error_read.close unless error_read.closed?
-      error_write.close unless error_write.closed?
+    WAIT_ON_LOCK_TIME = 1.0
+    def wait_on_lock
+      Timeout::timeout(WAIT_ON_LOCK_TIME) do
+        until File.exist?(lockfile)
+          sleep 0.1
+        end
+      end
+    rescue Timeout::Error
+      raise "Lockfile never created, abandoning test"
     end
 
-    # Send a RuntimeError from the child process to the parent process. Also
-    # prints error to $stdout, just in case something goes wrong with the error
-    # marshaling stuff.
-    def send_side_channel_error(message)
-      $stderr.puts(message)
-      $stderr.puts(caller)
-      e = RuntimeError.new(message)
-      error_write.print(Marshal.dump(e))
-    end
+    CLIENT_PROCESS_TIMEOUT = 10
+    BREATHING_ROOM = 1
 
-    # Read the error (if any) from the error channel. If a marhaled error is
-    # present, it is unmarshaled and raised (which will fail the test)
-    def raise_side_channel_error!
-      error_write.close
-      err = error_read.read
-      error_read.close
+    # ClientProcess is defined below
+    let!(:p1) { ClientProcess.new(self, "p1") }
+    let!(:p2) { ClientProcess.new(self, "p2") }
+    after(:each) do |example|
       begin
-        # ArgumentError from Marshal.load indicates no data, which we assume
-        # means no error in child process.
-        raise Marshal.load(err)
-      rescue ArgumentError
-        nil
+        p1.stop
+        p2.stop
+      rescue
+        example.exception = $!
+        raise
+      ensure
+        if example.exception
+          print_events
+        end
       end
     end
 
-    ##
-    # Interprocess synchronization via a pipe. This allows us to control the
-    # state of the processes competing over the lock without relying on sleep.
-
-    let!(:sync_pipe) do
-      r,w = IO.pipe
-      w.sync = true
-      [r,w]
-    end
-    let(:sync_read) { sync_pipe[0] }
-    let(:sync_write) { sync_pipe[1] }
-
-    after do
-      sync_read.close unless sync_read.closed?
-      sync_write.close unless sync_write.closed?
-    end
-
-    # Wait on synchronization signal. If not received within the timeout, an
-    # error is sent via the error channel, and the process exits.
-    def sync_wait
-      if IO.select([sync_read], nil, nil, 20).nil?
-        # timeout reading from the sync pipe.
-        send_side_channel_error("Error syncing processes in run lock test (timeout)")
-        exit!(1)
-      else
-        sync_read.getc
+    def print_events
+      # Consume any remaining events that went on the channel and print them all
+      p1.last_event
+      p2.last_event
+      events.each_with_index.sort_by { |(message, time), index| [ time, index ] }.each do |(message, time), index|
+        print "#{time} #{message}\n"
       end
     end
 
-    # Sends a character in the sync pipe, which wakes ("unlocks") another
-    # process that is waiting on the sync signal
-    def sync_send
-      sync_write.putc("!")
-      sync_write.flush
-    end
-
-    ##
-    # IPC to record test results in a pipe. Tests can read pipe contents to
-    # check that operations occur in the expected order.
-
-    let!(:results_pipe) do
-      r,w = IO.pipe
-      w.sync = true
-      [r,w]
-    end
-    let(:results_read) { results_pipe[0] }
-    let(:results_write) { results_pipe[1] }
-
-    after do
-      results_read.close unless results_read.closed?
-      results_write.close unless results_write.closed?
-    end
-
-    # writes the message to the results pipe for later checking.
-    # note that nothing accounts for the pipe filling and waiting forever on a
-    # read or write call, so don't put too much data in.
-    def record(message)
-      results_write.puts(message)
-      results_write.flush
-    end
-
-    def results
-      results_write.flush
-      results_write.close
-      message = results_read.read
-      results_read.close
-      message
-    end
-
-    ##
-    # Run lock is the system under test
-    let!(:run_lock) { Chef::RunLock.new(lockfile) }
-
-    it "creates the full path to the lockfile" do
-      expect { run_lock.acquire }.not_to raise_error
-      expect(File).to exist(lockfile)
-    end
-
-    it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
-      run_lock.acquire
-      expect(run_lock.runlock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
-    end
-
-    it "allows only one chef client run per lockfile" do
-      # First process, gets the lock and keeps it.
-      p1 = fork do
-        run_lock.acquire
-        record "p1 has lock"
-        # Wait until the other process is trying to get the lock:
-        sync_wait
-        # sleep a little bit to make process p2 wait on the lock
-        sleep 2
-        record "p1 releasing lock"
-        run_lock.release
-        exit!(0)
+    context "when the lockfile does not already exist" do
+      context "when a client creates the lockfile but has not yet acquired the lock" do
+        before { p1.run_to("created lock") }
+        shared_context "second client gets the lock" do
+          it "the lockfile is created" do
+            log_event("lockfile exists? #{File.exist?(lockfile)}")
+            expect(File.exist?(lockfile)).to be_truthy
+          end
+
+          it "the lockfile is not locked" do
+            run_lock = Chef::RunLock.new(lockfile)
+            begin
+              expect(run_lock.test).to be_truthy
+            ensure
+              run_lock.release
+            end
+          end
+
+          it "the lockfile is empty" do
+            expect(IO.read(lockfile)).to eq("")
+          end
+
+          context "and a second client gets the lock" do
+            before { p2.run_to("acquired lock") }
+            it "the first client does not get the lock until the second finishes" do
+              p1.run_to("acquired lock") do
+                p2.run_to_completion
+              end
+            end
+            it "and the first client tries to get the lock and the second is killed, the first client gets the lock immediately" do
+              p1.run_to("acquired lock") do
+                sleep BREATHING_ROOM
+                expect(p1.last_event).to match(/after (started|created lock)/)
+                p2.stop
+              end
+              p1.run_to_completion
+            end
+          end
+        end
+
+        context "and the second client has done nothing" do
+          include_context "second client gets the lock"
+        end
+
+        context "and the second client has created the lockfile but not yet acquired the lock" do
+          before { p2.run_to("created lock") }
+          include_context "second client gets the lock"
+        end
       end
 
-      # Wait until p1 creates the lockfile
-      wait_on_lock
-
-      p2 = fork do
-        # inform process p1 that we're trying to get the lock
-        sync_send
-        run_lock.acquire
-        record "p2 has lock"
-        run_lock.release
-        exit!(0)
+      context "when a client acquires the lock but has not yet saved the pid" do
+        before { p1.run_to("acquired lock") }
+
+        it "the lockfile is created" do
+          log_event("lockfile exists? #{File.exist?(lockfile)}")
+          expect(File.exist?(lockfile)).to be_truthy
+        end
+
+        it "the lockfile is locked" do
+          run_lock = Chef::RunLock.new(lockfile)
+          begin
+            expect(run_lock.test).to be_falsey
+          ensure
+            run_lock.release
+          end
+        end
+
+        it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
+          run_lock = File.open(lockfile)
+          expect(run_lock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
+        end
+
+        it "the lockfile is empty" do
+          expect(IO.read(lockfile)).to eq("")
+        end
+
+        it "and a second client tries to acquire the lock, it doesn't get the lock until *after* the first client exits" do
+          # Start p2 and tell it to move forward in the background
+          p2.run_to("acquired lock") do
+            # While p2 is trying to acquire, wait a bit and then let p1 complete
+            sleep(BREATHING_ROOM)
+            expect(p2.last_event).to match(/after (started|created lock)/)
+            p1.run_to_completion
+          end
+
+          p2.run_to_completion
+        end
+
+        it "and a second client tries to get the lock and the first is killed, the second client gets the lock immediately" do
+          p2.run_to("acquired lock") do
+            sleep BREATHING_ROOM
+            expect(p2.last_event).to match(/after (started|created lock)/)
+            p1.stop
+          end
+          p2.run_to_completion
+        end
       end
 
-      Process.waitpid2(p1)
-      Process.waitpid2(p2)
-
-      raise_side_channel_error!
-
-      expected=<<-E
-p1 has lock
-p1 releasing lock
-p2 has lock
-E
-      expect(results).to eq(expected)
-    end
-
-    it "clears the lock if the process dies unexpectedly" do
-      p1 = fork do
-        run_lock.acquire
-        record "p1 has lock"
-        sleep 60
-        record "p1 still has lock"
-        exit! 1
+      context "when a client acquires the lock and saves the pid" do
+        before { p1.run_to("saved pid") }
+
+        it "the lockfile is created" do
+          expect(File.exist?(lockfile)).to be_truthy
+        end
+
+        it "the lockfile is locked" do
+          run_lock = Chef::RunLock.new(lockfile)
+          begin
+            expect(run_lock.test).to be_falsey
+          ensure
+            run_lock.release
+          end
+        end
+
+        it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do
+          run_lock = File.open(lockfile)
+          expect(run_lock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).to eq(Fcntl::FD_CLOEXEC)
+        end
+
+        it "the PID is in the lockfile" do
+          expect(IO.read(lockfile)).to eq p1.pid.to_s
+        end
+
+        it "and a second client tries to acquire the lock, it doesn't get the lock until *after* the first client exits" do
+          # Start p2 and tell it to move forward in the background
+          p2.run_to("acquired lock") do
+            # While p2 is trying to acquire, wait a bit and then let p1 complete
+            sleep(BREATHING_ROOM)
+            expect(p2.last_event).to match(/after (started|created lock)/)
+            p1.run_to_completion
+          end
+
+          p2.run_to_completion
+        end
+
+        it "when a second client tries to get the lock and the first is killed, the second client gets the lock immediately" do
+          p2.run_to("acquired lock") do
+            sleep BREATHING_ROOM
+            expect(p2.last_event).to match(/after (started|created lock)/)
+            p1.stop
+          end
+          p2.run_to_completion
+        end
       end
 
-      wait_on_lock
-      Process.kill(:KILL, p1)
-      Process.waitpid2(p1)
-
-      p2 = fork do
-        run_lock.acquire
-        record "p2 has lock"
-        run_lock.release
-        exit! 0
+      context "when a client acquires a lock and exits normally" do
+        before { p1.run_to_completion }
+
+        it "the lockfile remains" do
+          expect(File.exist?(lockfile)).to be_truthy
+        end
+
+        it "the lockfile is not locked" do
+          run_lock = Chef::RunLock.new(lockfile)
+          begin
+            expect(run_lock.test).to be_truthy
+          ensure
+            run_lock.release
+          end
+        end
+
+        it "the PID is in the lockfile" do
+          expect(IO.read(lockfile)).to eq p1.pid.to_s
+        end
+
+        it "and a second client tries to acquire the lock, it gets the lock immediately" do
+          p2.run_to_completion
+        end
       end
-
-      Process.waitpid2(p2)
-
-      expect(results).to match(/p2 has lock\Z/)
     end
 
     it "test returns true and acquires the lock" do
+      run_lock = Chef::RunLock.new(lockfile)
       p1 = fork do
         expect(run_lock.test).to eq(true)
+        run_lock.save_pid
         sleep 2
         exit! 1
       end
@@ -255,8 +277,10 @@ E
     end
 
     it "test returns without waiting when the lock is acquired" do
+      run_lock = Chef::RunLock.new(lockfile)
       p1 = fork do
         run_lock.acquire
+        run_lock.save_pid
         sleep 2
         exit! 1
       end
@@ -267,20 +291,176 @@ E
       Process.waitpid2(p1)
     end
 
-    it "doesn't truncate the lock file so that contents can be read" do
-      p1 = fork do
-        run_lock.acquire
-        run_lock.save_pid
-        sleep 2
-        exit! 1
+  end
+
+  #
+  # Runs a process in the background that will:
+  #
+  # 1. start up (`started` event)
+  # 2. acquire the runlock file (`acquired lock` event)
+  # 3. save the pid to the lockfile (`saved pid` event)
+  # 4. exit
+  #
+  # You control exactly how far the client process goes with the `run_to`
+  # method: it will stop at any given spot so you can test for race conditions.
+  #
+  # It uses a pair of pipes to communicate with the process. The tests will
+  # send an event name over to the process, which gives the process permission
+  # to run until it reaches that event (at which point it waits for another event
+  # name). The process sends the name of each event it reaches back to the tests.
+  #
+  class ClientProcess
+    def initialize(example, name)
+      @example = example
+      @name = name
+      @read_from_process, @write_to_tests = IO.pipe
+      @read_from_tests, @write_to_process = IO.pipe
+    end
+
+    attr_reader :example
+    attr_reader :name
+    attr_reader :pid
+
+    def last_event
+      loop do
+        line = readline_nonblock(read_from_process)
+        break if line.nil?
+        event, time = line.split("@")
+        example.log_event("#{name}.last_event got #{event}")
+        example.log_event("[#{name}] #{event}", time.strip)
+        @last_event = event
       end
+      @last_event
+    end
 
-      wait_on_lock
-      sleep 0.5 # Possible race condition on Solaris which pid is observed as 0
-      expect(File.read(lockfile)).to eq(p1.to_s)
+    def run_to(to_event, &background_block)
+      example.log_event("#{name}.run_to(#{to_event.inspect})")
 
-      Process.waitpid2(p1)
+      # Start the process if it's not started
+      start if !pid
+
+      # Tell the process what to stop at (also means it can go)
+      write_to_process.print "#{to_event}\n"
+
+      # Run the background block
+      background_block.call if background_block
+
+      # Wait until it gets there
+      Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+        until @last_event == "after #{to_event}"
+          got_event, time = read_from_process.gets.split("@")
+          example.log_event("#{name}.last_event got #{got_event}")
+          example.log_event("[#{name}] #{got_event}", time.strip)
+          @last_event = got_event
+        end
+      end
+
+      example.log_event("#{name}.run_to(#{to_event.inspect}) finished")
     end
 
+    def run_to_completion
+      example.log_event("#{name}.run_to_completion")
+      # Start the process if it's not started
+      start if !pid
+
+      # Tell the process to stop at nothing (no blocking)
+      @write_to_process.print "nothing\n"
+
+      # Wait for the process to exit
+      wait_for_exit
+      example.log_event("#{name}.run_to_completion finished")
+    end
+
+    def wait_for_exit
+      example.log_event("#{name}.wait_for_exit (pid #{pid})")
+      Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+        Process.wait(pid) if pid
+      end
+      example.log_event("#{name}.wait_for_exit finished (pid #{pid})")
+    end
+
+    def stop
+      if pid
+        example.log_event("#{name}.stop (pid #{pid})")
+        begin
+          # Send it the kill signal over and over until it dies
+          Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+            Process.kill(:KILL, pid)
+            while !Process.waitpid2(pid, Process::WNOHANG)
+              sleep(0.05)
+            end
+          end
+          example.log_event("#{name}.stop finished (stopped pid #{pid})")
+        # Process not found is perfectly fine when we're trying to kill a process :)
+        rescue Errno::ESRCH
+          example.log_event("#{name}.stop finished (pid #{pid} wasn't running)")
+        end
+      end
+    end
+
+    def fire_event(event)
+      # Let the caller know what event we've reached
+      write_to_tests.print("after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
+
+      # Block until the client tells us where to stop
+      if !@run_to_event || event == @run_to_event
+        write_to_tests.print("waiting for instructions after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
+        @run_to_event = read_from_tests.gets.strip
+        write_to_tests.print("told to run to #{@run_to_event} after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
+      elsif @run_to_event
+        write_to_tests.print("continuing until #{@run_to_event} after #{event}@#{Time.now.strftime("%H:%M:%S.%L")}\n")
+      end
+    end
+
+    private
+
+    attr_reader :read_from_process
+    attr_reader :write_to_tests
+    attr_reader :read_from_tests
+    attr_reader :write_to_process
+
+    class TestRunLock < Chef::RunLock
+      attr_accessor :client_process
+      def create_lock
+        super
+        client_process.fire_event("created lock")
+      end
+    end
+
+    def start
+      example.log_event("#{name}.start")
+      @pid = fork do
+        begin
+          Timeout::timeout(CLIENT_PROCESS_TIMEOUT) do
+            run_lock = TestRunLock.new(example.lockfile)
+            run_lock.client_process = self
+            fire_event("started")
+            run_lock.acquire
+            fire_event("acquired lock")
+            run_lock.save_pid
+            fire_event("saved pid")
+            exit!(0)
+          end
+        rescue
+          fire_event($!.message.lines.join(" // "))
+          raise
+        end
+      end
+      example.log_event("#{name}.start forked (pid #{pid})")
+    end
+
+    def readline_nonblock(fd)
+      buffer = ""
+      buffer << fd.read_nonblock(1) while buffer[-1] != "\n"
+
+      buffer
+    #rescue IO::EAGAINUnreadable
+    rescue IO::WaitReadable
+      unless buffer == ""
+        sleep 0.1
+        retry
+      end
+      nil
+    end
   end
 end
diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb
index fa9de77..fe2abdb 100644
--- a/spec/functional/shell_spec.rb
+++ b/spec/functional/shell_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,11 @@
 # limitations under the License.
 #
 
-require 'functional/resource/base'
-require 'chef/version'
-require 'chef/shell'
-require 'chef/mixin/command/unix'
+require "spec_helper"
+require "functional/resource/base"
+require "chef/version"
+require "chef/shell"
+require "chef/mixin/command/unix"
 
 describe Shell do
 
@@ -29,6 +30,8 @@ describe Shell do
   describe "smoke tests", :unix_only => true do
     include Chef::Mixin::Command::Unix
 
+    TIMEOUT = 300
+
     def read_until(io, expected_value)
       start = Time.new
       buffer = ""
@@ -38,15 +41,30 @@ describe Shell do
         rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EIO, EOFError
           sleep 0.01
         end
-        if Time.new - start > 30
-          STDERR.puts "did not read expected value `#{expected_value}' within 15s"
-          STDERR.puts "Buffer so far: `#{buffer}'"
-          break
+        if Time.new - start > TIMEOUT
+          raise "did not read expected value `#{expected_value}' within #{TIMEOUT}s\n" +
+            "Buffer so far: `#{buffer}'"
         end
       end
       buffer
     end
 
+    def flush_output(io)
+      start = Time.new
+      loop do
+        begin
+          io.read_nonblock(1)
+        rescue Errno::EWOULDBLOCK, Errno::EAGAIN
+          sleep 0.01
+        rescue EOFError, Errno::EIO
+          break
+        end
+        if Time.new - start > TIMEOUT
+          raise "timed out after #{TIMEOUT}s waiting for output to end"
+        end
+      end
+    end
+
     def wait_or_die(pid)
       start = Time.new
 
@@ -65,14 +83,14 @@ describe Shell do
       when "aix"
         config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
         path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
-        output = ''
+        output = ""
         status = popen4("#{path_to_chef_shell} -c #{config} #{options}", :waitlast => true) do |pid, stdin, stdout, stderr|
-          read_until(stdout, "chef >")
+          read_until(stdout, "chef (#{Chef::VERSION})>")
           yield stdout, stdin if block_given?
           stdin.write("'done'\n")
           output = read_until(stdout, '=> "done"')
           stdin.print("exit\n")
-          read_until(stdout, "\n")
+          flush_output(stdout)
         end
 
         [output, status.exitstatus]
@@ -80,18 +98,16 @@ describe Shell do
         # Windows ruby installs don't (always?) have PTY,
         # so hide the require here
         begin
-          require 'pty'
+          require "pty"
           config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
           path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
           reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}")
-          read_until(reader, "chef >")
+          read_until(reader, "chef (#{Chef::VERSION})>")
           yield reader, writer if block_given?
           writer.puts('"done"')
           output = read_until(reader, '=> "done"')
           writer.print("exit\n")
-          read_until(reader, "exit")
-          read_until(reader, "\n")
-          read_until(reader, "\n")
+          flush_output(reader)
           writer.close
 
           exitstatus = wait_or_die(pid)
diff --git a/spec/functional/tiny_server_spec.rb b/spec/functional/tiny_server_spec.rb
index 87be948..3e394f3 100644
--- a/spec/functional/tiny_server_spec.rb
+++ b/spec/functional/tiny_server_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tiny_server'
+require "spec_helper"
+require "tiny_server"
 
 describe TinyServer::API do
   before do
@@ -26,39 +26,39 @@ describe TinyServer::API do
   end
 
   it "is a Singleton" do
-    expect {TinyServer::API.new}.to raise_error
+    expect { TinyServer::API.new }.to raise_error
   end
 
   it "clears the router" do
-    @api.get('/blargh', 200, "blargh")
+    @api.get("/blargh", 200, "blargh")
     @api.clear
     expect(@api.routes["GET"]).to be_empty
   end
 
   it "creates a route for a GET request" do
-    @api.get('/foo/bar', 200, 'hello foobar')
+    @api.get("/foo/bar", 200, "hello foobar")
     # WEBrick gives you the full URI with host, Thin only gave the part after scheme+host+port
-    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/foo/bar')
-    expect(response).to eq([200, {'Content-Type' => 'application/json'}, [ 'hello foobar' ]])
+    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "http://localhost:1974/foo/bar")
+    expect(response).to eq([200, { "Content-Type" => "application/json" }, [ "hello foobar" ]])
   end
 
   it "creates a route for a request with a block" do
     block_called = false
-    @api.get('/bar/baz', 200) { block_called = true; 'hello barbaz' }
-    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/bar/baz')
-    expect(response).to eq([200, {'Content-Type' => 'application/json'}, [ 'hello barbaz' ]])
+    @api.get("/bar/baz", 200) { block_called = true; "hello barbaz" }
+    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "http://localhost:1974/bar/baz")
+    expect(response).to eq([200, { "Content-Type" => "application/json" }, [ "hello barbaz" ]])
     expect(block_called).to be_truthy
   end
 
   it "returns debugging info for 404s" do
-    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/no_such_thing')
+    response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => "/no_such_thing")
     expect(response[0]).to eq(404)
-    expect(response[1]).to eq({'Content-Type' => 'application/json'})
+    expect(response[1]).to eq({ "Content-Type" => "application/json" })
     expect(response[2]).to be_a_kind_of(Array)
     response_obj = Chef::JSONCompat.from_json(response[2].first)
     expect(response_obj["message"]).to eq("no data matches the request for /no_such_thing")
-    expect(response_obj["available_routes"]).to eq({"GET"=>[], "PUT"=>[], "POST"=>[], "DELETE"=>[]})
-    expect(response_obj["request"]).to eq({"REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"/no_such_thing"})
+    expect(response_obj["available_routes"]).to eq({ "GET" => [], "PUT" => [], "POST" => [], "DELETE" => [] })
+    expect(response_obj["request"]).to eq({ "REQUEST_METHOD" => "GET", "REQUEST_URI" => "/no_such_thing" })
   end
 
 end
@@ -70,8 +70,8 @@ describe TinyServer::Manager do
 
     TinyServer::API.instance.get("/index", 200, "[\"hello\"]")
 
-    rest = Chef::REST.new('http://localhost:9000', false, false)
-    expect(rest.get_rest("index")).to eq(["hello"])
+    rest = Chef::HTTP.new("http://localhost:9000")
+    expect(rest.get("index")).to eq("[\"hello\"]")
 
     @server.stop
   end
diff --git a/spec/functional/util/path_helper_spec.rb b/spec/functional/util/path_helper_spec.rb
index 0321702..f1a953e 100644
--- a/spec/functional/util/path_helper_spec.rb
+++ b/spec/functional/util/path_helper_spec.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'tmpdir'
-require 'chef/util/path_helper'
-require 'spec_helper'
+require "tmpdir"
+require "chef/util/path_helper"
+require "spec_helper"
 
 describe Chef::Util::PathHelper, "escape_glob" do
   PathHelper = Chef::Util::PathHelper
@@ -27,7 +27,7 @@ describe Chef::Util::PathHelper, "escape_glob" do
       # add some files
       files = ["some.rb", "file.txt", "names.csv"]
       files.each do |file|
-        File.new(File.join(dir, file), 'w').close
+        File.new(File.join(dir, file), "w").close
       end
 
       pattern = File.join(PathHelper.escape_glob(dir), "*")
diff --git a/spec/functional/util/powershell/cmdlet_spec.rb b/spec/functional/util/powershell/cmdlet_spec.rb
index 201fb95..6ddbea2 100644
--- a/spec/functional/util/powershell/cmdlet_spec.rb
+++ b/spec/functional/util/powershell/cmdlet_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
+# Author:: Adam Edwards (<adamed at chef.io>)
 #
-# Copyright:: 2014, Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,24 +16,21 @@
 # limitations under the License.
 #
 
-require 'chef/json_compat'
-require File.expand_path('../../../../spec_helper', __FILE__)
+require "chef/json_compat"
+require File.expand_path("../../../../spec_helper", __FILE__)
 
-describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only  do
+describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
   before(:all) do
-    ohai = Ohai::System.new
-    ohai.load_plugins
-    ohai.run_plugins(true, ['platform', 'kernel'])
     @node = Chef::Node.new
-    @node.consume_external_attrs(ohai.data, {})
+    @node.consume_external_attrs(OHAI_SYSTEM.data, {})
   end
   let(:cmd_output_format) { :text }
-  let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-childitem', cmd_output_format, {:depth => 2}) }
-  let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-idontexist', cmd_output_format) }
-  let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'get-item', cmd_output_format, {:depth => 2}) }
-  let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, 'alias', cmd_output_format, {:depth => 2}) }
+  let(:simple_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "get-childitem", cmd_output_format, { :depth => 2 }) }
+  let(:invalid_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "get-idontexist", cmd_output_format) }
+  let(:cmdlet_get_item_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, "get-item", cmd_output_format, { :depth => 2 }) }
+  let(:cmdlet_alias_requires_switch_or_argument) { Chef::Util::Powershell::Cmdlet.new(@node, "alias", cmd_output_format, { :depth => 2 }) }
   let(:etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" }
-  let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE")}
+  let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE") }
 
   it "executes a simple process" do
     result = simple_cmdlet.run
@@ -41,17 +38,17 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only  do
   end
 
   it "#run does not raise a PowershellCmdletException exception if the command cannot be executed" do
-    expect {invalid_cmdlet.run}.not_to raise_error
+    expect { invalid_cmdlet.run }.not_to raise_error
   end
 
   it "#run! raises a PowershellCmdletException exception if the command cannot be executed" do
-    expect {invalid_cmdlet.run!}.to raise_error(Chef::Exceptions::PowershellCmdletException)
+    expect { invalid_cmdlet.run! }.to raise_error(Chef::Exceptions::PowershellCmdletException)
   end
 
   it "executes a 64-bit command on a 64-bit OS, 32-bit otherwise" do
-    os_arch = ENV['PROCESSOR_ARCHITEW6432']
+    os_arch = ENV["PROCESSOR_ARCHITEW6432"]
     if os_arch.nil?
-      os_arch = ENV['PROCESSOR_ARCHITECTURE']
+      os_arch = ENV["PROCESSOR_ARCHITECTURE"]
     end
 
     result = architecture_cmdlet.run
@@ -61,17 +58,17 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only  do
   end
 
   it "passes command line switches to the command" do
-    result = cmdlet_alias_requires_switch_or_argument.run({:name => 'ls'})
+    result = cmdlet_alias_requires_switch_or_argument.run({ :name => "ls" })
     expect(result.succeeded?).to eq(true)
   end
 
   it "passes command line arguments to the command" do
-    result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+    result = cmdlet_alias_requires_switch_or_argument.run({}, {}, "ls")
     expect(result.succeeded?).to eq(true)
   end
 
   it "passes command line arguments and switches to the command" do
-    result = cmdlet_get_item_requires_switch_or_argument.run({:path => etc_directory},{},' | select-object -property fullname | format-table -hidetableheaders')
+    result = cmdlet_get_item_requires_switch_or_argument.run({ :path => etc_directory }, {}, " | select-object -property fullname | format-table -hidetableheaders")
     expect(result.succeeded?).to eq(true)
     returned_directory = result.return_value
     returned_directory.strip!
@@ -79,7 +76,7 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only  do
   end
 
   it "passes execution options to the command" do
-    result = cmdlet_get_item_requires_switch_or_argument.run({},{:cwd => etc_directory},'. | select-object -property fullname | format-table -hidetableheaders')
+    result = cmdlet_get_item_requires_switch_or_argument.run({}, { :cwd => etc_directory }, ". | select-object -property fullname | format-table -hidetableheaders")
     expect(result.succeeded?).to eq(true)
     returned_directory = result.return_value
     returned_directory.strip!
@@ -89,26 +86,26 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only  do
   context "when returning json" do
     let(:cmd_output_format) { :json }
     it "returns json format data" do
-      result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls')
+      result = cmdlet_alias_requires_switch_or_argument.run({}, {}, "ls")
       expect(result.succeeded?).to eq(true)
-      expect(lambda{Chef::JSONCompat.parse(result.return_value)}).not_to raise_error
+      expect(lambda { Chef::JSONCompat.parse(result.return_value) }).not_to raise_error
     end
   end
 
   context "when returning Ruby objects" do
     let(:cmd_output_format) { :object }
     it "returns object format data" do
-      result = simple_cmdlet.run({},{:cwd => etc_directory}, 'hosts')
+      result = simple_cmdlet.run({}, { :cwd => etc_directory }, "hosts")
       expect(result.succeeded?).to eq(true)
       data = result.return_value
-      expect(data['Name']).to eq('hosts')
+      expect(data["Name"]).to eq("hosts")
     end
   end
 
   context "when constructor is given invalid arguments" do
     let(:cmd_output_format) { :invalid }
     it "throws an exception if an invalid format is passed to the constructor" do
-      expect(lambda{simple_cmdlet}).to raise_error
+      expect(lambda { simple_cmdlet }).to raise_error
     end
   end
 end
diff --git a/spec/functional/version_spec.rb b/spec/functional/version_spec.rb
index cd5bbc7..a45c25f 100644
--- a/spec/functional/version_spec.rb
+++ b/spec/functional/version_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/mixin/shell_out'
-require 'chef/version'
-require 'ohai/version'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/mixin/shell_out"
+require "chef/version"
+require "ohai/version"
 
 describe "Chef Versions" do
   include Chef::Mixin::ShellOut
diff --git a/spec/functional/win32/crypto_spec.rb b/spec/functional/win32/crypto_spec.rb
index 1492995..75a8bfb 100644
--- a/spec/functional/win32/crypto_spec.rb
+++ b/spec/functional/win32/crypto_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala(<jdm at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,28 +16,25 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 if Chef::Platform.windows?
-  require 'chef/win32/crypto'
+  require "chef/win32/crypto"
 end
 
-describe 'Chef::ReservedNames::Win32::Crypto', :windows_only do
+describe "Chef::ReservedNames::Win32::Crypto", :windows_only do
   describe '#encrypt' do
     before(:all) do
-      ohai_reader = Ohai::System.new
-      ohai_reader.all_plugins("platform")
-
       new_node = Chef::Node.new
-      new_node.consume_external_attrs(ohai_reader.data,{})
+      new_node.consume_external_attrs(OHAI_SYSTEM.data, {})
 
       events = Chef::EventDispatch::Dispatcher.new
 
       @run_context = Chef::RunContext.new(new_node, {}, events)
     end
 
-    let (:plaintext) { 'p at assword' }
+    let (:plaintext) { "p at assword" }
 
-    it 'can be decrypted by powershell' do
+    it "can be decrypted by powershell" do
       encrypted = Chef::ReservedNames::Win32::Crypto.encrypt(plaintext)
       resource = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context)
       resource.code <<-EOF
diff --git a/spec/functional/win32/registry_helper_spec.rb b/spec/functional/win32/registry_helper_spec.rb
deleted file mode 100644
index 7b070e6..0000000
--- a/spec/functional/win32/registry_helper_spec.rb
+++ /dev/null
@@ -1,632 +0,0 @@
-#
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-require 'chef/win32/registry'
-
-describe Chef::Resource::RegistryKey, :unix_only do
-  before(:all) do
-    events = Chef::EventDispatch::Dispatcher.new
-    node = Chef::Node.new
-    ohai = Ohai::System.new
-    ohai.all_plugins
-    node.consume_external_attrs(ohai.data,{})
-    run_context = Chef::RunContext.new(node, {}, events)
-    @resource = Chef::Resource::RegistryKey.new("HKCU\\Software", run_context)
-  end
-  context "when load_current_resource is run on a non-windows node" do
-    it "throws an exception because you don't have a windows registry (derp)" do
-      @resource.key("HKCU\\Software\\Opscode")
-      @resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}])
-      expect{@resource.run_action(:create)}.to raise_error(Chef::Exceptions::Win32NotWindows)
-    end
-  end
-end
-
-describe 'Chef::Win32::Registry', :windows_only do
-
-  before(:all) do
-    #Create a registry item
-    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root"
-    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch"
-    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Flower"
-    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-      reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous'
-      reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
-    end
-    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-      reg['Strong', Win32::Registry::REG_SZ] = 'bird nest'
-    end
-    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Flower', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-      reg['Petals', Win32::Registry::REG_MULTI_SZ] = ["Pink", "Delicate"]
-    end
-
-    #Create the node with ohai data
-    events = Chef::EventDispatch::Dispatcher.new
-    @node = Chef::Node.new
-    ohai = Ohai::System.new
-    ohai.all_plugins
-    @node.consume_external_attrs(ohai.data,{})
-    @run_context = Chef::RunContext.new(@node, {}, events)
-
-    #Create a registry object that has access ot the node previously created
-    @registry = Chef::Win32::Registry.new(@run_context)
-  end
-
-  #Delete what is left of the registry key-values previously created
-  after(:all) do
-    ::Win32::Registry::HKEY_CURRENT_USER.open("Software") do |reg|
-      reg.delete_key("Root", true)
-    end
-  end
-
-  # Server Versions
-  # it "succeeds if server versiion is 2003R2, 2008, 2008R2, 2012" do
-  # end
-  # it "falis if the server versions are anything else" do
-  # end
-
-  describe "hive_exists?" do
-    it "returns true if the hive exists" do
-      expect(@registry.hive_exists?("HKCU\\Software\\Root")).to eq(true)
-    end
-
-    it "returns false if the hive does not exist" do
-      hive = expect(@registry.hive_exists?("LYRU\\Software\\Root")).to eq(false)
-    end
-  end
-
-  describe "key_exists?" do
-    it "returns true if the key path exists" do
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Branch\\Flower")).to eq(true)
-    end
-
-    it "returns false if the key path does not exist" do
-      expect(@registry.key_exists?("HKCU\\Software\\Branch\\Flower")).to eq(false)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.key_exists?("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "key_exists!" do
-    it "returns true if the key path exists" do
-      expect(@registry.key_exists!("HKCU\\Software\\Root\\Branch\\Flower")).to eq(true)
-    end
-
-    it "throws an exception if the key path does not exist" do
-      expect {@registry.key_exists!("HKCU\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.key_exists!("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "value_exists?" do
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.value_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-    it "throws an exception if the key does not exist" do
-      expect {@registry.value_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-    it "returns true if the value exists" do
-      expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"})).to eq(true)
-    end
-    it "returns false if the value does not exist" do
-      expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})).to eq(false)
-    end
-  end
-
-  describe "value_exists!" do
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.value_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-    it "throws an exception if the key does not exist" do
-      expect {@registry.value_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-    it "returns true if the value exists" do
-      expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"})).to eq(true)
-    end
-    it "throws an exception if the value does not exist" do
-      expect {@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
-    end
-  end
-
-  describe "data_exists?" do
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.data_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-    it "throws an exception if the key does not exist" do
-      expect {@registry.data_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-    it "returns true if all the data matches" do
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
-    end
-    it "returns false if the name does not exist" do
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(false)
-    end
-    it "returns false if the types do not match" do
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})).to eq(false)
-    end
-    it "returns false if the data does not match" do
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})).to eq(false)
-    end
-  end
-
-  describe "data_exists!" do
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.data_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-    it "throws an exception if the key does not exist" do
-      expect {@registry.data_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-    it "returns true if all the data matches" do
-      expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})).to eq(true)
-    end
-    it "throws an exception if the name does not exist" do
-      expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
-    end
-    it "throws an exception if the types do not match" do
-      expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
-    end
-    it "throws an exception if the data does not match" do
-      expect {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
-    end
-  end
-
-  describe "get_values" do
-    it "returns all values for a key if it exists" do
-      values = @registry.get_values("HKCU\\Software\\Root")
-      expect(values).to be_an_instance_of Array
-      expect(values).to eq([{:name=>"RootType1", :type=>:string, :data=>"fibrous"},
-                        {:name=>"Roots", :type=>:multi_string, :data=>["strong roots", "healthy tree"]}])
-    end
-
-    it "throws an exception if the key does not exist" do
-      expect {@registry.get_values("HKCU\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.get_values("JKLM\\Software\\Branch\\Flower")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "set_value" do
-    it "updates a value if the key, value exist and type matches and value different" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
-    end
-
-    it "updates a value if the type does match and the values are different" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(false)
-    end
-
-    it "creates a value if key exists and value does not" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
-    end
-
-    it "does nothing if data,type and name parameters for the value are same" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(false)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})).to eq(true)
-    end
-
-    it "throws an exception if the key does not exist" do
-      expect {@registry.set_value("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-
-    # we are validating that the data gets .to_i called on it when type is a :dword
-
-    it "casts an integer string given as a dword into an integer" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>"32767"})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>32767})).to eq(true)
-    end
-
-    it "casts a nonsense string given as a dword into zero" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>"whatdoesthisdo"})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>0})).to eq(true)
-    end
-
-    it "throws an exception when trying to cast an array to an int for a dword" do
-      expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:dword, :data=>["one","two"]})}.to raise_error
-    end
-
-    # we are validating that the data gets .to_s called on it when type is a :string
-
-    it "stores the string representation of an array into a string if you pass it an array" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>["one","two"]})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>'["one", "two"]'})).to eq(true)
-    end
-
-    it "stores the string representation of a number into a string if you pass it an number" do
-      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>65535})).to eq(true)
-      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>"65535"})).to eq(true)
-    end
-
-    # we are validating that the data gets .to_a called on it when type is a :multi_string
-
-    it "throws an exception when a multi-string is passed a number" do
-      expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:multi_string, :data=>65535})}.to raise_error
-    end
-
-    it "throws an exception when a multi-string is passed a string" do
-      expect {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeWat", :type=>:multi_string, :data=>"foo"})}.to raise_error
-    end
-  end
-
-  describe "create_key" do
-    before(:all) do
-      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root") do |reg|
-        begin
-          reg.delete_key("Trunk", true)
-        rescue
-        end
-      end
-    end
-
-    it "throws an exception if the path has missing keys but recursive set to false" do
-      expect {@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(false)
-    end
-
-    it "creates the key_path if the keys were missing but recursive was set to true" do
-      expect(@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", true)).to eq(true)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
-    end
-
-    it "does nothing if the key already exists" do
-      expect(@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)).to eq(true)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
-    end
-
-    it "throws an exception of the hive does not exist" do
-      expect {@registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "delete_value" do
-    before(:all) do
-      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
-      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-        reg['Peter', Win32::Registry::REG_SZ] = 'Tiny'
-      end
-    end
-
-    it "deletes values if the value exists" do
-      expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(true)
-      expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(false)
-    end
-
-    it "does nothing if value does not exist" do
-      expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(true)
-      expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})).to eq(false)
-    end
-
-    it "throws an exception if the key does not exist?" do
-      expect {@registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "delete_key" do
-    before (:all) do
-      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Fruit"
-      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Fruit', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-        reg['Apple', Win32::Registry::REG_MULTI_SZ] = ["Red", "Juicy"]
-      end
-      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
-      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
-        reg['Peter', Win32::Registry::REG_SZ] = 'Tiny'
-      end
-    end
-
-    it "deletes a key if it has no subkeys" do
-      expect(@registry.delete_key("HKCU\\Software\\Root\\Branch\\Fruit", false)).to eq(true)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Branch\\Fruit")).to eq(false)
-    end
-
-    it "throws an exception if key to delete has subkeys and recursive is false" do
-      expect { @registry.delete_key("HKCU\\Software\\Root\\Trunk", false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
-    end
-
-    it "deletes a key if it has subkeys and recursive true" do
-      expect(@registry.delete_key("HKCU\\Software\\Root\\Trunk", true)).to eq(true)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk")).to eq(false)
-    end
-
-    it "does nothing if the key does not exist" do
-      expect(@registry.delete_key("HKCU\\Software\\Root\\Trunk", true)).to eq(true)
-      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk")).to eq(false)
-    end
-
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false)}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-  end
-
-  describe "has_subkeys?" do
-    before(:all) do
-      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk"
-      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root\\Trunk") do |reg|
-        begin
-          reg.delete_key("Red", true)
-        rescue
-        end
-      end
-    end
-
-    it "throws an exception if the hive was missing" do
-      expect {@registry.has_subkeys?("LMNO\\Software\\Root")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-
-    it "throws an exception if the key is missing" do
-      expect {@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "returns true if the key has subkeys" do
-      expect(@registry.has_subkeys?("HKCU\\Software\\Root")).to eq(true)
-    end
-
-    it "returns false if the key has no subkeys" do
-      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Red"
-      expect(@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")).to eq(false)
-    end
-  end
-
-  describe "get_subkeys" do
-    it "throws an exception if the key is missing" do
-      expect {@registry.get_subkeys("HKCU\\Software\\Trunk\\Red")}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-    it "throws an exception if the hive does not exist" do
-      expect {@registry.get_subkeys("JKLM\\Software\\Root")}.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
-    end
-    it "returns the array of subkeys for a given key" do
-      subkeys = @registry.get_subkeys("HKCU\\Software\\Root")
-      reg_subkeys = []
-      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root", Win32::Registry::KEY_ALL_ACCESS) do |reg|
-        reg.each_key{|name| reg_subkeys << name}
-      end
-      expect(reg_subkeys).to eq(subkeys)
-    end
-  end
-
-  describe "architecture" do
-    describe "on 32-bit" do
-      before(:all) do
-        @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine]
-        @node.automatic_attrs[:kernel][:machine] = :i386
-      end
-
-      after(:all) do
-        @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine
-      end
-
-      context "registry constructor" do
-        it "throws an exception if requested architecture is 64bit but running on 32bit" do
-          expect {Chef::Win32::Registry.new(@run_context, :x86_64)}.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
-        end
-
-        it "can correctly set the requested architecture to 32-bit" do
-          @r = Chef::Win32::Registry.new(@run_context, :i386)
-          expect(@r.architecture).to eq(:i386)
-          expect(@r.registry_system_architecture).to eq(0x0200)
-        end
-
-        it "can correctly set the requested architecture to :machine" do
-          @r = Chef::Win32::Registry.new(@run_context, :machine)
-          expect(@r.architecture).to eq(:machine)
-          expect(@r.registry_system_architecture).to eq(0x0200)
-        end
-      end
-
-      context "architecture setter" do
-        it "throws an exception if requested architecture is 64bit but running on 32bit" do
-          expect {@registry.architecture = :x86_64}.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
-        end
-
-        it "sets the requested architecture to :machine if passed :machine" do
-          @registry.architecture = :machine
-          expect(@registry.architecture).to eq(:machine)
-          expect(@registry.registry_system_architecture).to eq(0x0200)
-        end
-
-        it "sets the requested architecture to 32-bit if passed i386 as a string" do
-          @registry.architecture = :i386
-          expect(@registry.architecture).to eq(:i386)
-          expect(@registry.registry_system_architecture).to eq(0x0200)
-        end
-      end
-    end
-
-    describe "on 64-bit" do
-      before(:all) do
-        @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine]
-        @node.automatic_attrs[:kernel][:machine] = :x86_64
-      end
-
-      after(:all) do
-        @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine
-      end
-
-      context "registry constructor" do
-        it "can correctly set the requested architecture to 32-bit" do
-          @r = Chef::Win32::Registry.new(@run_context, :i386)
-          expect(@r.architecture).to eq(:i386)
-          expect(@r.registry_system_architecture).to eq(0x0200)
-        end
-
-        it "can correctly set the requested architecture to 64-bit" do
-          @r = Chef::Win32::Registry.new(@run_context, :x86_64)
-          expect(@r.architecture).to eq(:x86_64)
-          expect(@r.registry_system_architecture).to eq(0x0100)
-        end
-
-        it "can correctly set the requested architecture to :machine" do
-          @r = Chef::Win32::Registry.new(@run_context, :machine)
-          expect(@r.architecture).to eq(:machine)
-          expect(@r.registry_system_architecture).to eq(0x0100)
-        end
-      end
-
-      context "architecture setter" do
-        it "sets the requested architecture to 64-bit if passed 64-bit" do
-          @registry.architecture = :x86_64
-          expect(@registry.architecture).to eq(:x86_64)
-          expect(@registry.registry_system_architecture).to eq(0x0100)
-        end
-
-        it "sets the requested architecture to :machine if passed :machine" do
-          @registry.architecture = :machine
-          expect(@registry.architecture).to eq(:machine)
-          expect(@registry.registry_system_architecture).to eq(0x0100)
-        end
-
-        it "sets the requested architecture to 32-bit if passed 32-bit" do
-          @registry.architecture = :i386
-          expect(@registry.architecture).to eq(:i386)
-          expect(@registry.registry_system_architecture).to eq(0x0200)
-        end
-      end
-    end
-
-    describe "when running on an actual 64-bit server", :windows64_only do
-      before(:all) do
-        begin
-          ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
-            reg.delete_key("Trunk", true)
-          end
-        rescue
-        end
-        begin
-          ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
-            reg.delete_key("Trunk", true)
-          end
-        rescue
-        end
-        # 64-bit
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Mauve", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100)
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Mauve', Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
-          reg['Alert', Win32::Registry::REG_SZ] = 'Universal'
-        end
-        # 32-bit
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Poosh", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200)
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Poosh', Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
-          reg['Status', Win32::Registry::REG_SZ] = 'Lost'
-        end
-      end
-
-      after(:all) do
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
-          reg.delete_key("Trunk", true)
-        end
-        ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
-          reg.delete_key("Trunk", true)
-        end
-      end
-
-      describe "key_exists?" do
-        it "does not find 64-bit keys in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(false)
-        end
-        it "finds 32-bit keys in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(true)
-        end
-        it "does not find 32-bit keys in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(true)
-        end
-        it "finds 64-bit keys in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(false)
-        end
-      end
-
-      describe "value_exists?" do
-        it "does not find 64-bit values in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect{@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-        end
-        it "finds 32-bit values in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect(@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})).to eq(true)
-        end
-        it "does not find 32-bit values in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect(@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})).to eq(true)
-        end
-        it "finds 64-bit values in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect{@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-        end
-      end
-
-      describe "data_exists?" do
-        it "does not find 64-bit keys in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect{@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-        end
-        it "finds 32-bit keys in the 32-bit registry" do
-          @registry.architecture=:i386
-          expect(@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})).to eq(true)
-        end
-        it "does not find 32-bit keys in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect(@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})).to eq(true)
-        end
-        it "finds 64-bit keys in the 64-bit registry" do
-          @registry.architecture=:x86_64
-          expect{@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-        end
-      end
-
-      describe "create_key" do
-        it "can create a 32-bit only registry key" do
-          @registry.architecture = :i386
-          expect(@registry.create_key("HKLM\\Software\\Root\\Trunk\\Red", true)).to eq(true)
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red")).to eq(true)
-          @registry.architecture = :x86_64
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red")).to eq(false)
-        end
-
-        it "can create a 64-bit only registry key" do
-          @registry.architecture = :x86_64
-          expect(@registry.create_key("HKLM\\Software\\Root\\Trunk\\Blue", true)).to eq(true)
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue")).to eq(true)
-          @registry.architecture = :i386
-          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue")).to eq(false)
-        end
-      end
-
-    end
-  end
-end
diff --git a/spec/functional/win32/registry_spec.rb b/spec/functional/win32/registry_spec.rb
new file mode 100644
index 0000000..f0258ab
--- /dev/null
+++ b/spec/functional/win32/registry_spec.rb
@@ -0,0 +1,623 @@
+#
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/win32/registry"
+
+describe "Chef::Win32::Registry", :windows_only do
+
+  before(:all) do
+    #Create a registry item
+    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root"
+    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch"
+    ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Flower"
+    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+      reg["RootType1", Win32::Registry::REG_SZ] = "fibrous"
+      reg.write("Roots", Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"])
+    end
+    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+      reg["Strong", Win32::Registry::REG_SZ] = "bird nest"
+    end
+    ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Flower', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+      reg["Petals", Win32::Registry::REG_MULTI_SZ] = ["Pink", "Delicate"]
+    end
+
+    #Create the node with ohai data
+    events = Chef::EventDispatch::Dispatcher.new
+    @node = Chef::Node.new
+    @node.consume_external_attrs(OHAI_SYSTEM.data, {})
+    @run_context = Chef::RunContext.new(@node, {}, events)
+
+    #Create a registry object that has access ot the node previously created
+    @registry = Chef::Win32::Registry.new(@run_context)
+  end
+
+  #Delete what is left of the registry key-values previously created
+  after(:all) do
+    ::Win32::Registry::HKEY_CURRENT_USER.open("Software") do |reg|
+      reg.delete_key("Root", true)
+    end
+  end
+
+  # Server Versions
+  # it "succeeds if server versiion is 2003R2, 2008, 2008R2, 2012" do
+  # end
+  # it "falis if the server versions are anything else" do
+  # end
+
+  describe "hive_exists?" do
+    it "returns true if the hive exists" do
+      expect(@registry.hive_exists?("HKCU\\Software\\Root")).to eq(true)
+    end
+
+    it "returns false if the hive does not exist" do
+      hive = expect(@registry.hive_exists?("LYRU\\Software\\Root")).to eq(false)
+    end
+  end
+
+  describe "key_exists?" do
+    it "returns true if the key path exists" do
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Branch\\Flower")).to eq(true)
+    end
+
+    it "returns false if the key path does not exist" do
+      expect(@registry.key_exists?("HKCU\\Software\\Branch\\Flower")).to eq(false)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.key_exists?("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "key_exists!" do
+    it "returns true if the key path exists" do
+      expect(@registry.key_exists!("HKCU\\Software\\Root\\Branch\\Flower")).to eq(true)
+    end
+
+    it "throws an exception if the key path does not exist" do
+      expect { @registry.key_exists!("HKCU\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.key_exists!("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "value_exists?" do
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.value_exists?("JKLM\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+    it "throws an exception if the key does not exist" do
+      expect { @registry.value_exists?("HKCU\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+    it "returns true if the value exists" do
+      expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals" })).to eq(true)
+    end
+    it "returns true if the value exists with a case mismatch on the value name" do
+      expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals" })).to eq(true)
+    end
+    it "returns false if the value does not exist" do
+      expect(@registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "FOOBAR" })).to eq(false)
+    end
+  end
+
+  describe "value_exists!" do
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.value_exists!("JKLM\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+    it "throws an exception if the key does not exist" do
+      expect { @registry.value_exists!("HKCU\\Software\\Branch\\Flower", { :name => "Petals" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+    it "returns true if the value exists" do
+      expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals" })).to eq(true)
+    end
+    it "returns true if the value exists with a case mismatch on the value name" do
+      expect(@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals" })).to eq(true)
+    end
+    it "throws an exception if the value does not exist" do
+      expect { @registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "FOOBAR" }) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+    end
+  end
+
+  describe "data_exists?" do
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.data_exists?("JKLM\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+    it "throws an exception if the key does not exist" do
+      expect { @registry.data_exists?("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+    it "returns true if all the data matches" do
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] })).to eq(true)
+    end
+    it "returns true if all the data matches with a case mismatch on the data name" do
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals", :type => :multi_string, :data => ["Pink", "Delicate"] })).to eq(true)
+    end
+    it "returns false if the name does not exist" do
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "slateP", :type => :multi_string, :data => ["Pink", "Delicate"] })).to eq(false)
+    end
+    it "returns false if the types do not match" do
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Pink" })).to eq(false)
+    end
+    it "returns false if the data does not match" do
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Mauve", "Delicate"] })).to eq(false)
+    end
+  end
+
+  describe "data_exists!" do
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.data_exists!("JKLM\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+    it "throws an exception if the key does not exist" do
+      expect { @registry.data_exists!("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+    it "returns true if all the data matches" do
+      expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Pink", "Delicate"] })).to eq(true)
+    end
+    it "returns true if all the data matches with a case mismatch on the data name" do
+      expect(@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "petals", :type => :multi_string, :data => ["Pink", "Delicate"] })).to eq(true)
+    end
+    it "throws an exception if the name does not exist" do
+      expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "slateP", :type => :multi_string, :data => ["Pink", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+    end
+    it "throws an exception if the types do not match" do
+      expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Pink" }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+    end
+    it "throws an exception if the data does not match" do
+      expect { @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Mauve", "Delicate"] }) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+    end
+  end
+
+  describe "get_values" do
+    it "returns all values for a key if it exists" do
+      values = @registry.get_values("HKCU\\Software\\Root")
+      expect(values).to be_an_instance_of Array
+      expect(values).to eq([{ :name => "RootType1", :type => :string, :data => "fibrous" },
+                        { :name => "Roots", :type => :multi_string, :data => ["strong roots", "healthy tree"] }])
+    end
+
+    it "throws an exception if the key does not exist" do
+      expect { @registry.get_values("HKCU\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.get_values("JKLM\\Software\\Branch\\Flower") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "set_value" do
+    it "updates a value if the key, value exist and type matches and value different" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+    end
+
+    it "updates a value if the type does match and the values are different" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Yellow" })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :string, :data => "Yellow" })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(false)
+    end
+
+    it "creates a value if key exists and value does not" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+    end
+
+    it "does nothing if data,type and name parameters for the value are same" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(false)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "Stamen", :type => :multi_string, :data => ["Yellow", "Changed Color"] })).to eq(true)
+    end
+
+    it "throws an exception if the key does not exist" do
+      expect { @registry.set_value("HKCU\\Software\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", { :name => "Petals", :type => :multi_string, :data => ["Yellow", "Changed Color"] }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+
+    # we are validating that the data gets .to_i called on it when type is a :dword
+
+    it "casts an integer string given as a dword into an integer" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe32767", :type => :dword, :data => "32767" })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe32767", :type => :dword, :data => 32767 })).to eq(true)
+    end
+
+    it "casts a nonsense string given as a dword into zero" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeZero", :type => :dword, :data => "whatdoesthisdo" })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeZero", :type => :dword, :data => 0 })).to eq(true)
+    end
+
+    it "throws an exception when trying to cast an array to an int for a dword" do
+      expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :dword, :data => ["one", "two"] }) }.to raise_error
+    end
+
+    # we are validating that the data gets .to_s called on it when type is a :string
+
+    it "stores the string representation of an array into a string if you pass it an array" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBePainful", :type => :string, :data => ["one", "two"] })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBePainful", :type => :string, :data => '["one", "two"]' })).to eq(true)
+    end
+
+    it "stores the string representation of a number into a string if you pass it an number" do
+      expect(@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe65535", :type => :string, :data => 65535 })).to eq(true)
+      expect(@registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBe65535", :type => :string, :data => "65535" })).to eq(true)
+    end
+
+    # we are validating that the data gets .to_a called on it when type is a :multi_string
+
+    it "throws an exception when a multi-string is passed a number" do
+      expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :multi_string, :data => 65535 }) }.to raise_error
+    end
+
+    it "throws an exception when a multi-string is passed a string" do
+      expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeWat", :type => :multi_string, :data => "foo" }) }.to raise_error
+    end
+  end
+
+  describe "create_key" do
+    before(:all) do
+      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root") do |reg|
+        begin
+          reg.delete_key("Trunk", true)
+        rescue
+        end
+      end
+    end
+
+    it "throws an exception if the path has missing keys but recursive set to false" do
+      expect { @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(false)
+    end
+
+    it "creates the key_path if the keys were missing but recursive was set to true" do
+      expect(@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", true)).to eq(true)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
+    end
+
+    it "does nothing if the key already exists" do
+      expect(@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)).to eq(true)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
+    end
+
+    it "throws an exception of the hive does not exist" do
+      expect { @registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "delete_value" do
+    before(:all) do
+      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
+      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+        reg["Peter", Win32::Registry::REG_SZ] = "Tiny"
+      end
+    end
+
+    it "deletes values if the value exists" do
+      expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(true)
+      expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(false)
+    end
+
+    it "does nothing if value does not exist" do
+      expect(@registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(true)
+      expect(@registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" })).to eq(false)
+    end
+
+    it "throws an exception if the key does not exist?" do
+      expect { @registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", { :name => "Peter", :type => :string, :data => "Tiny" }) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "delete_key" do
+    before (:all) do
+      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Fruit"
+      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Fruit', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+        reg["Apple", Win32::Registry::REG_MULTI_SZ] = ["Red", "Juicy"]
+      end
+      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker"
+      ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg|
+        reg["Peter", Win32::Registry::REG_SZ] = "Tiny"
+      end
+    end
+
+    it "deletes a key if it has no subkeys" do
+      expect(@registry.delete_key("HKCU\\Software\\Root\\Branch\\Fruit", false)).to eq(true)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Branch\\Fruit")).to eq(false)
+    end
+
+    it "throws an exception if key to delete has subkeys and recursive is false" do
+      expect { @registry.delete_key("HKCU\\Software\\Root\\Trunk", false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker")).to eq(true)
+    end
+
+    it "deletes a key if it has subkeys and recursive true" do
+      expect(@registry.delete_key("HKCU\\Software\\Root\\Trunk", true)).to eq(true)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk")).to eq(false)
+    end
+
+    it "does nothing if the key does not exist" do
+      expect(@registry.delete_key("HKCU\\Software\\Root\\Trunk", true)).to eq(true)
+      expect(@registry.key_exists?("HKCU\\Software\\Root\\Trunk")).to eq(false)
+    end
+
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false) }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+  end
+
+  describe "has_subkeys?" do
+    before(:all) do
+      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk"
+      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root\\Trunk") do |reg|
+        begin
+          reg.delete_key("Red", true)
+        rescue
+        end
+      end
+    end
+
+    it "throws an exception if the hive was missing" do
+      expect { @registry.has_subkeys?("LMNO\\Software\\Root") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+
+    it "throws an exception if the key is missing" do
+      expect { @registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "returns true if the key has subkeys" do
+      expect(@registry.has_subkeys?("HKCU\\Software\\Root")).to eq(true)
+    end
+
+    it "returns false if the key has no subkeys" do
+      ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Red"
+      expect(@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")).to eq(false)
+    end
+  end
+
+  describe "get_subkeys" do
+    it "throws an exception if the key is missing" do
+      expect { @registry.get_subkeys("HKCU\\Software\\Trunk\\Red") }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+    it "throws an exception if the hive does not exist" do
+      expect { @registry.get_subkeys("JKLM\\Software\\Root") }.to raise_error(Chef::Exceptions::Win32RegHiveMissing)
+    end
+    it "returns the array of subkeys for a given key" do
+      subkeys = @registry.get_subkeys("HKCU\\Software\\Root")
+      reg_subkeys = []
+      ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root", Win32::Registry::KEY_ALL_ACCESS) do |reg|
+        reg.each_key { |name| reg_subkeys << name }
+      end
+      expect(reg_subkeys).to eq(subkeys)
+    end
+  end
+
+  describe "architecture" do
+    describe "on 32-bit" do
+      before(:all) do
+        @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine]
+        @node.automatic_attrs[:kernel][:machine] = :i386
+      end
+
+      after(:all) do
+        @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine
+      end
+
+      context "registry constructor" do
+        it "throws an exception if requested architecture is 64bit but running on 32bit" do
+          expect { Chef::Win32::Registry.new(@run_context, :x86_64) }.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
+        end
+
+        it "can correctly set the requested architecture to 32-bit" do
+          @r = Chef::Win32::Registry.new(@run_context, :i386)
+          expect(@r.architecture).to eq(:i386)
+          expect(@r.registry_system_architecture).to eq(0x0200)
+        end
+
+        it "can correctly set the requested architecture to :machine" do
+          @r = Chef::Win32::Registry.new(@run_context, :machine)
+          expect(@r.architecture).to eq(:machine)
+          expect(@r.registry_system_architecture).to eq(0x0200)
+        end
+      end
+
+      context "architecture setter" do
+        it "throws an exception if requested architecture is 64bit but running on 32bit" do
+          expect { @registry.architecture = :x86_64 }.to raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect)
+        end
+
+        it "sets the requested architecture to :machine if passed :machine" do
+          @registry.architecture = :machine
+          expect(@registry.architecture).to eq(:machine)
+          expect(@registry.registry_system_architecture).to eq(0x0200)
+        end
+
+        it "sets the requested architecture to 32-bit if passed i386 as a string" do
+          @registry.architecture = :i386
+          expect(@registry.architecture).to eq(:i386)
+          expect(@registry.registry_system_architecture).to eq(0x0200)
+        end
+      end
+    end
+
+    describe "on 64-bit" do
+      before(:all) do
+        @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine]
+        @node.automatic_attrs[:kernel][:machine] = :x86_64
+      end
+
+      after(:all) do
+        @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine
+      end
+
+      context "registry constructor" do
+        it "can correctly set the requested architecture to 32-bit" do
+          @r = Chef::Win32::Registry.new(@run_context, :i386)
+          expect(@r.architecture).to eq(:i386)
+          expect(@r.registry_system_architecture).to eq(0x0200)
+        end
+
+        it "can correctly set the requested architecture to 64-bit" do
+          @r = Chef::Win32::Registry.new(@run_context, :x86_64)
+          expect(@r.architecture).to eq(:x86_64)
+          expect(@r.registry_system_architecture).to eq(0x0100)
+        end
+
+        it "can correctly set the requested architecture to :machine" do
+          @r = Chef::Win32::Registry.new(@run_context, :machine)
+          expect(@r.architecture).to eq(:machine)
+          expect(@r.registry_system_architecture).to eq(0x0100)
+        end
+      end
+
+      context "architecture setter" do
+        it "sets the requested architecture to 64-bit if passed 64-bit" do
+          @registry.architecture = :x86_64
+          expect(@registry.architecture).to eq(:x86_64)
+          expect(@registry.registry_system_architecture).to eq(0x0100)
+        end
+
+        it "sets the requested architecture to :machine if passed :machine" do
+          @registry.architecture = :machine
+          expect(@registry.architecture).to eq(:machine)
+          expect(@registry.registry_system_architecture).to eq(0x0100)
+        end
+
+        it "sets the requested architecture to 32-bit if passed 32-bit" do
+          @registry.architecture = :i386
+          expect(@registry.architecture).to eq(:i386)
+          expect(@registry.registry_system_architecture).to eq(0x0200)
+        end
+      end
+    end
+
+    describe "when running on an actual 64-bit server", :windows64_only do
+      before(:all) do
+        begin
+          ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
+            reg.delete_key("Trunk", true)
+          end
+        rescue
+        end
+        begin
+          ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
+            reg.delete_key("Trunk", true)
+          end
+        rescue
+        end
+        # 64-bit
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Mauve", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100)
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Mauve', Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
+          reg["Alert", Win32::Registry::REG_SZ] = "Universal"
+        end
+        # 32-bit
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Poosh", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200)
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Poosh', Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
+          reg["Status", Win32::Registry::REG_SZ] = "Lost"
+        end
+      end
+
+      after(:all) do
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg|
+          reg.delete_key("Root", true)
+        end
+        ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg|
+          reg.delete_key("Root", true)
+        end
+      end
+
+      describe "key_exists?" do
+        it "does not find 64-bit keys in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(false)
+        end
+        it "finds 32-bit keys in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(true)
+        end
+        it "does not find 32-bit keys in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Mauve")).to eq(true)
+        end
+        it "finds 64-bit keys in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Poosh")).to eq(false)
+        end
+      end
+
+      describe "value_exists?" do
+        it "does not find 64-bit values in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect { @registry.value_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+        end
+        it "finds 32-bit values in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect(@registry.value_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status" })).to eq(true)
+        end
+        it "does not find 32-bit values in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect(@registry.value_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert" })).to eq(true)
+        end
+        it "finds 64-bit values in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect { @registry.value_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+        end
+      end
+
+      describe "data_exists?" do
+        it "does not find 64-bit keys in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect { @registry.data_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert", :type => :string, :data => "Universal" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+        end
+        it "finds 32-bit keys in the 32-bit registry" do
+          @registry.architecture = :i386
+          expect(@registry.data_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status", :type => :string, :data => "Lost" })).to eq(true)
+        end
+        it "does not find 32-bit keys in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect(@registry.data_exists?("HKLM\\Software\\Root\\Mauve", { :name => "Alert", :type => :string, :data => "Universal" })).to eq(true)
+        end
+        it "finds 64-bit keys in the 64-bit registry" do
+          @registry.architecture = :x86_64
+          expect { @registry.data_exists?("HKLM\\Software\\Root\\Poosh", { :name => "Status", :type => :string, :data => "Lost" }) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+        end
+      end
+
+      describe "create_key" do
+        it "can create a 32-bit only registry key" do
+          @registry.architecture = :i386
+          expect(@registry.create_key("HKLM\\Software\\Root\\Trunk\\Red", true)).to eq(true)
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red")).to eq(true)
+          @registry.architecture = :x86_64
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red")).to eq(false)
+        end
+
+        it "can create a 64-bit only registry key" do
+          @registry.architecture = :x86_64
+          expect(@registry.create_key("HKLM\\Software\\Root\\Trunk\\Blue", true)).to eq(true)
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue")).to eq(true)
+          @registry.architecture = :i386
+          expect(@registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue")).to eq(false)
+        end
+      end
+
+    end
+  end
+end
diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb
index 27af263..c4951f3 100644
--- a/spec/functional/win32/security_spec.rb
+++ b/spec/functional/win32/security_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 if Chef::Platform.windows?
-  require 'chef/win32/security'
+  require "chef/win32/security"
 end
 
-describe 'Chef::Win32::Security', :windows_only do
+describe "Chef::Win32::Security", :windows_only do
   it "has_admin_privileges? returns true when running as admin" do
     expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to eq(true)
   end
@@ -35,8 +35,8 @@ describe 'Chef::Win32::Security', :windows_only do
     skip "requires user support in mixlib-shellout"
   end
 
-  describe 'get_file_security' do
-    it 'should return a security descriptor when called with a path that exists' do
+  describe "get_file_security" do
+    it "should return a security descriptor when called with a path that exists" do
       security_descriptor = Chef::ReservedNames::Win32::Security.get_file_security(
         "C:\\Program Files")
       # Make sure the security descriptor works
@@ -44,7 +44,7 @@ describe 'Chef::Win32::Security', :windows_only do
     end
   end
 
-  describe 'access_check' do
+  describe "access_check" do
     let(:security_descriptor) {
       Chef::ReservedNames::Win32::Security.get_file_security(
         "C:\\Program Files")
@@ -69,31 +69,31 @@ describe 'Chef::Win32::Security', :windows_only do
 
     let(:desired_access) { Chef::ReservedNames::Win32::Security::FILE_GENERIC_READ }
 
-    it 'should check if the provided token has the desired access' do
-      expect(Chef::ReservedNames::Win32::Security.access_check(security_descriptor, 
+    it "should check if the provided token has the desired access" do
+      expect(Chef::ReservedNames::Win32::Security.access_check(security_descriptor,
                      token, desired_access, mapping)).to be true
     end
   end
 
-  describe 'Chef::Win32::Security::Token' do
+  describe "Chef::Win32::Security::Token" do
     let(:token) {
       Chef::ReservedNames::Win32::Security.open_process_token(
         Chef::ReservedNames::Win32::Process.get_current_process,
         token_rights)
     }
-    context 'with all rights' do
+    context "with all rights" do
       let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_ALL_ACCESS }
 
-      it 'can duplicate a token' do
-        expect{ token.duplicate_token(:SecurityImpersonation) }.not_to raise_error
+      it "can duplicate a token" do
+        expect { token.duplicate_token(:SecurityImpersonation) }.not_to raise_error
       end
     end
 
-    context 'with read only rights' do
+    context "with read only rights" do
       let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_READ }
 
-      it 'raises an exception when trying to duplicate' do
-        expect{ token.duplicate_token(:SecurityImpersonation) }.to raise_error(Chef::Exceptions::Win32APIError)
+      it "raises an exception when trying to duplicate" do
+        expect { token.duplicate_token(:SecurityImpersonation) }.to raise_error(Chef::Exceptions::Win32APIError)
       end
     end
   end
diff --git a/spec/functional/win32/service_manager_spec.rb b/spec/functional/win32/service_manager_spec.rb
index d2474de..7f8e943 100644
--- a/spec/functional/win32/service_manager_spec.rb
+++ b/spec/functional/win32/service_manager_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 if Chef::Platform.windows?
-  require 'chef/application/windows_service_manager'
+  require "chef/application/windows_service_manager"
 end
 
 #
@@ -33,7 +33,7 @@ end
 # directories.
 #
 
-describe "Chef::Application::WindowsServiceManager", :windows_only, :system_windows_service_gem_only do
+describe "Chef::Application::WindowsServiceManager", :windows_only, :system_windows_service_gem_only, :appveyor_only do
 
   include_context "using Win32::Service"
 
@@ -43,7 +43,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
     end
 
     it "throws an error with required missing options" do
-      test_service.each do |key,value|
+      [:service_name, :service_display_name, :service_description, :service_file_path].each do |key|
         service_def = test_service.dup
         service_def.delete(key)
 
@@ -101,8 +101,8 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
       end
 
       it "install => should say service already exists" do
-          service_manager.run(["-a", "install"])
-          expect(@service_manager_output.grep(/already exists/).length).to be > 0
+        service_manager.run(["-a", "install"])
+        expect(@service_manager_output.grep(/already exists/).length).to be > 0
       end
 
       context "and service is stopped" do
@@ -133,7 +133,6 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
           expect(test_service_state).to eq("stopped")
         end
 
-
         ["pause", "resume"].each do |action|
           it "#{action} => should raise error" do
             expect { service_manager.run(["-a", action]) }.to raise_error(SystemCallError)
@@ -211,7 +210,7 @@ describe "Chef::Application::WindowsServiceManager", :windows_only, :system_wind
           end
 
           it "start should raise an error" do
-            expect {service_manager.run(["-a", "start"])}.to raise_error(::Win32::Service::Error)
+            expect { service_manager.run(["-a", "start"]) }.to raise_error(::Win32::Service::Error)
           end
 
         end
diff --git a/spec/functional/win32/sid_spec.rb b/spec/functional/win32/sid_spec.rb
new file mode 100644
index 0000000..eac62d8
--- /dev/null
+++ b/spec/functional/win32/sid_spec.rb
@@ -0,0 +1,55 @@
+#
+# Author:: Dan Bjorge (<dbjorge at gmail.com>)
+# Copyright:: Copyright 2015-2016, Dan Bjorge
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+if Chef::Platform.windows?
+  require "chef/win32/security"
+end
+
+describe "Chef::ReservedNames::Win32::SID", :windows_only do
+  if Chef::Platform.windows?
+    SID ||= Chef::ReservedNames::Win32::Security::SID
+  end
+
+  it "should resolve default_security_object_group as a sane user group", :windows_not_domain_joined_only do
+    # Domain accounts: domain-specific Domain Users SID
+    # Microsoft Accounts: SID.current_user
+    # Else: SID.None
+    expect(SID.default_security_object_group).to eq(SID.None).or eq(SID.current_user)
+  end
+
+  context "running as an elevated administrator user" do
+    it "should resolve default_security_object_owner as the Administrators group" do
+      expect(SID.default_security_object_owner).to eq(SID.Administrators)
+    end
+  end
+
+  context "running as a non-elevated administrator user" do
+    it "should resolve default_security_object_owner as the current user" do
+      skip "requires user support in mixlib-shellout, see security_spec.rb"
+      expect(SID.default_security_object_owner).to eq(SID.Administrators)
+    end
+  end
+
+  context "running as a non-elevated, non-administrator user" do
+    it "should resolve default_security_object_owner as the current user" do
+      skip "requires user support in mixlib-shellout, see security_spec.rb"
+      expect(SID.default_security_object_owner).to eq(SID.current_user)
+    end
+  end
+end
diff --git a/spec/functional/win32/version_info_spec.rb b/spec/functional/win32/version_info_spec.rb
new file mode 100644
index 0000000..b557073
--- /dev/null
+++ b/spec/functional/win32/version_info_spec.rb
@@ -0,0 +1,50 @@
+#
+# Author:: Matt Wrock (<matt at mattwrock.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+if Chef::Platform.windows?
+  require "chef/win32/file/version_info"
+end
+
+describe "Chef::ReservedNames::Win32::File::VersionInfo", :windows_only do
+  require "wmi-lite/wmi"
+  let(:file_path) { ENV["ComSpec"] }
+  let(:os_version) do
+    wmi = WmiLite::Wmi.new
+    os_info = wmi.first_of("Win32_OperatingSystem")
+    os_info["version"]
+  end
+
+  subject { Chef::ReservedNames::Win32::File::VersionInfo.new(file_path) }
+
+  it "file version has the same version as windows" do
+    expect(subject.FileVersion).to start_with(os_version)
+  end
+
+  it "product version has the same version as windows" do
+    expect(subject.ProductVersion).to start_with(os_version)
+  end
+
+  it "company is microsoft" do
+    expect(subject.CompanyName).to eq("Microsoft Corporation")
+  end
+
+  it "file description is command processor" do
+    expect(subject.FileDescription).to eq("Windows Command Processor")
+  end
+end
diff --git a/spec/functional/win32/versions_spec.rb b/spec/functional/win32/versions_spec.rb
index 38af47b..aee5bbb 100644
--- a/spec/functional/win32/versions_spec.rb
+++ b/spec/functional/win32/versions_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Chirag Jog (<chirag at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 if Chef::Platform.windows?
-  require 'chef/win32/version'
+  require "chef/win32/version"
 end
 
 describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on_win2k3 do
   before do
 
     wmi = WmiLite::Wmi.new
-    host = wmi.first_of('Win32_OperatingSystem')
+    host = wmi.first_of("Win32_OperatingSystem")
 
     # Use WMI to determine current OS version.
     # On Win2k8R2 and later, we can dynamically obtain marketing
@@ -37,14 +37,14 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on
     # trademark on Win2k8 and Win2k3 that we're not using in our
     # library, so we have to set the expectation statically.
     if Chef::Platform::windows_server_2003?
-      @current_os_version = 'Windows Server 2003 R2'
+      @current_os_version = "Windows Server 2003 R2"
     elsif is_windows_server_2008?(host)
-      @current_os_version = 'Windows Server 2008'
+      @current_os_version = "Windows Server 2008"
     else
       # The name from WMI is actually what we want in Win2k8R2+.
       # So this expectation sould continue to hold without modification
       # as new versions of Windows are released.
-      @current_os_version = host['caption']
+      @current_os_version = host["caption"]
     end
 
     @version = Chef::ReservedNames::Win32::Version.new
@@ -52,7 +52,7 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on
 
   def for_each_windows_version(&block)
     @version.methods.each do |method_name|
-      if Chef::ReservedNames::Win32::Version::WIN_VERSIONS.keys.find { | key | method_name.to_s == Chef::ReservedNames::Win32::Version.send(:method_name_from_marketing_name,key) }
+      if Chef::ReservedNames::Win32::Version::WIN_VERSIONS.keys.find { |key| method_name.to_s == Chef::ReservedNames::Win32::Version.send(:method_name_from_marketing_name, key) }
         yield method_name
       end
     end
@@ -98,20 +98,20 @@ describe "Chef::ReservedNames::Win32::Version", :windows_only, :not_supported_on
   def is_windows_server_2008?(wmi_host)
     is_win2k8 = false
 
-    os_version = wmi_host['version']
+    os_version = wmi_host["version"]
 
     # The operating system version is a string in the following form
     # that can be split into components based on the '.' delimiter:
     # MajorVersionNumber.MinorVersionNumber.BuildNumber
-    os_version_components = os_version.split('.')
+    os_version_components = os_version.split(".")
 
     if os_version_components.length < 2
-      raise 'WMI returned a Windows version from Win32_OperatingSystem.Version ' +
-        'with an unexpected format. The Windows version could not be determined.'
+      raise "WMI returned a Windows version from Win32_OperatingSystem.Version " +
+        "with an unexpected format. The Windows version could not be determined."
     end
 
     # Windows 6.0 is Windows Server 2008, so test the major and
     # minor version components
-    is_win2k8 = os_version_components[0] == '6' && os_version_components[1] == '0'
+    is_win2k8 = os_version_components[0] == "6" && os_version_components[1] == "0"
   end
 end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index b5c5e12..bfc8865 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -1,36 +1,36 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
-require 'tiny_server'
-require 'tmpdir'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+require "tiny_server"
+require "tmpdir"
 
-def recipes_filename
-  File.join(CHEF_SPEC_DATA, 'recipes.tgz')
-end
+describe "chef-client" do
 
-def start_tiny_server(server_opts={})
-  recipes_size = File::Stat.new(recipes_filename).size
-  @server = TinyServer::Manager.new(server_opts)
-  @server.start
+  def recipes_filename
+    File.join(CHEF_SPEC_DATA, "recipes.tgz")
+  end
+
+  def start_tiny_server(server_opts = {})
+    @server = TinyServer::Manager.new(server_opts)
+    @server.start
     @api = TinyServer::API.instance
-  @api.clear
-  #
-  # trivial endpoints
-  #
-  # just a normal file
-  # (expected_content should be uncompressed)
-  @api.get("/recipes.tgz", 200) {
-    File.open(recipes_filename, "rb") do |f|
-      f.read
-    end
-  }
-end
+    @api.clear
+    #
+    # trivial endpoints
+    #
+    # just a normal file
+    # (expected_content should be uncompressed)
+    @api.get("/recipes.tgz", 200) {
+      File.open(recipes_filename, "rb") do |f|
+        f.read
+      end
+    }
+  end
 
-def stop_tiny_server
-  @server.stop
-  @server = @api = nil
-end
+  def stop_tiny_server
+    @server.stop
+    @server = @api = nil
+  end
 
-describe "chef-client" do
   include IntegrationSupport
   include Chef::Mixin::ShellOut
 
@@ -47,21 +47,38 @@ describe "chef-client" do
   # cf. CHEF-4914
   let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
 
+  let(:critical_env_vars) { %w{PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
+
   when_the_repository "has a cookbook with a no-op recipe" do
-    before { file 'cookbooks/x/recipes/default.rb', '' }
+    before { file "cookbooks/x/recipes/default.rb", "" }
 
     it "should complete with success" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 local_mode true
 cookbook_path "#{path_to('cookbooks')}"
 EOM
 
-      result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir)
-      result.error!
+      shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir)
+    end
+
+    it "should complete successfully with no other environment variables", :skip => (Chef::Platform.windows?) do
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+
+      begin
+        result = shell_out("env -i #{critical_env_vars} #{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir)
+        result.error!
+      rescue
+        Chef::Log.info "Bare invocation will have the following load-path."
+        Chef::Log.info shell_out!("env -i #{critical_env_vars} ruby -e 'puts $:'").stdout
+        raise
+      end
     end
 
     it "should complete successfully with --no-listen" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 local_mode true
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -70,29 +87,34 @@ EOM
       result.error!
     end
 
+    it "should be able to node.save with bad utf8 characters in the node data" do
+      file "cookbooks/x/attributes/default.rb", 'default["badutf8"] = "Elan Ruusam\xE4e"'
+      result = shell_out("#{chef_client} -z -r 'x::default' --disable-config", :cwd => path_to(""))
+      result.error!
+    end
 
-    context 'and no config file' do
-      it 'should complete with success when cwd is just above cookbooks and paths are not specified' do
-        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to(''))
+    context "and no config file" do
+      it "should complete with success when cwd is just above cookbooks and paths are not specified" do
+        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to(""))
         result.error!
       end
 
-      it 'should complete with success when cwd is below cookbooks and paths are not specified' do
-        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to('cookbooks/x'))
+      it "should complete with success when cwd is below cookbooks and paths are not specified" do
+        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => path_to("cookbooks/x"))
         result.error!
       end
 
-      it 'should fail when cwd is below high above and paths are not specified' do
-        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => File.expand_path('..', path_to('')))
+      it "should fail when cwd is below high above and paths are not specified" do
+        result = shell_out("#{chef_client} -z -o 'x::default' --disable-config", :cwd => File.expand_path("..", path_to("")))
         expect(result.exitstatus).to eq(1)
       end
     end
 
-    context 'and a config file under .chef/knife.rb' do
-      before { file '.chef/knife.rb', 'xxx.xxx' }
+    context "and a config file under .chef/knife.rb" do
+      before { file ".chef/knife.rb", "xxx.xxx" }
 
-      it 'should load .chef/knife.rb when -z is specified' do
-        result = shell_out("#{chef_client} -z -o 'x::default'", :cwd => path_to(''))
+      it "should load .chef/knife.rb when -z is specified" do
+        result = shell_out("#{chef_client} -z -o 'x::default'", :cwd => path_to(""))
         # FATAL: Configuration error NoMethodError: undefined method `xxx' for nil:NilClass
         expect(result.stdout).to include("xxx")
       end
@@ -100,7 +122,7 @@ EOM
     end
 
     it "should complete with success" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 local_mode true
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -109,9 +131,9 @@ EOM
       result.error!
     end
 
-    context 'and a private key' do
+    context "and a private key" do
       before do
-        file 'mykey.pem', <<EOM
+        file "mykey.pem", <<EOM
 -----BEGIN RSA PRIVATE KEY-----
 MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf
 0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk
@@ -143,7 +165,7 @@ EOM
       end
 
       it "should complete with success even with a client key" do
-        file 'config/client.rb', <<EOM
+        file "config/client.rb", <<EOM
 local_mode true
 client_key #{path_to('mykey.pem').inspect}
 cookbook_path #{path_to('cookbooks').inspect}
@@ -154,19 +176,19 @@ EOM
       end
 
       it "should run recipes specified directly on the command line" do
-        file 'config/client.rb', <<EOM
+        file "config/client.rb", <<EOM
 local_mode true
 client_key #{path_to('mykey.pem').inspect}
 cookbook_path #{path_to('cookbooks').inspect}
 EOM
 
-        file 'arbitrary.rb', <<EOM
+        file "arbitrary.rb", <<EOM
 file #{path_to('tempfile.txt').inspect} do
   content '1'
 end
 EOM
 
-        file 'arbitrary2.rb', <<EOM
+        file "arbitrary2.rb", <<EOM
 file #{path_to('tempfile2.txt').inspect} do
   content '2'
 end
@@ -175,57 +197,57 @@ EOM
         result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" #{path_to('arbitrary.rb')} #{path_to('arbitrary2.rb')}", :cwd => chef_dir)
         result.error!
 
-        expect(IO.read(path_to('tempfile.txt'))).to eq('1')
-        expect(IO.read(path_to('tempfile2.txt'))).to eq('2')
+        expect(IO.read(path_to("tempfile.txt"))).to eq("1")
+        expect(IO.read(path_to("tempfile2.txt"))).to eq("2")
       end
 
       it "should run recipes specified as relative paths directly on the command line" do
-        file 'config/client.rb', <<EOM
+        file "config/client.rb", <<EOM
 local_mode true
 client_key #{path_to('mykey.pem').inspect}
 cookbook_path #{path_to('cookbooks').inspect}
 EOM
 
-        file 'arbitrary.rb', <<EOM
+        file "arbitrary.rb", <<EOM
 file #{path_to('tempfile.txt').inspect} do
   content '1'
 end
 EOM
 
-        result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" arbitrary.rb", :cwd => path_to(''))
+        result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" arbitrary.rb", :cwd => path_to(""))
         result.error!
 
-        expect(IO.read(path_to('tempfile.txt'))).to eq('1')
+        expect(IO.read(path_to("tempfile.txt"))).to eq("1")
       end
 
       it "should run recipes specified directly on the command line AFTER recipes in the run list" do
-        file 'config/client.rb', <<EOM
+        file "config/client.rb", <<EOM
 local_mode true
 client_key #{path_to('mykey.pem').inspect}
 cookbook_path #{path_to('cookbooks').inspect}
 EOM
 
-        file 'cookbooks/x/recipes/constant_definition.rb', <<EOM
+        file "cookbooks/x/recipes/constant_definition.rb", <<EOM
 class ::Blah
   THECONSTANT = '1'
 end
 EOM
-        file 'arbitrary.rb', <<EOM
+        file "arbitrary.rb", <<EOM
 file #{path_to('tempfile.txt').inspect} do
   content ::Blah::THECONSTANT
 end
 EOM
 
-        result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o x::constant_definition arbitrary.rb", :cwd => path_to(''))
+        result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o x::constant_definition arbitrary.rb", :cwd => path_to(""))
         result.error!
 
-        expect(IO.read(path_to('tempfile.txt'))).to eq('1')
+        expect(IO.read(path_to("tempfile.txt"))).to eq("1")
       end
 
     end
 
     it "should complete with success when passed the -z flag" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_server_url 'http://omg.com/blah'
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -235,7 +257,7 @@ EOM
     end
 
     it "should complete with success when passed the --local-mode flag" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_server_url 'http://omg.com/blah'
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -245,7 +267,7 @@ EOM
     end
 
     it "should not print SSL warnings when running in local-mode" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_server_url 'http://omg.com/blah'
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -256,7 +278,7 @@ EOM
     end
 
     it "should complete with success when passed -z and --chef-zero-port" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_server_url 'http://omg.com/blah'
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -266,7 +288,7 @@ EOM
     end
 
     it "should complete with success when setting the run list with -r" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_server_url 'http://omg.com/blah'
 cookbook_path "#{path_to('cookbooks')}"
 EOM
@@ -278,12 +300,143 @@ EOM
       result.error!
     end
 
+    it "should complete with success when using --profile-ruby and output a profile file" do
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+      result = shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' -z --profile-ruby", :cwd => chef_dir)
+      expect(File.exist?(path_to("config/local-mode-cache/cache/graph_profile.out"))).to be true
+    end
+
+    it "doesn't produce a profile when --profile-ruby is not present" do
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+      result = shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' -z", :cwd => chef_dir)
+      expect(File.exist?(path_to("config/local-mode-cache/cache/graph_profile.out"))).to be false
+    end
+  end
+
+  when_the_repository "has a cookbook that should fail chef_version checks" do
+    before do
+      file "cookbooks/x/recipes/default.rb", ""
+      file "cookbooks/x/metadata.rb", <<EOM
+name 'x'
+version '0.0.1'
+chef_version '~> 999.99'
+EOM
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+EOM
+    end
+    it "should fail the chef client run" do
+      command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+      expect(command.exitstatus).to eql(1)
+      expect(command.stdout).to match(/Chef::Exceptions::CookbookChefVersionMismatch/)
+    end
+  end
+
+  when_the_repository "has a cookbook that uses cheffish resources" do
+    before do
+      file "cookbooks/x/recipes/default.rb", <<-EOM
+        raise "Cheffish was loaded before we used any cheffish things!" if defined?(Cheffish::VERSION)
+        ran_block = false
+        got_server = with_chef_server 'https://blah.com' do
+          ran_block = true
+          run_context.cheffish.current_chef_server
+        end
+        raise "with_chef_server block was not run!" if !ran_block
+        raise "Cheffish was not loaded when we did cheffish things!" if !defined?(Cheffish::VERSION)
+        raise "current_chef_server did not return its value!" if got_server[:chef_server_url] != 'https://blah.com'
+      EOM
+      file "config/client.rb", <<-EOM
+        local_mode true
+        cookbook_path "#{path_to('cookbooks')}"
+      EOM
+    end
+
+    it "the cheffish DSL is loaded lazily" do
+      command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+      expect(command.exitstatus).to eql(0)
+    end
+  end
+
+  when_the_repository "has a cookbook that uses chef-provisioning resources" do
+    before do
+      file "cookbooks/x/recipes/default.rb", <<-EOM
+        with_driver 'blah'
+      EOM
+      file "config/client.rb", <<-EOM
+        local_mode true
+        cookbook_path "#{path_to('cookbooks')}"
+      EOM
+    end
+
+    it "the cheffish DSL tries to load but fails (because chef-provisioning is not there)" do
+      command = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir)
+      expect(command.exitstatus).to eql(1)
+      expect(command.stdout).to match(/cannot load such file -- chef\/provisioning/)
+    end
+  end
+
+  when_the_repository "has a cookbook that generates deprecation warnings" do
+    before do
+      file "cookbooks/x/recipes/default.rb", <<-EOM
+        class ::MyResource < Chef::Resource
+          use_automatic_resource_name
+          property :x, default: []
+          property :y, default: {}
+        end
+
+        my_resource 'blah' do
+          1.upto(10) do
+            x nil
+          end
+          x nil
+        end
+      EOM
+    end
+
+    def match_indices(regex, str)
+      result = []
+      pos = 0
+      while match = regex.match(str, pos)
+        result << match.begin(0)
+        pos = match.end(0) + 1
+      end
+      result
+    end
+
+    it "should output each deprecation warning only once, at the end of the run" do
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+# Mimick what happens when you are on the console
+formatters << :doc
+log_level :warn
+EOM
+
+      ENV.delete("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
+
+      result = shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir)
+      expect(result.error?).to be_falsey
+
+      # Search to the end of the client run in the output
+      run_complete = result.stdout.index("Running handlers complete")
+      expect(run_complete).to be >= 0
+
+      # Make sure there is exactly one result for each, and that it occurs *after* the complete message.
+      expect(match_indices(/An attempt was made to change x from \[\] to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./, result.stdout)).to match([ be > run_complete ])
+    end
   end
 
   when_the_repository "has a cookbook with only an audit recipe" do
 
     before do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 local_mode true
 cookbook_path "#{path_to('cookbooks')}"
 audit_mode :enabled
@@ -291,7 +444,7 @@ EOM
     end
 
     it "should exit with a zero code when there is not an audit failure" do
-      file 'cookbooks/audit_test/recipes/succeed.rb', <<-RECIPE
+      file "cookbooks/audit_test/recipes/succeed.rb", <<-RECIPE
 control_group "control group without top level control" do
   it "should succeed" do
     expect(2 - 2).to eq(0)
@@ -305,7 +458,7 @@ end
     end
 
     it "should exit with a non-zero code when there is an audit failure" do
-      file 'cookbooks/audit_test/recipes/fail.rb', <<-RECIPE
+      file "cookbooks/audit_test/recipes/fail.rb", <<-RECIPE
 control_group "control group without top level control" do
   it "should fail" do
     expect(2 - 2).to eq(1)
@@ -319,7 +472,8 @@ end
     end
   end
 
-  context "when using recipe-url" do
+  # Fails on appveyor, but works locally on windows and on windows hosts in Ci.
+  context "when using recipe-url", :skip_appveyor do
     before(:all) do
       start_tiny_server
     end
@@ -331,16 +485,16 @@ end
     let(:tmp_dir) { Dir.mktmpdir("recipe-url") }
 
     it "should complete with success when passed -z and --recipe-url" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 chef_repo_path "#{tmp_dir}"
 EOM
       result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --recipe-url=http://localhost:9000/recipes.tgz -o 'x::default' -z", :cwd => tmp_dir)
       result.error!
     end
 
-    it 'should fail when passed --recipe-url and not passed -z' do
+    it "should fail when passed --recipe-url and not passed -z" do
       result = shell_out("#{chef_client} --recipe-url=http://localhost:9000/recipes.tgz", :cwd => tmp_dir)
-      expect(result.exitstatus).to eq(1)
+      expect(result.exitstatus).not_to eq(0)
     end
   end
 end
diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb
index 8be873e..68c58bb 100644
--- a/spec/integration/client/ipv6_spec.rb
+++ b/spec/integration/client/ipv6_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
 
 describe "chef-client" do
   include IntegrationSupport
   include Chef::Mixin::ShellOut
 
-  let(:chef_zero_opts) { {:host => "::1"} }
+  let(:chef_zero_opts) { { :host => "::1" } }
 
   let(:validation_pem) do
     <<-END_VALIDATION_PEM
@@ -73,10 +73,9 @@ END_CLIENT_RB
     basic_config_file
   end
 
-
   let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
 
-  let(:chef_client_cmd) { %Q[ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn] }
+  let(:chef_client_cmd) { %Q{ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
 
   after do
     FileUtils.rm_rf(cache_path)
@@ -84,13 +83,13 @@ END_CLIENT_RB
 
   # Some Solaris test platforms are too old for IPv6. These tests should not
   # otherwise be platform dependent, so exclude solaris
-  when_the_chef_server "is running on IPv6", :not_supported_on_solaris do
+  when_the_chef_server "is running on IPv6", :not_supported_on_solaris, :not_supported_on_gce do
 
     when_the_repository "has a cookbook with a no-op recipe" do
       before do
-        cookbook 'noop', '1.0.0', { }, "recipes" => {"default.rb" => "#raise 'foo'"}
-        file 'config/client.rb', client_rb_content
-        file 'config/validator.pem', validation_pem
+        cookbook "noop", "1.0.0", {}, "recipes" => { "default.rb" => "#raise 'foo'" }
+        file "config/client.rb", client_rb_content
+        file "config/validator.pem", validation_pem
       end
 
       it "should complete with success" do
@@ -103,7 +102,7 @@ END_CLIENT_RB
     when_the_repository "has a cookbook that hits server APIs" do
 
       before do
-        recipe=<<-END_RECIPE
+        recipe = <<-END_RECIPE
           actual_item = data_bag_item("expect_bag", "expect_item")
           if actual_item.key?("expect_key") and actual_item["expect_key"] == "expect_value"
             Chef::Log.info "lookin good"
@@ -115,14 +114,14 @@ END_CLIENT_RB
 
         END_RECIPE
 
-        data_bag('expect_bag', { 'expect_item' => {"expect_key" => "expect_value"} })
+        data_bag("expect_bag", { "expect_item" => { "expect_key" => "expect_value" } })
 
-        cookbook 'api-smoke-test', '1.0.0', { }, "recipes" => {"default.rb" => recipe}
+        cookbook "api-smoke-test", "1.0.0", {}, "recipes" => { "default.rb" => recipe }
       end
 
       before do
-        file 'config/client.rb', client_rb_content
-        file 'config/validator.pem', validation_pem
+        file "config/client.rb", client_rb_content
+        file "config/validator.pem", validation_pem
       end
 
       it "should complete with success" do
diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb
index c1f2c71..02508b7 100644
--- a/spec/integration/knife/chef_fs_data_store_spec.rb
+++ b/spec/integration/knife/chef_fs_data_store_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,36 +15,77 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/delete'
-require 'chef/knife/show'
-require 'chef/knife/raw'
-require 'chef/knife/cookbook_upload'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/delete"
+require "chef/knife/show"
+require "chef/knife/raw"
+require "chef/knife/cookbook_upload"
 
-describe 'ChefFSDataStore tests', :workstation do
+describe "ChefFSDataStore tests", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
   let(:cookbook_x_100_metadata_rb) { cb_metadata("x", "1.0.0") }
   let(:cookbook_z_100_metadata_rb) { cb_metadata("z", "1.0.0") }
 
-  when_the_repository "has one of each thing" do
+  describe "with repo mode 'hosted_everything' (default)" do
     before do
-      file 'clients/x.json', {}
-      file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
-      file 'data_bags/x/y.json', {}
-      file 'environments/x.json', {}
-      file 'nodes/x.json', {}
-      file 'roles/x.json', {}
-      file 'users/x.json', {}
+      Chef::Config.chef_zero.osc_compat = false
     end
 
-    context 'GET /TYPE' do
-      it 'knife list -z -R returns everything' do
-        knife('list -z -Rfp /').should_succeed <<EOM
+    when_the_repository "has one of each thing" do
+      before do
+        file "clients/x.json", {}
+        file "cookbook_artifacts/x-111/metadata.rb", cookbook_x_100_metadata_rb
+        file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+        file "data_bags/x/y.json", {}
+        file "environments/x.json", {}
+        file "nodes/x.json", {}
+        file "roles/x.json", {}
+        # file "users/x.json", {}
+        file "containers/x.json", {}
+        file "groups/x.json", {}
+        file "containers/x.json", {}
+        file "groups/x.json", {}
+        file "policies/x-111.json", {}
+        file "policy_groups/x.json", {}
+      end
+
+      context "GET /TYPE" do
+        it "knife list -z -R returns everything" do
+          knife("list -z -Rfp /").should_succeed <<EOM
+/acls/
+/acls/clients/
+/acls/clients/x.json
+/acls/containers/
+/acls/containers/x.json
+/acls/cookbook_artifacts/
+/acls/cookbook_artifacts/x.json
+/acls/cookbooks/
+/acls/cookbooks/x.json
+/acls/data_bags/
+/acls/data_bags/x.json
+/acls/environments/
+/acls/environments/x.json
+/acls/groups/
+/acls/groups/x.json
+/acls/nodes/
+/acls/nodes/x.json
+/acls/organization.json
+/acls/policies/
+/acls/policies/x.json
+/acls/policy_groups/
+/acls/policy_groups/x.json
+/acls/roles/
+/acls/roles/x.json
 /clients/
 /clients/x.json
+/containers/
+/containers/x.json
+/cookbook_artifacts/
+/cookbook_artifacts/x-111/
+/cookbook_artifacts/x-111/metadata.rb
 /cookbooks/
 /cookbooks/x/
 /cookbooks/x/metadata.rb
@@ -53,317 +94,462 @@ describe 'ChefFSDataStore tests', :workstation do
 /data_bags/x/y.json
 /environments/
 /environments/x.json
+/groups/
+/groups/x.json
+/invitations.json
+/members.json
 /nodes/
 /nodes/x.json
+/org.json
+/policies/
+/policies/x-111.json
+/policy_groups/
+/policy_groups/x.json
 /roles/
 /roles/x.json
-/users/
-/users/x.json
 EOM
+        end
       end
-    end
 
-    context 'DELETE /TYPE/NAME' do
-      it 'knife delete -z /clients/x.json works' do
-        knife('delete -z /clients/x.json').should_succeed "Deleted /clients/x.json\n"
-        knife('list -z -Rfp /clients').should_succeed ''
-      end
+      context "DELETE /TYPE/NAME" do
+        it "knife delete -z /clients/x.json works" do
+          knife("delete -z /clients/x.json").should_succeed "Deleted /clients/x.json\n"
+          knife("list -z -Rfp /clients").should_succeed ""
+        end
 
-      it 'knife delete -z -r /cookbooks/x works' do
-        knife('delete -z -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -z -Rfp /cookbooks').should_succeed ''
-      end
+        it "knife delete -z -r /cookbooks/x works" do
+          knife("delete -z -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+          knife("list -z -Rfp /cookbooks").should_succeed ""
+        end
 
-      it 'knife delete -z -r /data_bags/x works' do
-        knife('delete -z -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
-        knife('list -z -Rfp /data_bags').should_succeed ''
-      end
+        it "knife delete -z -r /data_bags/x works" do
+          knife("delete -z -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+          knife("list -z -Rfp /data_bags").should_succeed ""
+        end
 
-      it 'knife delete -z /data_bags/x/y.json works' do
-        knife('delete -z /data_bags/x/y.json').should_succeed "Deleted /data_bags/x/y.json\n"
-        knife('list -z -Rfp /data_bags').should_succeed "/data_bags/x/\n"
-      end
+        it "knife delete -z /data_bags/x/y.json works" do
+          knife("delete -z /data_bags/x/y.json").should_succeed "Deleted /data_bags/x/y.json\n"
+          knife("list -z -Rfp /data_bags").should_succeed "/data_bags/x/\n"
+        end
 
-      it 'knife delete -z /environments/x.json works' do
-        knife('delete -z /environments/x.json').should_succeed "Deleted /environments/x.json\n"
-        knife('list -z -Rfp /environments').should_succeed ''
-      end
+        it "knife delete -z /environments/x.json works" do
+          knife("delete -z /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+          knife("list -z -Rfp /environments").should_succeed ""
+        end
 
-      it 'knife delete -z /nodes/x.json works' do
-        knife('delete -z /nodes/x.json').should_succeed "Deleted /nodes/x.json\n"
-        knife('list -z -Rfp /nodes').should_succeed ''
-      end
+        it "knife delete -z /nodes/x.json works" do
+          knife("delete -z /nodes/x.json").should_succeed "Deleted /nodes/x.json\n"
+          knife("list -z -Rfp /nodes").should_succeed ""
+        end
 
-      it 'knife delete -z /roles/x.json works' do
-        knife('delete -z /roles/x.json').should_succeed "Deleted /roles/x.json\n"
-        knife('list -z -Rfp /roles').should_succeed ''
-      end
+        it "knife delete -z /roles/x.json works" do
+          knife("delete -z /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+          knife("list -z -Rfp /roles").should_succeed ""
+        end
 
-      it 'knife delete -z /users/x.json works' do
-        knife('delete -z /users/x.json').should_succeed "Deleted /users/x.json\n"
-        knife('list -z -Rfp /users').should_succeed ''
       end
-    end
 
-    context 'GET /TYPE/NAME' do
-      it 'knife show -z /clients/x.json works' do
-        knife('show -z /clients/x.json').should_succeed( /"x"/ )
-      end
+      context "GET /TYPE/NAME" do
+        it "knife show -z /clients/x.json works" do
+          knife("show -z /clients/x.json").should_succeed( /"x"/ )
+        end
 
-      it 'knife show -z /cookbooks/x/metadata.rb works' do
-        knife('show -z /cookbooks/x/metadata.rb').should_succeed "/cookbooks/x/metadata.rb:\n#{cookbook_x_100_metadata_rb}\n"
-      end
+        it "knife show -z /cookbooks/x/metadata.rb works" do
+          knife("show -z /cookbooks/x/metadata.rb").should_succeed "/cookbooks/x/metadata.rb:\n#{cookbook_x_100_metadata_rb}\n"
+        end
 
-      it 'knife show -z /data_bags/x/y.json works' do
-        knife('show -z /data_bags/x/y.json').should_succeed( /"y"/ )
-      end
+        it "knife show -z /data_bags/x/y.json works" do
+          knife("show -z /data_bags/x/y.json").should_succeed( /"y"/ )
+        end
 
-      it 'knife show -z /environments/x.json works' do
-        knife('show -z /environments/x.json').should_succeed( /"x"/ )
-      end
+        it "knife show -z /environments/x.json works" do
+          knife("show -z /environments/x.json").should_succeed( /"x"/ )
+        end
 
-      it 'knife show -z /nodes/x.json works' do
-        knife('show -z /nodes/x.json').should_succeed( /"x"/ )
-      end
+        it "knife show -z /nodes/x.json works" do
+          knife("show -z /nodes/x.json").should_succeed( /"x"/ )
+        end
 
-      it 'knife show -z /roles/x.json works' do
-        knife('show -z /roles/x.json').should_succeed( /"x"/ )
-      end
+        it "knife show -z /roles/x.json works" do
+          knife("show -z /roles/x.json").should_succeed( /"x"/ )
+        end
 
-      it 'knife show -z /users/x.json works' do
-        knife('show -z /users/x.json').should_succeed( /"x"/ )
       end
-    end
 
-    context 'PUT /TYPE/NAME' do
-      before do
-        file 'empty.json', {}
-        file 'dummynode.json', { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}}
-        file 'rolestuff.json', '{"description":"hi there","name":"x"}'
-        file 'cookbooks_to_upload/x/metadata.rb', cookbook_x_100_metadata_rb
-      end
+      context "PUT /TYPE/NAME" do
+        before do
+          file "empty.json", {}
+          file "dummynode.json", { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+          file "rolestuff.json", '{"description":"hi there","name":"x"}'
+          file "cookbooks_to_upload/x/metadata.rb", cookbook_x_100_metadata_rb
+        end
 
-      it 'knife raw -z -i empty.json -m PUT /clients/x' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_succeed( /"x"/ )
-        knife('list --local /clients').should_succeed "/clients/x.json\n"
-      end
+        it "knife raw -z -i empty.json -m PUT /clients/x" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_succeed( /"x"/ )
+          knife("list --local /clients").should_succeed "/clients/x.json\n"
+        end
 
-      it 'knife cookbook upload works' do
-        knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed :stderr => <<EOM
+        it "knife cookbook upload works" do
+          knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed :stderr => <<EOM
 Uploading x              [1.0.0]
 Uploaded 1 cookbook.
 EOM
-        knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
-      end
-
-      it 'knife raw -z -i empty.json -m PUT /data/x/y' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_succeed( /"y"/ )
-        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/y.json\n"
-      end
-
-      it 'knife raw -z -i empty.json -m PUT /environments/x' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_succeed( /"x"/ )
-        knife('list --local /environments').should_succeed "/environments/x.json\n"
-      end
-
-      it 'knife raw -z -i dummynode.json -m PUT /nodes/x' do
-        knife("raw -z -i #{path_to('dummynode.json')} -m PUT /nodes/x").should_succeed( /"x"/ )
-        knife('list --local /nodes').should_succeed "/nodes/x.json\n"
-        knife('show -z /nodes/x.json --verbose').should_succeed /"bar"/
-      end
-
-      it 'knife raw -z -i empty.json -m PUT /roles/x' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_succeed( /"x"/ )
-        knife('list --local /roles').should_succeed "/roles/x.json\n"
-      end
-
-      it 'knife raw -z -i empty.json -m PUT /users/x' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_succeed( /"x"/ )
-        knife('list --local /users').should_succeed "/users/x.json\n"
-      end
-
-      it 'After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty', :skip => (RUBY_VERSION < "1.9") do
-        knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
-        expect(IO.read(path_to('roles/x.json'))).to eq <<EOM.strip
+          knife("list --local -Rfp /cookbooks").should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
+        end
+
+        it "knife raw -z -i empty.json -m PUT /data/x/y" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_succeed( /"y"/ )
+          knife("list --local -Rfp /data_bags").should_succeed "/data_bags/x/\n/data_bags/x/y.json\n"
+        end
+
+        it "knife raw -z -i empty.json -m PUT /environments/x" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_succeed( /"x"/ )
+          knife("list --local /environments").should_succeed "/environments/x.json\n"
+        end
+
+        it "knife raw -z -i dummynode.json -m PUT /nodes/x" do
+          knife("raw -z -i #{path_to('dummynode.json')} -m PUT /nodes/x").should_succeed( /"x"/ )
+          knife("list --local /nodes").should_succeed "/nodes/x.json\n"
+          knife("show -z /nodes/x.json --verbose").should_succeed(/"bar"/)
+        end
+
+        it "knife raw -z -i empty.json -m PUT /roles/x" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+          knife("list --local /roles").should_succeed "/roles/x.json\n"
+        end
+
+        it "After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+          knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+          expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
 {
   "name": "x",
   "description": "hi there"
 }
 EOM
+        end
       end
     end
-  end
-
-  when_the_repository 'is empty' do
-    context 'POST /TYPE/NAME' do
-      before do
-        file 'empty.json', { 'name' => 'z' }
-        file 'dummynode.json', { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => {"foo" => "bar"}}
-        file 'empty_x.json', { 'name' => 'x' }
-        file 'empty_id.json', { 'id' => 'z' }
-        file 'rolestuff.json', '{"description":"hi there","name":"x"}'
-        file 'cookbooks_to_upload/z/metadata.rb', cookbook_z_100_metadata_rb
-      end
 
-      it 'knife raw -z -i empty.json -m POST /clients' do
-        knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed( /uri/ )
-        knife('list --local /clients').should_succeed "/clients/z.json\n"
-      end
-
-      it 'knife cookbook upload works' do
-        knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed :stderr => <<EOM
+    when_the_repository "is empty" do
+      context "POST /TYPE/NAME" do
+        before do
+          file "empty.json", { "name" => "z" }
+          file "dummynode.json", { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+          file "empty_x.json", { "name" => "x" }
+          file "empty_id.json", { "id" => "z" }
+          file "rolestuff.json", '{"description":"hi there","name":"x"}'
+          file "cookbooks_to_upload/z/metadata.rb", cookbook_z_100_metadata_rb
+        end
+
+        it "knife raw -z -i empty.json -m POST /clients" do
+          knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed( /uri/ )
+          knife("list --local /clients").should_succeed "/clients/z.json\n"
+        end
+
+        it "knife cookbook upload works" do
+          knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed :stderr => <<EOM
 Uploading z            [1.0.0]
 Uploaded 1 cookbook.
 EOM
-        knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
-      end
-
-      it 'knife raw -z -i empty.json -m POST /data' do
-        knife("raw -z -i #{path_to('empty.json')} -m POST /data").should_succeed( /uri/ )
-        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/z/\n"
-      end
-
-      it 'knife raw -z -i empty.json -m POST /data/x' do
-        knife("raw -z -i #{path_to('empty_x.json')} -m POST /data").should_succeed( /uri/ )
-        knife("raw -z -i #{path_to('empty_id.json')} -m POST /data/x").should_succeed( /"z"/ )
-        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/z.json\n"
-      end
-
-      it 'knife raw -z -i empty.json -m POST /environments' do
-        knife("raw -z -i #{path_to('empty.json')} -m POST /environments").should_succeed( /uri/ )
-        knife('list --local /environments').should_succeed "/environments/z.json\n"
-      end
-
-      it 'knife raw -z -i dummynode.json -m POST /nodes' do
-        knife("raw -z -i #{path_to('dummynode.json')} -m POST /nodes").should_succeed( /uri/ )
-        knife('list --local /nodes').should_succeed "/nodes/z.json\n"
-        knife('show -z /nodes/z.json').should_succeed /"bar"/
-      end
-
-      it 'knife raw -z -i empty.json -m POST /roles' do
-        knife("raw -z -i #{path_to('empty.json')} -m POST /roles").should_succeed( /uri/ )
-        knife('list --local /roles').should_succeed "/roles/z.json\n"
-      end
-
-      it 'knife raw -z -i empty.json -m POST /users' do
-        knife("raw -z -i #{path_to('empty.json')} -m POST /users").should_succeed( /uri/ )
-        knife('list --local /users').should_succeed "/users/z.json\n"
-      end
-
-      it 'After knife raw -z -i rolestuff.json -m POST /roles, the output is pretty', :skip => (RUBY_VERSION < "1.9") do
-        knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed( /uri/ )
-        expect(IO.read(path_to('roles/x.json'))).to eq <<EOM.strip
+          knife("list --local -Rfp /cookbooks").should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
+        end
+
+        it "knife raw -z -i empty.json -m POST /data" do
+          knife("raw -z -i #{path_to('empty.json')} -m POST /data").should_succeed( /uri/ )
+          knife("list --local -Rfp /data_bags").should_succeed "/data_bags/z/\n"
+        end
+
+        it "knife raw -z -i empty.json -m POST /data/x" do
+          knife("raw -z -i #{path_to('empty_x.json')} -m POST /data").should_succeed( /uri/ )
+          knife("raw -z -i #{path_to('empty_id.json')} -m POST /data/x").should_succeed( /"z"/ )
+          knife("list --local -Rfp /data_bags").should_succeed "/data_bags/x/\n/data_bags/x/z.json\n"
+        end
+
+        it "knife raw -z -i empty.json -m POST /environments" do
+          knife("raw -z -i #{path_to('empty.json')} -m POST /environments").should_succeed( /uri/ )
+          knife("list --local /environments").should_succeed "/environments/z.json\n"
+        end
+
+        it "knife raw -z -i dummynode.json -m POST /nodes" do
+          knife("raw -z -i #{path_to('dummynode.json')} -m POST /nodes").should_succeed( /uri/ )
+          knife("list --local /nodes").should_succeed "/nodes/z.json\n"
+          knife("show -z /nodes/z.json").should_succeed(/"bar"/)
+        end
+
+        it "knife raw -z -i empty.json -m POST /roles" do
+          knife("raw -z -i #{path_to('empty.json')} -m POST /roles").should_succeed( /uri/ )
+          knife("list --local /roles").should_succeed "/roles/z.json\n"
+        end
+
+        it "After knife raw -z -i rolestuff.json -m POST /roles, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+          knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed( /uri/ )
+          expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
 {
   "name": "x",
   "description": "hi there"
 }
 EOM
-      end
-    end
-
-    it 'knife list -z -R returns nothing' do
-      knife('list -z -Rfp /').should_succeed <<EOM
+        end
+      end
+
+      it "knife list -z -R returns nothing" do
+        knife("list -z -Rfp /").should_succeed <<EOM
+/acls/
+/acls/clients/
+/acls/containers/
+/acls/cookbook_artifacts/
+/acls/cookbooks/
+/acls/data_bags/
+/acls/environments/
+/acls/groups/
+/acls/nodes/
+/acls/organization.json
+/acls/policies/
+/acls/policy_groups/
+/acls/roles/
 /clients/
+/containers/
+/cookbook_artifacts/
 /cookbooks/
 /data_bags/
 /environments/
+/groups/
+/invitations.json
+/members.json
 /nodes/
+/org.json
+/policies/
+/policy_groups/
 /roles/
-/users/
 EOM
-    end
-
-    context 'DELETE /TYPE/NAME' do
-      it 'knife delete -z /clients/x.json fails with an error' do
-        knife('delete -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
       end
 
-      it 'knife delete -z -r /cookbooks/x fails with an error' do
-        knife('delete -z -r /cookbooks/x').should_fail "ERROR: /cookbooks/x: No such file or directory\n"
-      end
+      context "DELETE /TYPE/NAME" do
+        it "knife delete -z /clients/x.json fails with an error" do
+          knife("delete -z /clients/x.json").should_fail "ERROR: /clients/x.json: No such file or directory\n"
+        end
 
-      it 'knife delete -z -r /data_bags/x fails with an error' do
-        knife('delete -z -r /data_bags/x').should_fail "ERROR: /data_bags/x: No such file or directory\n"
-      end
+        it "knife delete -z -r /cookbooks/x fails with an error" do
+          knife("delete -z -r /cookbooks/x").should_fail "ERROR: /cookbooks/x: No such file or directory\n"
+        end
 
-      it 'knife delete -z /data_bags/x/y.json fails with an error' do
-        knife('delete -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
-      end
+        it "knife delete -z -r /data_bags/x fails with an error" do
+          knife("delete -z -r /data_bags/x").should_fail "ERROR: /data_bags/x: No such file or directory\n"
+        end
 
-      it 'knife delete -z /environments/x.json fails with an error' do
-        knife('delete -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
-      end
+        it "knife delete -z /data_bags/x/y.json fails with an error" do
+          knife("delete -z /data_bags/x/y.json").should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
+        end
 
-      it 'knife delete -z /nodes/x.json fails with an error' do
-        knife('delete -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
-      end
+        it "knife delete -z /environments/x.json fails with an error" do
+          knife("delete -z /environments/x.json").should_fail "ERROR: /environments/x.json: No such file or directory\n"
+        end
 
-      it 'knife delete -z /roles/x.json fails with an error' do
-        knife('delete -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
-      end
+        it "knife delete -z /nodes/x.json fails with an error" do
+          knife("delete -z /nodes/x.json").should_fail "ERROR: /nodes/x.json: No such file or directory\n"
+        end
 
-      it 'knife delete -z /users/x.json fails with an error' do
-        knife('delete -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
-      end
-    end
+        it "knife delete -z /roles/x.json fails with an error" do
+          knife("delete -z /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
+        end
 
-    context 'GET /TYPE/NAME' do
-      it 'knife show -z /clients/x.json fails with an error' do
-        knife('show -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
       end
 
-      it 'knife show -z /cookbooks/x/metadata.rb fails with an error' do
-        knife('show -z /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb: No such file or directory\n"
-      end
+      context "GET /TYPE/NAME" do
+        it "knife show -z /clients/x.json fails with an error" do
+          knife("show -z /clients/x.json").should_fail "ERROR: /clients/x.json: No such file or directory\n"
+        end
 
-      it 'knife show -z /data_bags/x/y.json fails with an error' do
-        knife('show -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
-      end
+        it "knife show -z /cookbooks/x/metadata.rb fails with an error" do
+          knife("show -z /cookbooks/x/metadata.rb").should_fail "ERROR: /cookbooks/x/metadata.rb: No such file or directory\n"
+        end
 
-      it 'knife show -z /environments/x.json fails with an error' do
-        knife('show -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
-      end
+        it "knife show -z /data_bags/x/y.json fails with an error" do
+          knife("show -z /data_bags/x/y.json").should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
+        end
 
-      it 'knife show -z /nodes/x.json fails with an error' do
-        knife('show -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
-      end
+        it "knife show -z /environments/x.json fails with an error" do
+          knife("show -z /environments/x.json").should_fail "ERROR: /environments/x.json: No such file or directory\n"
+        end
+
+        it "knife show -z /nodes/x.json fails with an error" do
+          knife("show -z /nodes/x.json").should_fail "ERROR: /nodes/x.json: No such file or directory\n"
+        end
+
+        it "knife show -z /roles/x.json fails with an error" do
+          knife("show -z /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
+        end
 
-      it 'knife show -z /roles/x.json fails with an error' do
-        knife('show -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
       end
 
-      it 'knife show -z /users/x.json fails with an error' do
-        knife('show -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
+      context "PUT /TYPE/NAME" do
+        before do
+          file "empty.json", {}
+        end
+
+        it "knife raw -z -i empty.json -m PUT /clients/x fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_fail( /404/ )
+        end
+
+        it "knife raw -z -i empty.json -m PUT /data/x/y fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_fail( /404/ )
+        end
+
+        it "knife raw -z -i empty.json -m PUT /environments/x fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_fail( /404/ )
+        end
+
+        it "knife raw -z -i empty.json -m PUT /nodes/x fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_fail( /404/ )
+        end
+
+        it "knife raw -z -i empty.json -m PUT /roles/x fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_fail( /404/ )
+        end
+
       end
     end
+  end
 
-    context 'PUT /TYPE/NAME' do
+  # We have to configure Zero for Chef 11 mode in order to test users because:
+  # 1. local mode overrides your `chef_server_url` to something like "http://localhost:PORT"
+  # 2. single org mode maps requests like "https://localhost:PORT/users" so
+  #   they're functionally equivalent to "https://localhost:PORT/organizations/DEFAULT/users"
+  # 3. Users are global objects in Chef 12, and should be accessed at URLs like
+  #   "https://localhost:PORT/users" (there is an org-specific users endpoint,
+  #   but it's for listing users in an org, not for managing users).
+  # 4. Therefore you can't hit the _real_ users endpoint in local mode when
+  #   configured for Chef Server 12 mode.
+  #
+  # Because of this, we have to configure Zero for Chef 11 OSC mode in order to
+  # test the users part of the data store with local mode.
+  describe "with repo mode 'everything'" do
+    before do
+      Chef::Config.repo_mode = "everything"
+      Chef::Config.chef_zero.osc_compat = true
+    end
+
+    when_the_repository "has one of each thing" do
       before do
-        file 'empty.json', {}
+        file "clients/x.json", {}
+        file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+        file "data_bags/x/y.json", {}
+        file "environments/x.json", {}
+        file "nodes/x.json", {}
+        file "roles/x.json", {}
+        file "users/x.json", {}
+      end
+
+      context "GET /TYPE" do
+        it "knife list -z -R returns everything" do
+          knife("list -z -Rfp /").should_succeed <<EOM
+/clients/
+/clients/x.json
+/cookbooks/
+/cookbooks/x/
+/cookbooks/x/metadata.rb
+/data_bags/
+/data_bags/x/
+/data_bags/x/y.json
+/environments/
+/environments/x.json
+/nodes/
+/nodes/x.json
+/roles/
+/roles/x.json
+/users/
+/users/x.json
+EOM
+        end
       end
 
-      it 'knife raw -z -i empty.json -m PUT /clients/x fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_fail( /404/ )
+      context "DELETE /TYPE/NAME" do
+        it "knife delete -z /users/x.json works" do
+          knife("delete -z /users/x.json").should_succeed "Deleted /users/x.json\n"
+          knife("list -z -Rfp /users").should_succeed ""
+        end
       end
 
-      it 'knife raw -z -i empty.json -m PUT /data/x/y fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_fail( /404/ )
+      context "GET /TYPE/NAME" do
+        it "knife show -z /users/x.json works" do
+          knife("show -z /users/x.json").should_succeed( /"x"/ )
+        end
+      end
+
+      context "PUT /TYPE/NAME" do
+        before do
+          file "empty.json", {}
+          file "dummynode.json", { "name" => "x", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+          file "rolestuff.json", '{"description":"hi there","name":"x"}'
+          file "cookbooks_to_upload/x/metadata.rb", cookbook_x_100_metadata_rb
+        end
+
+        it "knife raw -z -i empty.json -m PUT /users/x" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_succeed( /"x"/ )
+          knife("list --local /users").should_succeed "/users/x.json\n"
+        end
+
+        it "After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty", :skip => (RUBY_VERSION < "1.9") do
+          knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ )
+          expect(IO.read(path_to("roles/x.json"))).to eq <<EOM.strip
+{
+  "name": "x",
+  "description": "hi there"
+}
+EOM
+        end
       end
+    end
 
-      it 'knife raw -z -i empty.json -m PUT /environments/x fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_fail( /404/ )
+    when_the_repository "is empty" do
+      context "POST /TYPE/NAME" do
+        before do
+          file "empty.json", { "name" => "z" }
+          file "dummynode.json", { "name" => "z", "chef_environment" => "rspec" , "json_class" => "Chef::Node", "normal" => { "foo" => "bar" } }
+          file "empty_x.json", { "name" => "x" }
+          file "empty_id.json", { "id" => "z" }
+          file "rolestuff.json", '{"description":"hi there","name":"x"}'
+          file "cookbooks_to_upload/z/metadata.rb", cookbook_z_100_metadata_rb
+        end
+
+        it "knife raw -z -i empty.json -m POST /users" do
+          knife("raw -z -i #{path_to('empty.json')} -m POST /users").should_succeed( /uri/ )
+          knife("list --local /users").should_succeed "/users/z.json\n"
+        end
+      end
+
+      it "knife list -z -R returns nothing" do
+        knife("list -z -Rfp /").should_succeed <<EOM
+/clients/
+/cookbooks/
+/data_bags/
+/environments/
+/nodes/
+/roles/
+/users/
+EOM
       end
 
-      it 'knife raw -z -i empty.json -m PUT /nodes/x fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_fail( /404/ )
+      context "DELETE /TYPE/NAME" do
+        it "knife delete -z /users/x.json fails with an error" do
+          knife("delete -z /users/x.json").should_fail "ERROR: /users/x.json: No such file or directory\n"
+        end
       end
 
-      it 'knife raw -z -i empty.json -m PUT /roles/x fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_fail( /404/ )
+      context "GET /TYPE/NAME" do
+        it "knife show -z /users/x.json fails with an error" do
+          knife("show -z /users/x.json").should_fail "ERROR: /users/x.json: No such file or directory\n"
+        end
       end
 
-      it 'knife raw -z -i empty.json -m PUT /users/x fails with 404' do
-        knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_fail( /404/ )
+      context "PUT /TYPE/NAME" do
+        before do
+          file "empty.json", {}
+        end
+
+        it "knife raw -z -i empty.json -m PUT /users/x fails with 404" do
+          knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_fail( /404/ )
+        end
       end
     end
   end
diff --git a/spec/integration/knife/chef_repo_path_spec.rb b/spec/integration/knife/chef_repo_path_spec.rb
index 874b339..cf12b7d 100644
--- a/spec/integration/knife/chef_repo_path_spec.rb
+++ b/spec/integration/knife/chef_repo_path_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,47 +15,49 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
+require "chef/knife/show"
 
-describe 'chef_repo_path tests', :workstation do
+describe "chef_repo_path tests", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
+  let(:error_rel_path_outside_repo) { /^ERROR: Attempt to use relative path '' when current directory is outside the repository path/ }
+
   # TODO alternate repo_path / *_path
-  context 'alternate *_path' do
-    when_the_repository 'has clients and clients2, cookbooks and cookbooks2, etc.' do
+  context "alternate *_path" do
+    when_the_repository "has clients and clients2, cookbooks and cookbooks2, etc." do
       before do
-        file 'clients/client1.json', {}
-        file 'cookbooks/cookbook1/metadata.rb', ''
-        file 'data_bags/bag/item.json', {}
-        file 'environments/env1.json', {}
-        file 'nodes/node1.json', {}
-        file 'roles/role1.json', {}
-        file 'users/user1.json', {}
-
-        file 'clients2/client2.json', {}
-        file 'cookbooks2/cookbook2/metadata.rb', ''
-        file 'data_bags2/bag2/item2.json', {}
-        file 'environments2/env2.json', {}
-        file 'nodes2/node2.json', {}
-        file 'roles2/role2.json', {}
-        file 'users2/user2.json', {}
-
-        directory 'chef_repo2' do
-          file 'clients/client3.json', {}
-          file 'cookbooks/cookbook3/metadata.rb', ''
-          file 'data_bags/bag3/item3.json', {}
-          file 'environments/env3.json', {}
-          file 'nodes/node3.json', {}
-          file 'roles/role3.json', {}
-          file 'users/user3.json', {}
+        file "clients/client1.json", {}
+        file "cookbooks/cookbook1/metadata.rb", ""
+        file "data_bags/bag/item.json", {}
+        file "environments/env1.json", {}
+        file "nodes/node1.json", {}
+        file "roles/role1.json", {}
+        file "users/user1.json", {}
+
+        file "clients2/client2.json", {}
+        file "cookbooks2/cookbook2/metadata.rb", ""
+        file "data_bags2/bag2/item2.json", {}
+        file "environments2/env2.json", {}
+        file "nodes2/node2.json", {}
+        file "roles2/role2.json", {}
+        file "users2/user2.json", {}
+
+        directory "chef_repo2" do
+          file "clients/client3.json", {}
+          file "cookbooks/cookbook3/metadata.rb", ""
+          file "data_bags/bag3/item3.json", {}
+          file "environments/env3.json", {}
+          file "nodes/node3.json", {}
+          file "roles/role3.json", {}
+          file "users/user3.json", {}
         end
       end
 
-      it 'knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff' do
+      it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
         Chef::Config.delete(:chef_repo_path)
         knife("list --local -Rfp --chef-repo-path #{path_to('chef_repo2')} /").should_succeed <<EOM
 /clients/
@@ -77,15 +79,15 @@ describe 'chef_repo_path tests', :workstation do
 EOM
       end
 
-      context 'when all _paths are set to alternates' do
+      context "when all _paths are set to alternates" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
           end
-          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
         end
 
-        it 'knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff' do
+        it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
           knife("list --local -Rfp --chef-repo-path #{path_to('chef_repo2')} /").should_succeed <<EOM
 /clients/
 /clients/client3.json
@@ -106,24 +108,24 @@ EOM
 EOM
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client2.json
 cookbooks/
@@ -144,31 +146,31 @@ EOM
           end
         end
 
-        context 'when cwd is inside data_bags2' do
-          before { cwd 'data_bags2' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside data_bags2" do
+          before { cwd "data_bags2" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag2/
 bag2/item2.json
 EOM
           end
-          it 'knife list --local -Rfp ../roles lists roles' do
-            knife('list --local -Rfp ../roles').should_succeed "/roles/role2.json\n"
+          it "knife list --local -Rfp ../roles lists roles" do
+            knife("list --local -Rfp ../roles").should_succeed "/roles/role2.json\n"
           end
         end
       end
 
-      context 'when all _paths except chef_repo_path are set to alternates' do
+      context "when all _paths except chef_repo_path are set to alternates" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
           end
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client2.json
 cookbooks/
@@ -189,24 +191,24 @@ EOM
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside data_bags2' do
-          before { cwd 'data_bags2' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside data_bags2" do
+          before { cwd "data_bags2" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag2/
 bag2/item2.json
 EOM
@@ -214,32 +216,32 @@ EOM
         end
       end
 
-      context 'when only chef_repo_path is set to its alternate' do
+      context "when only chef_repo_path is set to its alternate" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
-          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client3.json
 cookbooks/
@@ -260,10 +262,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2/data_bags' do
-          before { cwd 'chef_repo2/data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2/data_bags" do
+          before { cwd "chef_repo2/data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag3/
 bag3/item3.json
 EOM
@@ -271,24 +273,24 @@ EOM
         end
       end
 
-      context 'when paths are set to point to both versions of each' do
+      context "when paths are set to point to both versions of each" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config["#{object_name}_path".to_sym] = [
               File.join(Chef::Config.chef_repo_path, "#{object_name}s"),
-              File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
+              File.join(Chef::Config.chef_repo_path, "#{object_name}s2"),
             ]
           end
-          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
         end
 
-        context 'when there is a directory in clients1 and file in clients2 with the same name' do
+        context "when there is a directory in clients1 and file in clients2 with the same name" do
           before do
-            directory 'clients/blah.json'
-            file 'clients2/blah.json', {}
+            directory "clients/blah.json"
+            file "clients2/blah.json", {}
           end
-          it 'knife show /clients/blah.json succeeds' do
-            knife('show --local /clients/blah.json').should_succeed <<EOM
+          it "knife show /clients/blah.json succeeds" do
+            knife("show --local /clients/blah.json").should_succeed <<EOM
 /clients/blah.json:
 {
 
@@ -297,13 +299,13 @@ EOM
           end
         end
 
-        context 'when there is a file in cookbooks1 and directory in cookbooks2 with the same name' do
+        context "when there is a file in cookbooks1 and directory in cookbooks2 with the same name" do
           before do
-            file 'cookbooks/blah', ''
-            file 'cookbooks2/blah/metadata.rb', ''
+            file "cookbooks/blah", ""
+            file "cookbooks2/blah/metadata.rb", ""
           end
-          it 'knife list -Rfp cookbooks shows files in blah' do
-            knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+          it "knife list -Rfp cookbooks shows files in blah" do
+            knife("list --local -Rfp /cookbooks").should_succeed <<EOM
 /cookbooks/blah/
 /cookbooks/blah/metadata.rb
 /cookbooks/cookbook1/
@@ -314,13 +316,13 @@ EOM
           end
         end
 
-        context 'when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name' do
+        context "when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name" do
           before do
-            directory 'cookbooks/blah'
-            file 'cookbooks2/blah/metadata.rb', ''
+            directory "cookbooks/blah"
+            file "cookbooks2/blah/metadata.rb", ""
           end
-          it 'knife list -Rfp cookbooks shows files in blah' do
-            knife('list --local -Rfp /cookbooks').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n")
+          it "knife list -Rfp cookbooks shows files in blah" do
+            knife("list --local -Rfp /cookbooks").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n")
 /cookbooks/blah/
 /cookbooks/blah/metadata.rb
 /cookbooks/cookbook1/
@@ -331,13 +333,13 @@ EOM
           end
         end
 
-        context 'when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name' do
+        context "when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name" do
           before do
-            file 'cookbooks/blah/metadata.json', {}
-            file 'cookbooks2/blah/metadata.rb', ''
+            file "cookbooks/blah/metadata.json", {}
+            file "cookbooks2/blah/metadata.rb", ""
           end
-          it 'knife list -Rfp cookbooks shows files in the first cookbook and not the second' do
-            knife('list --local -Rfp /cookbooks').should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n")
+          it "knife list -Rfp cookbooks shows files in the first cookbook and not the second" do
+            knife("list --local -Rfp /cookbooks").should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n")
 /cookbooks/blah/
 /cookbooks/blah/metadata.json
 /cookbooks/cookbook1/
@@ -348,13 +350,13 @@ EOM
           end
         end
 
-        context 'when there is a file in data_bags1 and a directory in data_bags2 with the same name' do
+        context "when there is a file in data_bags1 and a directory in data_bags2 with the same name" do
           before do
-            file 'data_bags/blah', ''
-            file 'data_bags2/blah/item.json', ''
+            file "data_bags/blah", ""
+            file "data_bags2/blah/item.json", ""
           end
-          it 'knife list -Rfp data_bags shows files in blah' do
-            knife('list --local -Rfp /data_bags').should_succeed <<EOM
+          it "knife list -Rfp data_bags shows files in blah" do
+            knife("list --local -Rfp /data_bags").should_succeed <<EOM
 /data_bags/bag/
 /data_bags/bag/item.json
 /data_bags/bag2/
@@ -365,13 +367,13 @@ EOM
           end
         end
 
-        context 'when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name' do
+        context "when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name" do
           before do
-            file 'data_bags/blah/item1.json', ''
-            file 'data_bags2/blah/item2.json', ''
+            file "data_bags/blah/item1.json", ""
+            file "data_bags2/blah/item2.json", ""
           end
-          it 'knife list -Rfp data_bags shows only items in data_bags1' do
-            knife('list --local -Rfp /data_bags').should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n")
+          it "knife list -Rfp data_bags shows only items in data_bags1" do
+            knife("list --local -Rfp /data_bags").should_succeed(<<EOM, :stderr => "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n")
 /data_bags/bag/
 /data_bags/bag/item.json
 /data_bags/bag2/
@@ -382,13 +384,13 @@ EOM
           end
         end
 
-        context 'when there is a directory in environments1 and file in environments2 with the same name' do
+        context "when there is a directory in environments1 and file in environments2 with the same name" do
           before do
-            directory 'environments/blah.json'
-            file 'environments2/blah.json', {}
+            directory "environments/blah.json"
+            file "environments2/blah.json", {}
           end
-          it 'knife show /environments/blah.json succeeds' do
-            knife('show --local /environments/blah.json').should_succeed <<EOM
+          it "knife show /environments/blah.json succeeds" do
+            knife("show --local /environments/blah.json").should_succeed <<EOM
 /environments/blah.json:
 {
 
@@ -397,13 +399,13 @@ EOM
           end
         end
 
-        context 'when there is a directory in nodes1 and file in nodes2 with the same name' do
+        context "when there is a directory in nodes1 and file in nodes2 with the same name" do
           before do
-            directory 'nodes/blah.json'
-            file 'nodes2/blah.json', {}
+            directory "nodes/blah.json"
+            file "nodes2/blah.json", {}
           end
-          it 'knife show /nodes/blah.json succeeds' do
-            knife('show --local /nodes/blah.json').should_succeed <<EOM
+          it "knife show /nodes/blah.json succeeds" do
+            knife("show --local /nodes/blah.json").should_succeed <<EOM
 /nodes/blah.json:
 {
 
@@ -412,13 +414,13 @@ EOM
           end
         end
 
-        context 'when there is a directory in roles1 and file in roles2 with the same name' do
+        context "when there is a directory in roles1 and file in roles2 with the same name" do
           before do
-            directory 'roles/blah.json'
-            file 'roles2/blah.json', {}
+            directory "roles/blah.json"
+            file "roles2/blah.json", {}
           end
-          it 'knife show /roles/blah.json succeeds' do
-            knife('show --local /roles/blah.json').should_succeed <<EOM
+          it "knife show /roles/blah.json succeeds" do
+            knife("show --local /roles/blah.json").should_succeed <<EOM
 /roles/blah.json:
 {
 
@@ -427,13 +429,13 @@ EOM
           end
         end
 
-        context 'when there is a directory in users1 and file in users2 with the same name' do
+        context "when there is a directory in users1 and file in users2 with the same name" do
           before do
-            directory 'users/blah.json'
-            file 'users2/blah.json', {}
+            directory "users/blah.json"
+            file "users2/blah.json", {}
           end
-          it 'knife show /users/blah.json succeeds' do
-            knife('show --local /users/blah.json').should_succeed <<EOM
+          it "knife show /users/blah.json succeeds" do
+            knife("show --local /users/blah.json").should_succeed <<EOM
 /users/blah.json:
 {
 
@@ -442,17 +444,17 @@ EOM
           end
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag2/
@@ -461,10 +463,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client1.json
 clients/client2.json
@@ -494,10 +496,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside data_bags2' do
-          before { cwd 'data_bags2' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside data_bags2" do
+          before { cwd "data_bags2" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag2/
@@ -507,21 +509,21 @@ EOM
         end
       end
 
-      context 'when when chef_repo_path is set to both places and no other _path is set' do
+      context "when when chef_repo_path is set to both places and no other _path is set" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
           Chef::Config.chef_repo_path = [
             Chef::Config.chef_repo_path,
-            File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+            File.join(Chef::Config.chef_repo_path, "chef_repo2"),
           ]
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client1.json
 clients/client3.json
@@ -551,10 +553,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag3/
@@ -563,10 +565,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client1.json
 clients/client3.json
@@ -596,10 +598,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2/data_bags' do
-          before { cwd 'chef_repo2/data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2/data_bags" do
+          before { cwd "chef_repo2/data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag3/
@@ -609,33 +611,33 @@ EOM
         end
       end
 
-      context 'when cookbook_path is set and nothing else' do
+      context "when cookbook_path is set and nothing else" do
         before :each do
-          %w(client data_bag environment node role user).each do |object_name|
+          %w{client data_bag environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
           Chef::Config.delete(:chef_repo_path)
-          Chef::Config.cookbook_path = File.join(@repository_dir, 'chef_repo2', 'cookbooks')
+          Chef::Config.cookbook_path = File.join(@repository_dir, "chef_repo2", "cookbooks")
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client3.json
 cookbooks/
@@ -656,10 +658,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2/data_bags' do
-          before { cwd 'chef_repo2/data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2/data_bags" do
+          before { cwd "chef_repo2/data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag3/
 bag3/item3.json
 EOM
@@ -667,22 +669,22 @@ EOM
         end
       end
 
-      context 'when cookbook_path is set to multiple places and nothing else is set' do
+      context "when cookbook_path is set to multiple places and nothing else is set" do
         before :each do
-          %w(client data_bag environment node role user).each do |object_name|
+          %w{client data_bag environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
           Chef::Config.delete(:chef_repo_path)
           Chef::Config.cookbook_path = [
-            File.join(@repository_dir, 'cookbooks'),
-            File.join(@repository_dir, 'chef_repo2', 'cookbooks')
+            File.join(@repository_dir, "cookbooks"),
+            File.join(@repository_dir, "chef_repo2", "cookbooks"),
           ]
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client1.json
 clients/client3.json
@@ -712,10 +714,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag3/
@@ -724,10 +726,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client1.json
 clients/client3.json
@@ -757,10 +759,10 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2/data_bags' do
-          before { cwd 'chef_repo2/data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2/data_bags" do
+          before { cwd "chef_repo2/data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 bag3/
@@ -770,36 +772,36 @@ EOM
         end
       end
 
-      context 'when data_bag_path and chef_repo_path are set, and nothing else' do
+      context "when data_bag_path and chef_repo_path are set, and nothing else" do
         before :each do
-          %w(client cookbook  environment node role user).each do |object_name|
+          %w{client cookbook  environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
-          Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, 'data_bags')
-          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'chef_repo2')
+          Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, "data_bags")
+          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
         end
 
-        context 'when cwd is at the top level' do
-          before { cwd '.' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is at the top level" do
+          before { cwd "." }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2' do
-          before { cwd 'chef_repo2' }
-          it 'knife list --local -Rfp lists everything' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside chef_repo2" do
+          before { cwd "chef_repo2" }
+          it "knife list --local -Rfp lists everything" do
+            knife("list --local -Rfp").should_succeed <<EOM
 clients/
 clients/client3.json
 cookbooks/
@@ -820,44 +822,44 @@ EOM
           end
         end
 
-        context 'when cwd is inside chef_repo2/data_bags' do
-          before { cwd 'chef_repo2/data_bags' }
-          it 'knife list --local -Rfp fails' do
-            knife('list --local -Rfp').should_fail("ERROR: Attempt to use relative path '' when current directory is outside the repository path\n")
+        context "when cwd is inside chef_repo2/data_bags" do
+          before { cwd "chef_repo2/data_bags" }
+          it "knife list --local -Rfp fails" do
+            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
           end
         end
       end
 
-      context 'when data_bag_path is set and nothing else' do
+      context "when data_bag_path is set and nothing else" do
         include_context "default config options"
 
         before :each do
-          %w(client cookbook  environment node role user).each do |object_name|
+          %w{client cookbook  environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
           Chef::Config.delete(:chef_repo_path)
-          Chef::Config.data_bag_path = File.join(@repository_dir, 'data_bags')
+          Chef::Config.data_bag_path = File.join(@repository_dir, "data_bags")
         end
 
-        it 'knife list --local -Rfp / lists data bags' do
-          knife('list --local -Rfp /').should_succeed <<EOM
+        it "knife list --local -Rfp / lists data bags" do
+          knife("list --local -Rfp /").should_succeed <<EOM
 /data_bags/
 /data_bags/bag/
 /data_bags/bag/item.json
 EOM
         end
 
-        it 'knife list --local -Rfp /data_bags lists data bags' do
-          knife('list --local -Rfp /data_bags').should_succeed <<EOM
+        it "knife list --local -Rfp /data_bags lists data bags" do
+          knife("list --local -Rfp /data_bags").should_succeed <<EOM
 /data_bags/bag/
 /data_bags/bag/item.json
 EOM
         end
 
-        context 'when cwd is inside the data_bags directory' do
-          before { cwd 'data_bags' }
-          it 'knife list --local -Rfp lists data bags' do
-            knife('list --local -Rfp').should_succeed <<EOM
+        context "when cwd is inside the data_bags directory" do
+          before { cwd "data_bags" }
+          it "knife list --local -Rfp lists data bags" do
+            knife("list --local -Rfp").should_succeed <<EOM
 bag/
 bag/item.json
 EOM
@@ -866,21 +868,21 @@ EOM
       end
     end
 
-    when_the_repository 'is empty' do
-      context 'when the repository _paths point to places that do not exist' do
+    when_the_repository "is empty" do
+      context "when the repository _paths point to places that do not exist" do
         before :each do
-          %w(client cookbook data_bag environment node role user).each do |object_name|
-            Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, 'nowhere', object_name)
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
+            Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "nowhere", object_name)
           end
-          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, 'nowhere')
+          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "nowhere")
         end
 
-        it 'knife list --local -Rfp / fails' do
-          knife('list --local -Rfp /').should_succeed ''
+        it "knife list --local -Rfp / fails" do
+          knife("list --local -Rfp /").should_succeed ""
         end
 
-        it 'knife list --local -Rfp /data_bags fails' do
-          knife('list --local -Rfp /data_bags').should_fail("ERROR: /data_bags: No such file or directory\n")
+        it "knife list --local -Rfp /data_bags fails" do
+          knife("list --local -Rfp /data_bags").should_fail("ERROR: /data_bags: No such file or directory\n")
         end
       end
     end
diff --git a/spec/integration/knife/chef_repository_file_system_spec.rb b/spec/integration/knife/chef_repository_file_system_spec.rb
index 34afd22..e431c7f 100644
--- a/spec/integration/knife/chef_repository_file_system_spec.rb
+++ b/spec/integration/knife/chef_repository_file_system_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/show"
 
-describe 'General chef_repo file system checks', :workstation do
+describe "General chef_repo file system checks", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
-  context 'directories and files that should/should not be ignored' do
+  context "directories and files that should/should not be ignored" do
     when_the_repository "has empty roles, environments and data bag item directories" do
       before do
         directory "roles"
@@ -32,7 +32,7 @@ describe 'General chef_repo file system checks', :workstation do
       end
 
       it "knife list --local -Rfp / returns them" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /data_bags/
 /data_bags/bag1/
 /environments/
@@ -45,25 +45,25 @@ EOM
       before { directory "data_bags" }
 
       it "knife list --local / returns it" do
-        knife('list --local /').should_succeed "/data_bags\n"
+        knife("list --local /").should_succeed "/data_bags\n"
       end
     end
 
     when_the_repository "has an empty cookbook directory" do
-      before { directory 'cookbooks/cookbook1' }
+      before { directory "cookbooks/cookbook1" }
 
       it "knife list --local -Rfp / does not return it" do
-        knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+        knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
 /cookbooks/
 EOM
       end
     end
 
     when_the_repository "has only empty cookbook subdirectories" do
-      before { directory 'cookbooks/cookbook1/recipes' }
+      before { directory "cookbooks/cookbook1/recipes" }
 
       it "knife list --local -Rfp / does not return it" do
-        knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+        knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
 /cookbooks/
 EOM
       end
@@ -71,12 +71,12 @@ EOM
 
     when_the_repository "has empty and non-empty cookbook subdirectories" do
       before do
-        directory 'cookbooks/cookbook1/recipes'
-        file 'cookbooks/cookbook1/templates/default/x.txt', ''
+        directory "cookbooks/cookbook1/recipes"
+        file "cookbooks/cookbook1/templates/default/x.txt", ""
       end
 
       it "knife list --local -Rfp / does not return the empty ones" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/templates/
@@ -87,10 +87,10 @@ EOM
     end
 
     when_the_repository "has only empty cookbook sub-sub-directories" do
-      before { directory 'cookbooks/cookbook1/templates/default' }
+      before { directory "cookbooks/cookbook1/templates/default" }
 
       it "knife list --local -Rfp / does not return it" do
-        knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+        knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
 /cookbooks/
 EOM
       end
@@ -98,13 +98,13 @@ EOM
 
     when_the_repository "has empty cookbook sub-sub-directories alongside non-empty ones" do
       before do
-        file 'cookbooks/cookbook1/templates/default/x.txt', ''
-        directory 'cookbooks/cookbook1/templates/rhel'
-        directory 'cookbooks/cookbook1/files/default'
+        file "cookbooks/cookbook1/templates/default/x.txt", ""
+        directory "cookbooks/cookbook1/templates/rhel"
+        directory "cookbooks/cookbook1/files/default"
       end
 
       it "knife list --local -Rfp / does not return the empty ones" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/templates/
@@ -122,7 +122,7 @@ EOM
       end
 
       it "knife list --local -Rfp / should NOT return it" do
-        knife('list --local -Rfp /').should_succeed ""
+        knife("list --local -Rfp /").should_succeed ""
       end
     end
 
@@ -146,7 +146,7 @@ EOM
       end
 
       it "knife list --local -Rfp / should NOT return them" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /data_bags/
 /data_bags/bag1/
 /data_bags/bag1/item1.json
@@ -160,62 +160,62 @@ EOM
 
     when_the_repository "has extraneous subdirectories and files under a cookbook" do
       before do
-        directory 'cookbooks/cookbook1' do
-          file 'a.rb', ''
-          file 'blarghle/blah.rb', ''
-          directory 'attributes' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+        directory "cookbooks/cookbook1" do
+          file "a.rb", ""
+          file "blarghle/blah.rb", ""
+          directory "attributes" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'definitions' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "definitions" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'recipes' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "recipes" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'libraries' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "libraries" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'templates' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "templates" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'files' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "files" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'resources' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "resources" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
-          directory 'providers' do
-            file 'a.rb', ''
-            file 'b.json', {}
-            file 'c/d.rb', ''
-            file 'c/e.json', {}
+          directory "providers" do
+            file "a.rb", ""
+            file "b.json", {}
+            file "c/d.rb", ""
+            file "c/e.json", {}
           end
         end
       end
 
       it "knife list --local -Rfp / should NOT return them" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/a.rb
@@ -252,41 +252,41 @@ EOM
     end
 
     when_the_repository "has a file in cookbooks/" do
-      before { file 'cookbooks/file', '' }
-      it 'does not show up in list -Rfp' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      before { file "cookbooks/file", "" }
+      it "does not show up in list -Rfp" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 EOM
       end
     end
 
     when_the_repository "has a file in data_bags/" do
-      before { file 'data_bags/file', '' }
-      it 'does not show up in list -Rfp' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      before { file "data_bags/file", "" }
+      it "does not show up in list -Rfp" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /data_bags/
 EOM
       end
     end
   end
 
-  when_the_repository 'has a cookbook starting with .' do
+  when_the_repository "has a cookbook starting with ." do
     before do
-      file 'cookbooks/.svn/metadata.rb', ''
-      file 'cookbooks/a.b/metadata.rb', ''
+      file "cookbooks/.svn/metadata.rb", ""
+      file "cookbooks/a.b/metadata.rb", ""
     end
-    it 'knife list does not show it' do
-      knife('list --local -fp /cookbooks').should_succeed "/cookbooks/a.b/\n"
+    it "knife list does not show it" do
+      knife("list --local -fp /cookbooks").should_succeed "/cookbooks/a.b/\n"
     end
   end
 
-  when_the_repository 'has a data bag starting with .' do
+  when_the_repository "has a data bag starting with ." do
     before do
-      file 'data_bags/.svn/x.json', {}
-      file 'data_bags/a.b/x.json', {}
+      file "data_bags/.svn/x.json", {}
+      file "data_bags/a.b/x.json", {}
     end
-    it 'knife list does not show it' do
-      knife('list --local -fp /data_bags').should_succeed "/data_bags/a.b/\n"
+    it "knife list does not show it" do
+      knife("list --local -fp /data_bags").should_succeed "/data_bags/a.b/\n"
     end
   end
 end
diff --git a/spec/integration/knife/chefignore_spec.rb b/spec/integration/knife/chefignore_spec.rb
index 34bf391..aa5a397 100644
--- a/spec/integration/knife/chefignore_spec.rb
+++ b/spec/integration/knife/chefignore_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,37 +15,37 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/list'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "chef/knife/list"
+require "chef/knife/show"
 
-describe 'chefignore tests', :workstation do
+describe "chefignore tests", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
   when_the_repository "has lots of stuff in it" do
     before do
-      file 'roles/x.json', {}
-      file 'environments/x.json', {}
-      file 'data_bags/bag1/x.json', {}
-      file 'cookbooks/cookbook1/x.json', {}
+      file "roles/x.json", {}
+      file "environments/x.json", {}
+      file "data_bags/bag1/x.json", {}
+      file "cookbooks/cookbook1/x.json", {}
     end
 
     context "and has a chefignore everywhere except cookbooks" do
       before do
         chefignore = "x.json\nroles/x.json\nenvironments/x.json\ndata_bags/bag1/x.json\nbag1/x.json\ncookbooks/cookbook1/x.json\ncookbook1/x.json\n"
-        file 'chefignore', chefignore
-        file 'roles/chefignore', chefignore
-        file 'environments/chefignore', chefignore
-        file 'data_bags/chefignore', chefignore
-        file 'data_bags/bag1/chefignore', chefignore
-        file 'cookbooks/cookbook1/chefignore', chefignore
+        file "chefignore", chefignore
+        file "roles/chefignore", chefignore
+        file "environments/chefignore", chefignore
+        file "data_bags/chefignore", chefignore
+        file "data_bags/bag1/chefignore", chefignore
+        file "cookbooks/cookbook1/chefignore", chefignore
       end
 
-      it 'matching files and directories get ignored' do
+      it "matching files and directories get ignored" do
         # NOTE: many of the "chefignore" files should probably not show up
         # themselves, but we have other tests that talk about that
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/chefignore
@@ -61,15 +61,15 @@ EOM
     end
   end
 
-  when_the_repository 'has a cookbook with only chefignored files' do
+  when_the_repository "has a cookbook with only chefignored files" do
     before do
-      file 'cookbooks/cookbook1/templates/default/x.rb', ''
-      file 'cookbooks/cookbook1/libraries/x.rb', ''
-      file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
+      file "cookbooks/cookbook1/templates/default/x.rb", ""
+      file "cookbooks/cookbook1/libraries/x.rb", ""
+      file "cookbooks/chefignore", "libraries/x.rb\ntemplates/default/x.rb\n"
     end
 
-    it 'the cookbook is not listed' do
-      knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
+    it "the cookbook is not listed" do
+      knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
 /cookbooks/
 EOM
     end
@@ -77,17 +77,17 @@ EOM
 
   when_the_repository "has multiple cookbooks" do
     before do
-      file 'cookbooks/cookbook1/x.json', {}
-      file 'cookbooks/cookbook1/y.json', {}
-      file 'cookbooks/cookbook2/x.json', {}
-      file 'cookbooks/cookbook2/y.json', {}
+      file "cookbooks/cookbook1/x.json", {}
+      file "cookbooks/cookbook1/y.json", {}
+      file "cookbooks/cookbook2/x.json", {}
+      file "cookbooks/cookbook2/y.json", {}
     end
 
-    context 'and has a chefignore with filenames' do
-      before { file 'cookbooks/chefignore', "x.json\n" }
+    context "and has a chefignore with filenames" do
+      before { file "cookbooks/chefignore", "x.json\n" }
 
-      it 'matching files and directories get ignored in all cookbooks' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "matching files and directories get ignored in all cookbooks" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/y.json
@@ -99,12 +99,12 @@ EOM
 
     context "and has a chefignore with wildcards" do
       before do
-        file 'cookbooks/chefignore', "x.*\n"
-        file 'cookbooks/cookbook1/x.rb', ''
+        file "cookbooks/chefignore", "x.*\n"
+        file "cookbooks/cookbook1/x.rb", ""
       end
 
-      it 'matching files and directories get ignored in all cookbooks' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "matching files and directories get ignored in all cookbooks" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/y.json
@@ -116,13 +116,13 @@ EOM
 
     context "and has a chefignore with relative paths" do
       before do
-        file 'cookbooks/cookbook1/recipes/x.rb', ''
-        file 'cookbooks/cookbook2/recipes/y.rb', ''
-        file 'cookbooks/chefignore', "recipes/x.rb\n"
+        file "cookbooks/cookbook1/recipes/x.rb", ""
+        file "cookbooks/cookbook2/recipes/y.rb", ""
+        file "cookbooks/chefignore", "recipes/x.rb\n"
       end
 
-      it 'matching directories get ignored' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "matching directories get ignored" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/x.json
@@ -138,12 +138,12 @@ EOM
 
     context "and has a chefignore with subdirectories" do
       before do
-        file 'cookbooks/cookbook1/recipes/y.rb', ''
-        file 'cookbooks/chefignore', "recipes\nrecipes/\n"
+        file "cookbooks/cookbook1/recipes/y.rb", ""
+        file "cookbooks/chefignore", "recipes\nrecipes/\n"
       end
 
-      it 'matching directories do NOT get ignored' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "matching directories do NOT get ignored" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/recipes/
@@ -159,13 +159,13 @@ EOM
 
     context "and has a chefignore that ignores all files in a subdirectory" do
       before do
-        file 'cookbooks/cookbook1/templates/default/x.rb', ''
-        file 'cookbooks/cookbook1/libraries/x.rb', ''
-        file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
+        file "cookbooks/cookbook1/templates/default/x.rb", ""
+        file "cookbooks/cookbook1/libraries/x.rb", ""
+        file "cookbooks/chefignore", "libraries/x.rb\ntemplates/default/x.rb\n"
       end
 
-      it 'ignores the subdirectory entirely' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "ignores the subdirectory entirely" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/x.json
@@ -179,11 +179,11 @@ EOM
 
     context "and has an empty chefignore" do
       before do
-        file 'cookbooks/chefignore', "\n"
+        file "cookbooks/chefignore", "\n"
       end
 
-      it 'nothing is ignored' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "nothing is ignored" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/x.json
@@ -197,11 +197,11 @@ EOM
 
     context "and has a chefignore with comments and empty lines" do
       before do
-        file 'cookbooks/chefignore', "\n\n # blah\n#\nx.json\n\n"
+        file "cookbooks/chefignore", "\n\n # blah\n#\nx.json\n\n"
       end
 
-      it 'matching files and directories get ignored in all cookbooks' do
-        knife('list --local -Rfp /').should_succeed <<EOM
+      it "matching files and directories get ignored in all cookbooks" do
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/cookbook1/
 /cookbooks/cookbook1/y.json
@@ -215,25 +215,25 @@ EOM
   when_the_repository "has multiple cookbook paths" do
     before :each do
       Chef::Config.cookbook_path = [
-        File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
-        File.join(Chef::Config.chef_repo_path, 'cookbooks2')
+        File.join(Chef::Config.chef_repo_path, "cookbooks1"),
+        File.join(Chef::Config.chef_repo_path, "cookbooks2"),
       ]
     end
 
     before do
-      file 'cookbooks1/mycookbook/metadata.rb', ''
-      file 'cookbooks1/mycookbook/x.json', {}
-      file 'cookbooks2/yourcookbook/metadata.rb', ''
-      file 'cookbooks2/yourcookbook/x.json', ''
+      file "cookbooks1/mycookbook/metadata.rb", ""
+      file "cookbooks1/mycookbook/x.json", {}
+      file "cookbooks2/yourcookbook/metadata.rb", ""
+      file "cookbooks2/yourcookbook/x.json", ""
     end
 
     context "and multiple chefignores" do
       before do
-        file 'cookbooks1/chefignore', "metadata.rb\n"
-        file 'cookbooks2/chefignore', "x.json\n"
+        file "cookbooks1/chefignore", "metadata.rb\n"
+        file "cookbooks2/chefignore", "x.json\n"
       end
       it "chefignores apply only to the directories they are in" do
-        knife('list --local -Rfp /').should_succeed <<EOM
+        knife("list --local -Rfp /").should_succeed <<EOM
 /cookbooks/
 /cookbooks/mycookbook/
 /cookbooks/mycookbook/x.json
@@ -244,14 +244,14 @@ EOM
 
       context "and conflicting cookbooks" do
         before do
-          file 'cookbooks1/yourcookbook/metadata.rb', ''
-          file 'cookbooks1/yourcookbook/x.json', ''
-          file 'cookbooks1/yourcookbook/onlyincookbooks1.rb', ''
-          file 'cookbooks2/yourcookbook/onlyincookbooks2.rb', ''
+          file "cookbooks1/yourcookbook/metadata.rb", ""
+          file "cookbooks1/yourcookbook/x.json", ""
+          file "cookbooks1/yourcookbook/onlyincookbooks1.rb", ""
+          file "cookbooks2/yourcookbook/onlyincookbooks2.rb", ""
         end
 
         it "chefignores apply only to the winning cookbook" do
-          knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n")
+          knife("list --local -Rfp /").should_succeed(<<EOM, :stderr => "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n")
 /cookbooks/
 /cookbooks/mycookbook/
 /cookbooks/mycookbook/x.json
@@ -264,32 +264,32 @@ EOM
     end
   end
 
-  when_the_repository 'has a cookbook named chefignore' do
+  when_the_repository "has a cookbook named chefignore" do
     before do
-      file 'cookbooks/chefignore/metadata.rb', {}
+      file "cookbooks/chefignore/metadata.rb", {}
     end
-    it 'knife list -Rfp /cookbooks shows it' do
-      knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+    it "knife list -Rfp /cookbooks shows it" do
+      knife("list --local -Rfp /cookbooks").should_succeed <<EOM
 /cookbooks/chefignore/
 /cookbooks/chefignore/metadata.rb
 EOM
     end
   end
 
-  when_the_repository 'has multiple cookbook paths, one with a chefignore file and the other with a cookbook named chefignore' do
+  when_the_repository "has multiple cookbook paths, one with a chefignore file and the other with a cookbook named chefignore" do
     before do
-      file 'cookbooks1/chefignore', ''
-      file 'cookbooks1/blah/metadata.rb', ''
-      file 'cookbooks2/chefignore/metadata.rb', ''
+      file "cookbooks1/chefignore", ""
+      file "cookbooks1/blah/metadata.rb", ""
+      file "cookbooks2/chefignore/metadata.rb", ""
     end
     before :each do
       Chef::Config.cookbook_path = [
-        File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
-        File.join(Chef::Config.chef_repo_path, 'cookbooks2')
+        File.join(Chef::Config.chef_repo_path, "cookbooks1"),
+        File.join(Chef::Config.chef_repo_path, "cookbooks2"),
       ]
     end
-    it 'knife list -Rfp /cookbooks shows the chefignore cookbook' do
-      knife('list --local -Rfp /cookbooks').should_succeed <<EOM
+    it "knife list -Rfp /cookbooks shows the chefignore cookbook" do
+      knife("list --local -Rfp /cookbooks").should_succeed <<EOM
 /cookbooks/blah/
 /cookbooks/blah/metadata.rb
 /cookbooks/chefignore/
diff --git a/spec/integration/knife/common_options_spec.rb b/spec/integration/knife/common_options_spec.rb
index b2e2e3f..c941dcc 100644
--- a/spec/integration/knife/common_options_spec.rb
+++ b/spec/integration/knife/common_options_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,46 +15,46 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/raw'
+require "support/shared/integration/integration_helper"
+require "chef/knife/raw"
 
-describe 'knife common options', :workstation do
+describe "knife common options", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
   when_the_repository "has a node" do
-    before { file 'nodes/x.json', {} }
+    before { file "nodes/x.json", {} }
 
-    context 'When chef_zero.enabled is true' do
+    context "When chef_zero.enabled is true" do
       before(:each) do
         Chef::Config.chef_zero.enabled = true
       end
 
-      it 'knife raw /nodes/x should retrieve the node' do
-        knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+      it "knife raw /nodes/x should retrieve the node" do
+        knife("raw /nodes/x").should_succeed( /"name": "x"/ )
       end
 
-      context 'And chef_zero.port is 9999' do
+      context "And chef_zero.port is 9999" do
         before(:each) { Chef::Config.chef_zero.port = 9999 }
 
-        it 'knife raw /nodes/x should retrieve the node' do
-          knife('raw /nodes/x').should_succeed( /"name": "x"/ )
-          expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+        it "knife raw /nodes/x should retrieve the node" do
+          knife("raw /nodes/x").should_succeed( /"name": "x"/ )
+          expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
         end
       end
 
       # 0.0.0.0 is not a valid address to bind to on windows.
-      context 'And chef_zero.host is 0.0.0.0', :unix_only do
-        before(:each) { Chef::Config.chef_zero.host = '0.0.0.0' }
+      context "And chef_zero.host is 0.0.0.0", :unix_only do
+        before(:each) { Chef::Config.chef_zero.host = "0.0.0.0" }
 
-        it 'knife raw /nodes/x should retrieve the role' do
-          knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+        it "knife raw /nodes/x should retrieve the role" do
+          knife("raw /nodes/x").should_succeed( /"name": "x"/ )
         end
       end
 
-      context 'and there is a private key' do
+      context "and there is a private key" do
         before do
-          file 'mykey.pem', <<EOM
+          file "mykey.pem", <<EOM
 -----BEGIN RSA PRIVATE KEY-----
 MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf
 0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk
@@ -85,29 +85,29 @@ syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T
 EOM
         end
 
-        it 'knife raw /nodes/x should retrieve the node' do
-          knife('raw /nodes/x').should_succeed( /"name": "x"/ )
+        it "knife raw /nodes/x should retrieve the node" do
+          knife("raw /nodes/x").should_succeed( /"name": "x"/ )
         end
       end
     end
 
-    it 'knife raw -z /nodes/x retrieves the node' do
-      knife('raw -z /nodes/x').should_succeed( /"name": "x"/ )
+    it "knife raw -z /nodes/x retrieves the node" do
+      knife("raw -z /nodes/x").should_succeed( /"name": "x"/ )
     end
 
-    it 'knife raw --local-mode /nodes/x retrieves the node' do
-      knife('raw --local-mode /nodes/x').should_succeed( /"name": "x"/ )
+    it "knife raw --local-mode /nodes/x retrieves the node" do
+      knife("raw --local-mode /nodes/x").should_succeed( /"name": "x"/ )
     end
 
-    it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
-      knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
-      expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+    it "knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node" do
+      knife("raw -z --chef-zero-port=9999 /nodes/x").should_succeed( /"name": "x"/ )
+      expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
     end
 
-    context 'when the default port (8889) is already bound' do
+    context "when the default port (8889) is already bound" do
       before :each do
         begin
-          @server = ChefZero::Server.new(:host => 'localhost', :port => 8889)
+          @server = ChefZero::Server.new(:host => "localhost", :port => 8889)
           @server.start_background
         rescue Errno::EADDRINUSE
           # OK.  Don't care who has it in use, as long as *someone* does.
@@ -117,16 +117,16 @@ EOM
         @server.stop if @server
       end
 
-      it 'knife raw -z /nodes/x retrieves the node' do
-        knife('raw -z /nodes/x').should_succeed( /"name": "x"/ )
+      it "knife raw -z /nodes/x retrieves the node" do
+        knife("raw -z /nodes/x").should_succeed( /"name": "x"/ )
         expect(URI(Chef::Config.chef_server_url).port).to be > 8889
       end
     end
 
-    context 'when port 9999 is already bound' do
+    context "when port 9999 is already bound" do
       before :each do
         begin
-          @server = ChefZero::Server.new(:host => 'localhost', :port => 9999)
+          @server = ChefZero::Server.new(:host => "localhost", :port => 9999)
           @server.start_background
         rescue Errno::EADDRINUSE
           # OK.  Don't care who has it in use, as long as *someone* does.
@@ -136,20 +136,20 @@ EOM
         @server.stop if @server
       end
 
-      it 'knife raw -z --chef-zero-port=9999-20000 /nodes/x' do
-        knife('raw -z --chef-zero-port=9999-20000 /nodes/x').should_succeed( /"name": "x"/ )
+      it "knife raw -z --chef-zero-port=9999-20000 /nodes/x" do
+        knife("raw -z --chef-zero-port=9999-20000 /nodes/x").should_succeed( /"name": "x"/ )
         expect(URI(Chef::Config.chef_server_url).port).to be > 9999
       end
 
-      it 'knife raw -z --chef-zero-port=9999-9999,19423' do
-        knife('raw -z --chef-zero-port=9999-9999,19423 /nodes/x').should_succeed( /"name": "x"/ )
+      it "knife raw -z --chef-zero-port=9999-9999,19423" do
+        knife("raw -z --chef-zero-port=9999-9999,19423 /nodes/x").should_succeed( /"name": "x"/ )
         expect(URI(Chef::Config.chef_server_url).port).to be == 19423
       end
     end
 
-    it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
-      knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
-      expect(Chef::Config.chef_server_url).to eq('chefzero://localhost:9999')
+    it "knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node" do
+      knife("raw -z --chef-zero-port=9999 /nodes/x").should_succeed( /"name": "x"/ )
+      expect(Chef::Config.chef_server_url).to eq("chefzero://localhost:9999")
     end
   end
 end
diff --git a/spec/integration/knife/cookbook_api_ipv6_spec.rb b/spec/integration/knife/cookbook_api_ipv6_spec.rb
index 3d468be..0a4a6a6 100644
--- a/spec/integration/knife/cookbook_api_ipv6_spec.rb
+++ b/spec/integration/knife/cookbook_api_ipv6_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +15,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
 
-describe "Knife cookbook API integration with IPv6", :workstation do
+describe "Knife cookbook API integration with IPv6", :workstation, :not_supported_on_gce do
   include IntegrationSupport
   include Chef::Mixin::ShellOut
 
   when_the_chef_server "is bound to IPv6" do
-    let(:chef_zero_opts) { {:host => "::1"} }
+    let(:chef_zero_opts) { { :host => "::1" } }
 
     let(:client_key) do
       <<-END_VALIDATION_PEM
@@ -84,8 +84,8 @@ END_CLIENT_RB
         end
 
         before do
-          file 'config/knife.rb', knife_rb_content
-          file 'config/knifeuser.pem', client_key
+          file "config/knife.rb", knife_rb_content
+          file "config/knifeuser.pem", client_key
         end
 
         it "successfully uploads a cookbook" do
@@ -102,7 +102,7 @@ END_CLIENT_RB
 
           it "downloads the cookbook" do
             shell_out!("knife cookbook download apache2 #{knife_config_flag} -d #{cache_path}", :cwd => chef_dir)
-            expect(Dir["#{cache_path}/*"].map {|entry| File.basename(entry)}).to include("apache2-0.0.1")
+            expect(Dir["#{cache_path}/*"].map { |entry| File.basename(entry) }).to include("apache2-0.0.1")
           end
         end
 
diff --git a/spec/integration/knife/delete_spec.rb b/spec/integration/knife/delete_spec.rb
index 733a7ef..d8cb8d9 100644
--- a/spec/integration/knife/delete_spec.rb
+++ b/spec/integration/knife/delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/delete'
-require 'chef/knife/list'
-require 'chef/knife/raw'
+require "support/shared/integration/integration_helper"
+require "chef/knife/delete"
+require "chef/knife/list"
+require "chef/knife/raw"
 
-describe 'knife delete', :workstation do
+describe "knife delete", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
@@ -100,39 +100,39 @@ EOM
 
   when_the_chef_server "has one of each thing" do
     before do
-      client 'x', '{}'
-      cookbook 'x', '1.0.0'
-      data_bag 'x', { 'y' => '{}' }
-      environment 'x', '{}'
-      node 'x', '{}'
-      role 'x', '{}'
-      user 'x', '{}'
+      client "x", "{}"
+      cookbook "x", "1.0.0"
+      data_bag "x", { "y" => "{}" }
+      environment "x", "{}"
+      node "x", "{}"
+      role "x", "{}"
+      user "x", "{}"
     end
 
-    when_the_repository 'also has one of each thing' do
+    when_the_repository "also has one of each thing" do
       before do
-        file 'clients/x.json', {}
-        file 'cookbooks/x/metadata.rb', ''
-        file 'data_bags/x/y.json', {}
-        file 'environments/_default.json', {}
-        file 'environments/x.json', {}
-        file 'nodes/x.json', {}
-        file 'roles/x.json', {}
-        file 'users/x.json', {}
-      end
-
-      it 'knife delete --both /cookbooks/x fails' do
-        knife('delete --both /cookbooks/x').should_fail <<EOM
+        file "clients/x.json", {}
+        file "cookbooks/x/metadata.rb", ""
+        file "data_bags/x/y.json", {}
+        file "environments/_default.json", {}
+        file "environments/x.json", {}
+        file "nodes/x.json", {}
+        file "roles/x.json", {}
+        file "users/x.json", {}
+      end
+
+      it "knife delete --both /cookbooks/x fails" do
+        knife("delete --both /cookbooks/x").should_fail <<EOM
 ERROR: /cookbooks/x (remote) must be deleted recursively!  Pass -r to knife delete.
 ERROR: /cookbooks/x (local) must be deleted recursively!  Pass -r to knife delete.
 EOM
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both -r /cookbooks/x deletes x' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both -r /cookbooks/x deletes x" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -152,7 +152,7 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed <<EOM
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -171,10 +171,10 @@ EOM
 EOM
       end
 
-      it 'knife delete -r --local /cookbooks/x deletes x locally but not remotely' do
-        knife('delete -r --local /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete -r --local /cookbooks/x deletes x locally but not remotely" do
+        knife("delete -r --local /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -193,9 +193,9 @@ EOM
 EOM
       end
 
-      it 'knife delete -r /cookbooks/x deletes x remotely but not locally' do
-        knife('delete -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete -r /cookbooks/x deletes x remotely but not locally" do
+        knife("delete -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -215,22 +215,22 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf --local /").should_succeed everything
       end
 
       # TODO delete empty data bag (particularly different on local side)
-      context 'with an empty data bag on both' do
+      context "with an empty data bag on both" do
         before do
-          data_bag 'empty', {}
-          directory 'data_bags/empty'
+          data_bag "empty", {}
+          directory "data_bags/empty"
         end
 
-        it 'knife delete --both /data_bags/empty fails but deletes local version' do
-          knife('delete --both /data_bags/empty').should_fail <<EOM
+        it "knife delete --both /data_bags/empty fails but deletes local version" do
+          knife("delete --both /data_bags/empty").should_fail <<EOM
 ERROR: /data_bags/empty (remote) must be deleted recursively!  Pass -r to knife delete.
 ERROR: /data_bags/empty (local) must be deleted recursively!  Pass -r to knife delete.
 EOM
-          knife('list -Rf /').should_succeed <<EOM
+          knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -253,7 +253,7 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-          knife('list -Rf --local /').should_succeed <<EOM
+          knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -276,18 +276,18 @@ EOM
         end
       end
 
-      it 'knife delete --both /data_bags/x fails' do
-        knife('delete --both /data_bags/x').should_fail <<EOM
+      it "knife delete --both /data_bags/x fails" do
+        knife("delete --both /data_bags/x").should_fail <<EOM
 ERROR: /data_bags/x (remote) must be deleted recursively!  Pass -r to knife delete.
 ERROR: /data_bags/x (local) must be deleted recursively!  Pass -r to knife delete.
 EOM
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both -r /data_bags/x deletes x' do
-        knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both -r /data_bags/x deletes x" do
+        knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -307,7 +307,7 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed <<EOM
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -326,9 +326,9 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /environments/x.json deletes x' do
-        knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both /environments/x.json deletes x" do
+        knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -349,7 +349,7 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed <<EOM
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -369,9 +369,9 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /roles/x.json deletes x' do
-        knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both /roles/x.json deletes x" do
+        knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -392,7 +392,7 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed <<EOM
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -412,10 +412,10 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /environments/_default.json fails but still deletes the local copy' do
-        knife('delete --both /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete --both /environments/_default.json fails but still deletes the local copy" do
+        knife("delete --both /environments/_default.json").should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -435,23 +435,23 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /environments/nonexistent.json fails' do
-        knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed everything
+      it "knife delete --both /environments/nonexistent.json fails" do
+        knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both / fails' do
-        knife('delete --both /').should_fail <<EOM
+      it "knife delete --both / fails" do
+        knife("delete --both /").should_fail <<EOM
 ERROR: / (remote) cannot be deleted.
 ERROR: / (local) cannot be deleted.
 EOM
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both -r /* fails' do
-        knife('delete --both -r /*').should_fail <<EOM
+      it "knife delete --both -r /* fails" do
+        knife("delete --both -r /*").should_fail <<EOM
 ERROR: / (remote) cannot be deleted.
 ERROR: / (local) cannot be deleted.
 ERROR: /clients (remote) cannot be deleted.
@@ -469,31 +469,31 @@ ERROR: /roles (local) cannot be deleted.
 ERROR: /users (remote) cannot be deleted.
 ERROR: /users (local) cannot be deleted.
 EOM
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed everything
       end
     end
 
-    when_the_repository 'has only top-level directories' do
+    when_the_repository "has only top-level directories" do
       before do
-        directory 'clients'
-        directory 'cookbooks'
-        directory 'data_bags'
-        directory 'environments'
-        directory 'nodes'
-        directory 'roles'
-        directory 'users'
+        directory "clients"
+        directory "cookbooks"
+        directory "data_bags"
+        directory "environments"
+        directory "nodes"
+        directory "roles"
+        directory "users"
       end
 
-      it 'knife delete --both /cookbooks/x fails' do
-        knife('delete --both /cookbooks/x').should_fail "ERROR: /cookbooks/x (remote) must be deleted recursively!  Pass -r to knife delete.\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+      it "knife delete --both /cookbooks/x fails" do
+        knife("delete --both /cookbooks/x").should_fail "ERROR: /cookbooks/x (remote) must be deleted recursively!  Pass -r to knife delete.\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both -r /cookbooks/x deletes x' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both -r /cookbooks/x deletes x" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -513,18 +513,18 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed nothing
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both /data_bags/x fails' do
-        knife('delete --both /data_bags/x').should_fail "ERROR: /data_bags/x (remote) must be deleted recursively!  Pass -r to knife delete.\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+      it "knife delete --both /data_bags/x fails" do
+        knife("delete --both /data_bags/x").should_fail "ERROR: /data_bags/x (remote) must be deleted recursively!  Pass -r to knife delete.\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both -r /data_bags/x deletes x' do
-        knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both -r /data_bags/x deletes x" do
+        knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -544,12 +544,12 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed nothing
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both /environments/x.json deletes x' do
-        knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both /environments/x.json deletes x" do
+        knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -570,12 +570,12 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed nothing
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both /roles/x.json deletes x' do
-        knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
-        knife('list -Rf /').should_succeed <<EOM
+      it "knife delete --both /roles/x.json deletes x" do
+        knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+        knife("list -Rf /").should_succeed <<EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -596,23 +596,23 @@ EOM
 /users/admin.json
 /users/x.json
 EOM
-        knife('list -Rf --local /').should_succeed nothing
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both /environments/_default.json fails' do
-        knife('delete --both /environments/_default.json').should_fail "", :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+      it "knife delete --both /environments/_default.json fails" do
+        knife("delete --both /environments/_default.json").should_fail "", :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both / fails' do
-        knife('delete --both /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+      it "knife delete --both / fails" do
+        knife("delete --both /").should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both -r /* fails' do
-        knife('delete --both -r /*').should_fail <<EOM
+      it "knife delete --both -r /* fails" do
+        knife("delete --both -r /*").should_fail <<EOM
 ERROR: / (remote) cannot be deleted.
 ERROR: / (local) cannot be deleted.
 ERROR: /clients (remote) cannot be deleted.
@@ -630,21 +630,21 @@ ERROR: /roles (local) cannot be deleted.
 ERROR: /users (remote) cannot be deleted.
 ERROR: /users (local) cannot be deleted.
 EOM
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      it 'knife delete --both /environments/nonexistent.json fails' do
-        knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
-        knife('list -Rf /').should_succeed server_everything
-        knife('list -Rf --local /').should_succeed nothing
+      it "knife delete --both /environments/nonexistent.json fails" do
+        knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+        knife("list -Rf /").should_succeed server_everything
+        knife("list -Rf --local /").should_succeed nothing
       end
 
-      context 'and cwd is at the top level' do
-        before { cwd '.' }
-        it 'knife delete fails' do
-          knife('delete').should_fail "FATAL: Must specify at least one argument.  If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
-          knife('list -Rf /').should_succeed <<EOM
+      context "and cwd is at the top level" do
+        before { cwd "." }
+        it "knife delete fails" do
+          knife("delete").should_fail "FATAL: Must specify at least one argument.  If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
+          knife("list -Rf /").should_succeed <<EOM
 clients
 clients/chef-validator.json
 clients/chef-webui.json
@@ -666,7 +666,7 @@ users
 users/admin.json
 users/x.json
 EOM
-          knife('list -Rf --local /').should_succeed <<EOM
+          knife("list -Rf --local /").should_succeed <<EOM
 clients
 cookbooks
 data_bags
@@ -680,29 +680,29 @@ EOM
     end
   end
 
-  when_the_chef_server 'is empty' do
-    when_the_repository 'has one of each thing' do
+  when_the_chef_server "is empty" do
+    when_the_repository "has one of each thing" do
       before do
-        file 'clients/x.json', {}
-        file 'cookbooks/x/metadata.rb', ''
-        file 'data_bags/x/y.json', {}
-        file 'environments/_default.json', {}
-        file 'environments/x.json', {}
-        file 'nodes/x.json', {}
-        file 'roles/x.json', {}
-        file 'users/x.json', {}
-      end
-
-      it 'knife delete --both /cookbooks/x fails' do
-        knife('delete --both /cookbooks/x').should_fail "ERROR: /cookbooks/x (local) must be deleted recursively!  Pass -r to knife delete.\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed everything
-      end
-
-      it 'knife delete --both -r /cookbooks/x deletes x' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed <<EOM
+        file "clients/x.json", {}
+        file "cookbooks/x/metadata.rb", ""
+        file "data_bags/x/y.json", {}
+        file "environments/_default.json", {}
+        file "environments/x.json", {}
+        file "nodes/x.json", {}
+        file "roles/x.json", {}
+        file "users/x.json", {}
+      end
+
+      it "knife delete --both /cookbooks/x fails" do
+        knife("delete --both /cookbooks/x").should_fail "ERROR: /cookbooks/x (local) must be deleted recursively!  Pass -r to knife delete.\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed everything
+      end
+
+      it "knife delete --both -r /cookbooks/x deletes x" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -721,16 +721,16 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /data_bags/x fails' do
-        knife('delete --both /data_bags/x').should_fail "ERROR: /data_bags/x (local) must be deleted recursively!  Pass -r to knife delete.\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed everything
+      it "knife delete --both /data_bags/x fails" do
+        knife("delete --both /data_bags/x").should_fail "ERROR: /data_bags/x (local) must be deleted recursively!  Pass -r to knife delete.\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both -r /data_bags/x deletes x' do
-        knife('delete --both -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete --both -r /data_bags/x deletes x" do
+        knife("delete --both -r /data_bags/x").should_succeed "Deleted /data_bags/x\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -749,10 +749,10 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /environments/x.json deletes x' do
-        knife('delete --both /environments/x.json').should_succeed "Deleted /environments/x.json\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete --both /environments/x.json deletes x" do
+        knife("delete --both /environments/x.json").should_succeed "Deleted /environments/x.json\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -772,10 +772,10 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /roles/x.json deletes x' do
-        knife('delete --both /roles/x.json').should_succeed "Deleted /roles/x.json\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete --both /roles/x.json deletes x" do
+        knife("delete --both /roles/x.json").should_succeed "Deleted /roles/x.json\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -795,10 +795,10 @@ EOM
 EOM
       end
 
-      it 'knife delete --both /environments/_default.json fails but still deletes the local copy' do
-        knife('delete --both /environments/_default.json').should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed <<EOM
+      it "knife delete --both /environments/_default.json fails but still deletes the local copy" do
+        knife("delete --both /environments/_default.json").should_fail :stderr => "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed <<EOM
 /clients
 /clients/x.json
 /cookbooks
@@ -818,14 +818,14 @@ EOM
 EOM
       end
 
-      it 'knife delete --both / fails' do
-        knife('delete --both /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed everything
+      it "knife delete --both / fails" do
+        knife("delete --both /").should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both -r /* fails' do
-        knife('delete --both -r /*').should_fail <<EOM
+      it "knife delete --both -r /* fails" do
+        knife("delete --both -r /*").should_fail <<EOM
 ERROR: / (remote) cannot be deleted.
 ERROR: / (local) cannot be deleted.
 ERROR: /clients (remote) cannot be deleted.
@@ -843,21 +843,21 @@ ERROR: /roles (local) cannot be deleted.
 ERROR: /users (remote) cannot be deleted.
 ERROR: /users (local) cannot be deleted.
 EOM
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed everything
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      it 'knife delete --both /environments/nonexistent.json fails' do
-        knife('delete --both /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
-        knife('list -Rf /').should_succeed server_nothing
-        knife('list -Rf --local /').should_succeed everything
+      it "knife delete --both /environments/nonexistent.json fails" do
+        knife("delete --both /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+        knife("list -Rf /").should_succeed server_nothing
+        knife("list -Rf --local /").should_succeed everything
       end
 
-      context 'and cwd is at the top level' do
-        before { cwd '.' }
-        it 'knife delete fails' do
-          knife('delete').should_fail "FATAL: Must specify at least one argument.  If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
-          knife('list -Rf /').should_succeed <<EOM
+      context "and cwd is at the top level" do
+        before { cwd "." }
+        it "knife delete fails" do
+          knife("delete").should_fail "FATAL: Must specify at least one argument.  If you want to delete everything in this directory, type \"knife delete --recurse .\"\n", :stdout => /USAGE/
+          knife("list -Rf /").should_succeed <<EOM
 clients
 clients/chef-validator.json
 clients/chef-webui.json
@@ -870,7 +870,7 @@ roles
 users
 users/admin.json
 EOM
-          knife('list -Rf --local /').should_succeed <<EOM
+          knife("list -Rf --local /").should_succeed <<EOM
 clients
 clients/x.json
 cookbooks
@@ -894,110 +894,124 @@ EOM
     end
   end
 
-  when_the_repository 'has a cookbook' do
+  when_the_repository "has a cookbook" do
     before do
-      file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
-      file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+      file "cookbooks/x/metadata.rb", 'version "1.0.0"'
+      file "cookbooks/x/onlyin1.0.0.rb", "old_text"
     end
 
-    when_the_chef_server 'has a later version for the cookbook' do
+    when_the_chef_server "has a later version for the cookbook" do
       before do
-        cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-        cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+        cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+        cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
       end
 
       # TODO this seems wrong
-      it 'knife delete --both -r /cookbooks/x deletes the latest version on the server and the local version' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('raw /cookbooks/x').should_succeed(/1.0.0/)
-        knife('list --local /cookbooks').should_succeed ''
+      it "knife delete --both -r /cookbooks/x deletes the latest version on the server and the local version" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("raw /cookbooks/x").should_succeed(/1.0.0/)
+        knife("list --local /cookbooks").should_succeed ""
       end
     end
 
-    when_the_chef_server 'has an earlier version for the cookbook' do
+    when_the_chef_server "has an earlier version for the cookbook" do
       before do
-        cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-        cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+        cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+        cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
       end
 
-      it 'knife delete --both /cookbooks/x deletes the latest version on the server and the local version' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('raw /cookbooks/x').should_succeed(/0.9.9/)
-        knife('list --local /cookbooks').should_succeed ''
+      it "knife delete --both /cookbooks/x deletes the latest version on the server and the local version" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("raw /cookbooks/x").should_succeed(/0.9.9/)
+        knife("list --local /cookbooks").should_succeed ""
       end
     end
 
-    when_the_chef_server 'has a later version for the cookbook, and no current version' do
-      before { cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' } }
+    when_the_chef_server "has a later version for the cookbook, and no current version" do
+      before { cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" } }
 
-      it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('raw /cookbooks/x').should_fail(/404/)
-        knife('list --local /cookbooks').should_succeed ''
+      it "knife delete --both /cookbooks/x deletes the server and client version of the cookbook" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("raw /cookbooks/x").should_fail(/404/)
+        knife("list --local /cookbooks").should_succeed ""
       end
     end
 
-    when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
-      before { cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' } }
+    when_the_chef_server "has an earlier version for the cookbook, and no current version" do
+      before { cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" } }
 
-      it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('raw /cookbooks/x').should_fail(/404/)
-        knife('list --local /cookbooks').should_succeed ''
+      it "knife delete --both /cookbooks/x deletes the server and client version of the cookbook" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("raw /cookbooks/x").should_fail(/404/)
+        knife("list --local /cookbooks").should_succeed ""
       end
     end
   end
 
-  when_the_repository 'is empty' do
-    when_the_chef_server 'has two versions of a cookbook' do
+  when_the_repository "is empty" do
+    when_the_chef_server "has two versions of a cookbook" do
       before do
-        cookbook 'x', '2.0.11'
-        cookbook 'x', '11.0.0'
+        cookbook "x", "2.0.11"
+        cookbook "x", "11.0.0"
       end
 
-      it 'knife delete deletes the latest version' do
-        knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
-        knife('raw /cookbooks/x').should_succeed( /2.0.11/ )
+      it "knife delete deletes the latest version" do
+        knife("delete --both -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
+        knife("raw /cookbooks/x").should_succeed( /2.0.11/ )
       end
     end
   end
 
   when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
     before do
-      organization 'foo' do
-        container 'x', {}
-        group 'x', {}
+      organization "foo" do
+        container "x", {}
+        group "x", {}
+        policy "x", "1.2.3", {}
+        policy_group "x", { "policies" => { "x" => { "revision_id" => "1.2.3" } } }
       end
     end
 
     before :each do
-      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
     end
 
-    it 'knife delete /acls/containers/environments.json fails with a reasonable error' do
-      knife('delete /acls/containers/environments.json').should_fail "ERROR: /acls/containers/environments.json (remote) cannot be deleted.\n"
+    it "knife delete /acls/containers/environments.json fails with a reasonable error" do
+      knife("delete /acls/containers/environments.json").should_fail "ERROR: /acls/containers/environments.json (remote) ACLs cannot be deleted.\n"
     end
 
-    it 'knife delete /containers/x.json succeeds' do
-      knife('delete /containers/x.json').should_succeed "Deleted /containers/x.json\n"
-      knife('raw /containers/x.json').should_fail(/404/)
+    it "knife delete /containers/x.json succeeds" do
+      knife("delete /containers/x.json").should_succeed "Deleted /containers/x.json\n"
+      knife("raw /containers/x.json").should_fail(/404/)
     end
 
-    it 'knife delete /groups/x.json succeeds' do
-      knife('delete /groups/x.json').should_succeed "Deleted /groups/x.json\n"
-      knife('raw /groups/x.json').should_fail(/404/)
+    it "knife delete /groups/x.json succeeds" do
+      knife("delete /groups/x.json").should_succeed "Deleted /groups/x.json\n"
+      knife("raw /groups/x.json").should_fail(/404/)
     end
 
-    it 'knife delete /org.json fails with a reasonable error' do
-      knife('delete /org.json').should_fail "ERROR: /org.json (remote) cannot be deleted.\n"
+    it "knife delete /policies/x-1.2.3.json succeeds" do
+      knife("raw /policies/x/revisions/1.2.3").should_succeed "{\n  \"name\": \"x\",\n  \"revision_id\": \"1.2.3\",\n  \"run_list\": [\n\n  ],\n  \"cookbook_locks\": {\n\n  }\n}\n"
+      knife("delete /policies/x-1.2.3.json").should_succeed "Deleted /policies/x-1.2.3.json\n"
+      knife("raw /policies/x/revisions/1.2.3").should_fail(/404/)
     end
 
-    it 'knife delete /invitations.json fails with a reasonable error' do
-      knife('delete /invitations.json').should_fail "ERROR: /invitations.json (remote) cannot be deleted.\n"
+    it "knife delete /policy_groups/x.json succeeds" do
+      knife("raw /policy_groups/x").should_succeed "{\n  \"uri\": \"http://127.0.0.1:8900/organizations/foo/policy_groups/x\",\n  \"policies\": {\n    \"x\": {\n      \"revision_id\": \"1.2.3\"\n    }\n  }\n}\n"
+      knife("delete /policy_groups/x.json").should_succeed "Deleted /policy_groups/x.json\n"
+      knife("raw /policy_groups/x").should_fail(/404/)
     end
 
-    it 'knife delete /members.json fails with a reasonable error' do
-      knife('delete /members.json').should_fail "ERROR: /members.json (remote) cannot be deleted.\n"
+    it "knife delete /org.json fails with a reasonable error" do
+      knife("delete /org.json").should_fail "ERROR: /org.json (remote) cannot be deleted.\n"
+    end
+
+    it "knife delete /invitations.json fails with a reasonable error" do
+      knife("delete /invitations.json").should_fail "ERROR: /invitations.json (remote) cannot be deleted.\n"
+    end
+
+    it "knife delete /members.json fails with a reasonable error" do
+      knife("delete /members.json").should_fail "ERROR: /members.json (remote) cannot be deleted.\n"
     end
   end
 end
diff --git a/spec/integration/knife/deps_spec.rb b/spec/integration/knife/deps_spec.rb
index 3120db4..d80fb77 100644
--- a/spec/integration/knife/deps_spec.rb
+++ b/spec/integration/knife/deps_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,33 +15,33 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/deps'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/deps"
 
-describe 'knife deps', :workstation do
+describe "knife deps", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
-  context 'local' do
-    when_the_repository 'has a role with no run_list' do
-      before { file 'roles/starring.json', {} }
-      it 'knife deps reports no dependencies' do
-        knife('deps /roles/starring.json').should_succeed "/roles/starring.json\n"
+  context "local" do
+    when_the_repository "has a role with no run_list" do
+      before { file "roles/starring.json", {} }
+      it "knife deps reports no dependencies" do
+        knife("deps /roles/starring.json").should_succeed "/roles/starring.json\n"
       end
     end
 
-    when_the_repository 'has a role with a default run_list' do
+    when_the_repository "has a role with a default run_list" do
       before do
-        file 'roles/starring.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
-        file 'roles/minor.json', {}
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
-        file 'cookbooks/soup/metadata.rb', 'name "soup"'
-        file 'cookbooks/soup/recipes/chicken.rb', ''
-      end
-      it 'knife deps reports all dependencies' do
-        knife('deps /roles/starring.json').should_succeed <<EOM
+        file "roles/starring.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+        file "roles/minor.json", {}
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+        file "cookbooks/quiche/recipes/default.rb", ""
+        file "cookbooks/soup/metadata.rb", 'name "soup"'
+        file "cookbooks/soup/recipes/chicken.rb", ""
+      end
+      it "knife deps reports all dependencies" do
+        knife("deps /roles/starring.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -50,17 +50,17 @@ EOM
       end
     end
 
-    when_the_repository 'has a role with an env_run_list' do
+    when_the_repository "has a role with an env_run_list" do
       before do
-        file 'roles/starring.json', { 'env_run_lists' => { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } }
-        file 'roles/minor.json', {}
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
-        file 'cookbooks/soup/metadata.rb', 'name "soup"'
-        file 'cookbooks/soup/recipes/chicken.rb', ''
-      end
-      it 'knife deps reports all dependencies' do
-        knife('deps /roles/starring.json').should_succeed <<EOM
+        file "roles/starring.json", { "env_run_lists" => { "desert" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} } }
+        file "roles/minor.json", {}
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+        file "cookbooks/quiche/recipes/default.rb", ""
+        file "cookbooks/soup/metadata.rb", 'name "soup"'
+        file "cookbooks/soup/recipes/chicken.rb", ""
+      end
+      it "knife deps reports all dependencies" do
+        knife("deps /roles/starring.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -69,32 +69,32 @@ EOM
       end
     end
 
-    when_the_repository 'has a node with no environment or run_list' do
-      before { file 'nodes/mort.json', {} }
-      it 'knife deps reports just the node' do
-        knife('deps /nodes/mort.json').should_succeed "/nodes/mort.json\n"
+    when_the_repository "has a node with no environment or run_list" do
+      before { file "nodes/mort.json", {} }
+      it "knife deps reports just the node" do
+        knife("deps /nodes/mort.json").should_succeed "/nodes/mort.json\n"
       end
     end
-    when_the_repository 'has a node with an environment' do
+    when_the_repository "has a node with an environment" do
       before do
-        file 'environments/desert.json', {}
-        file 'nodes/mort.json', { 'chef_environment' => 'desert' }
+        file "environments/desert.json", {}
+        file "nodes/mort.json", { "chef_environment" => "desert" }
       end
-      it 'knife deps reports just the node' do
-        knife('deps /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n"
+      it "knife deps reports just the node" do
+        knife("deps /nodes/mort.json").should_succeed "/environments/desert.json\n/nodes/mort.json\n"
       end
     end
-    when_the_repository 'has a node with roles and recipes in its run_list' do
+    when_the_repository "has a node with roles and recipes in its run_list" do
       before do
-        file 'roles/minor.json', {}
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
-        file 'cookbooks/soup/metadata.rb', 'name "soup"'
-        file 'cookbooks/soup/recipes/chicken.rb', ''
-        file 'nodes/mort.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
-      end
-      it 'knife deps reports just the node' do
-        knife('deps /nodes/mort.json').should_succeed <<EOM
+        file "roles/minor.json", {}
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+        file "cookbooks/quiche/recipes/default.rb", ""
+        file "cookbooks/soup/metadata.rb", 'name "soup"'
+        file "cookbooks/soup/recipes/chicken.rb", ""
+        file "nodes/mort.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+      end
+      it "knife deps reports just the node" do
+        knife("deps /nodes/mort.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -102,53 +102,53 @@ EOM
 EOM
       end
     end
-    when_the_repository 'has a cookbook with no dependencies' do
+    when_the_repository "has a cookbook with no dependencies" do
       before do
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+        file "cookbooks/quiche/recipes/default.rb", ""
       end
-      it 'knife deps reports just the cookbook' do
-        knife('deps /cookbooks/quiche').should_succeed "/cookbooks/quiche\n"
+      it "knife deps reports just the cookbook" do
+        knife("deps /cookbooks/quiche").should_succeed "/cookbooks/quiche\n"
       end
     end
-    when_the_repository 'has a cookbook with dependencies' do
+    when_the_repository "has a cookbook with dependencies" do
       before do
-        file 'cookbooks/kettle/metadata.rb', 'name "kettle"'
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"
+        file "cookbooks/kettle/metadata.rb", 'name "kettle"'
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"
 depends "kettle"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
+        file "cookbooks/quiche/recipes/default.rb", ""
       end
-      it 'knife deps reports just the cookbook' do
-        knife('deps /cookbooks/quiche').should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
+      it "knife deps reports just the cookbook" do
+        knife("deps /cookbooks/quiche").should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
       end
     end
-    when_the_repository 'has a data bag' do
-      before { file 'data_bags/bag/item.json', {} }
-      it 'knife deps reports just the data bag' do
-        knife('deps /data_bags/bag/item.json').should_succeed "/data_bags/bag/item.json\n"
+    when_the_repository "has a data bag" do
+      before { file "data_bags/bag/item.json", {} }
+      it "knife deps reports just the data bag" do
+        knife("deps /data_bags/bag/item.json").should_succeed "/data_bags/bag/item.json\n"
       end
     end
-    when_the_repository 'has an environment' do
-      before { file 'environments/desert.json', {} }
-      it 'knife deps reports just the environment' do
-        knife('deps /environments/desert.json').should_succeed "/environments/desert.json\n"
+    when_the_repository "has an environment" do
+      before { file "environments/desert.json", {} }
+      it "knife deps reports just the environment" do
+        knife("deps /environments/desert.json").should_succeed "/environments/desert.json\n"
       end
     end
-    when_the_repository 'has a deep dependency tree' do
+    when_the_repository "has a deep dependency tree" do
       before do
-        file 'roles/starring.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
-        file 'roles/minor.json', {}
-        file 'cookbooks/quiche/metadata.rb', 'name "quiche"'
-        file 'cookbooks/quiche/recipes/default.rb', ''
-        file 'cookbooks/soup/metadata.rb', 'name "soup"'
-        file 'cookbooks/soup/recipes/chicken.rb', ''
-        file 'environments/desert.json', {}
-        file 'nodes/mort.json', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] }
-        file 'nodes/bart.json', { 'run_list' => [ 'role[minor]' ] }
+        file "roles/starring.json", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+        file "roles/minor.json", {}
+        file "cookbooks/quiche/metadata.rb", 'name "quiche"'
+        file "cookbooks/quiche/recipes/default.rb", ""
+        file "cookbooks/soup/metadata.rb", 'name "soup"'
+        file "cookbooks/soup/recipes/chicken.rb", ""
+        file "environments/desert.json", {}
+        file "nodes/mort.json", { "chef_environment" => "desert", "run_list" => [ "role[starring]" ] }
+        file "nodes/bart.json", { "run_list" => [ "role[minor]" ] }
       end
 
-      it 'knife deps reports all dependencies' do
-        knife('deps /nodes/mort.json').should_succeed <<EOM
+      it "knife deps reports all dependencies" do
+        knife("deps /nodes/mort.json").should_succeed <<EOM
 /environments/desert.json
 /roles/minor.json
 /cookbooks/quiche
@@ -157,8 +157,8 @@ depends "kettle"'
 /nodes/mort.json
 EOM
       end
-      it 'knife deps * reports all dependencies of all things' do
-        knife('deps /nodes/*').should_succeed <<EOM
+      it "knife deps * reports all dependencies of all things" do
+        knife("deps /nodes/*").should_succeed <<EOM
 /roles/minor.json
 /nodes/bart.json
 /environments/desert.json
@@ -168,8 +168,8 @@ EOM
 /nodes/mort.json
 EOM
       end
-      it 'knife deps a b reports all dependencies of a and b' do
-        knife('deps /nodes/bart.json /nodes/mort.json').should_succeed <<EOM
+      it "knife deps a b reports all dependencies of a and b" do
+        knife("deps /nodes/bart.json /nodes/mort.json").should_succeed <<EOM
 /roles/minor.json
 /nodes/bart.json
 /environments/desert.json
@@ -179,8 +179,8 @@ EOM
 /nodes/mort.json
 EOM
       end
-      it 'knife deps --tree /* shows dependencies in a tree' do
-        knife('deps --tree /nodes/*').should_succeed <<EOM
+      it "knife deps --tree /* shows dependencies in a tree" do
+        knife("deps --tree /nodes/*").should_succeed <<EOM
 /nodes/bart.json
   /roles/minor.json
 /nodes/mort.json
@@ -191,8 +191,8 @@ EOM
     /cookbooks/soup
 EOM
       end
-      it 'knife deps --tree --no-recurse shows only the first level of dependencies' do
-        knife('deps --tree --no-recurse /nodes/*').should_succeed <<EOM
+      it "knife deps --tree --no-recurse shows only the first level of dependencies" do
+        knife("deps --tree --no-recurse /nodes/*").should_succeed <<EOM
 /nodes/bart.json
   /roles/minor.json
 /nodes/mort.json
@@ -202,55 +202,49 @@ EOM
       end
     end
 
-    context 'circular dependencies' do
-      when_the_repository 'has cookbooks with circular dependencies' do
+    context "circular dependencies" do
+      when_the_repository "has cookbooks with circular dependencies" do
         before do
-          file 'cookbooks/foo/metadata.rb', 'name "foo"
+          file "cookbooks/foo/metadata.rb", 'name "foo"
 depends "bar"'
-          file 'cookbooks/bar/metadata.rb', 'name "bar"
+          file "cookbooks/bar/metadata.rb", 'name "bar"
 depends "baz"'
-          file 'cookbooks/baz/metadata.rb', 'name "baz"
+          file "cookbooks/baz/metadata.rb", 'name "baz"
 depends "foo"'
-          file 'cookbooks/self/metadata.rb', 'name "self"
+          file "cookbooks/self/metadata.rb", 'name "self"
 depends "self"'
         end
 
-        it 'knife deps prints each once' do
-          knife('deps /cookbooks/foo /cookbooks/self').should_succeed <<EOM
-/cookbooks/baz
-/cookbooks/bar
-/cookbooks/foo
-/cookbooks/self
-EOM
+        it "knife deps prints each once" do
+          knife("deps /cookbooks/foo /cookbooks/self").should_succeed(
+            stdout: "/cookbooks/baz\n/cookbooks/bar\n/cookbooks/foo\n/cookbooks/self\n",
+            stderr: "WARN: Ignoring self-dependency in cookbook self, please remove it (in the future this will be fatal).\n",
+          )
         end
-        it 'knife deps --tree prints each once' do
-          knife('deps --tree /cookbooks/foo /cookbooks/self').should_succeed <<EOM
-/cookbooks/foo
-  /cookbooks/bar
-    /cookbooks/baz
-      /cookbooks/foo
-/cookbooks/self
-  /cookbooks/self
-EOM
+        it "knife deps --tree prints each once" do
+          knife("deps --tree /cookbooks/foo /cookbooks/self").should_succeed(
+            stdout: "/cookbooks/foo\n  /cookbooks/bar\n    /cookbooks/baz\n      /cookbooks/foo\n/cookbooks/self\n",
+            stderr: "WARN: Ignoring self-dependency in cookbook self, please remove it (in the future this will be fatal).\n",
+          )
         end
       end
-      when_the_repository 'has roles with circular dependencies' do
+      when_the_repository "has roles with circular dependencies" do
         before do
-          file 'roles/foo.json', { 'run_list' => [ 'role[bar]' ] }
-          file 'roles/bar.json', { 'run_list' => [ 'role[baz]' ] }
-          file 'roles/baz.json', { 'run_list' => [ 'role[foo]' ] }
-          file 'roles/self.json', { 'run_list' => [ 'role[self]' ] }
+          file "roles/foo.json", { "run_list" => [ "role[bar]" ] }
+          file "roles/bar.json", { "run_list" => [ "role[baz]" ] }
+          file "roles/baz.json", { "run_list" => [ "role[foo]" ] }
+          file "roles/self.json", { "run_list" => [ "role[self]" ] }
         end
-        it 'knife deps prints each once' do
-          knife('deps /roles/foo.json /roles/self.json').should_succeed <<EOM
+        it "knife deps prints each once" do
+          knife("deps /roles/foo.json /roles/self.json").should_succeed <<EOM
 /roles/baz.json
 /roles/bar.json
 /roles/foo.json
 /roles/self.json
 EOM
         end
-        it 'knife deps --tree prints each once' do
-          knife('deps --tree /roles/foo.json /roles/self.json') do
+        it "knife deps --tree prints each once" do
+          knife("deps --tree /roles/foo.json /roles/self.json") do
             expect(stdout).to eq("/roles/foo.json\n  /roles/bar.json\n    /roles/baz.json\n      /roles/foo.json\n/roles/self.json\n  /roles/self.json\n")
             expect(stderr).to eq("WARNING: No knife configuration file found\n")
           end
@@ -258,111 +252,111 @@ EOM
       end
     end
 
-    context 'missing objects' do
-      when_the_repository 'is empty' do
-        it 'knife deps /blah reports an error' do
-          knife('deps /blah').should_fail(
+    context "missing objects" do
+      when_the_repository "is empty" do
+        it "knife deps /blah reports an error" do
+          knife("deps /blah").should_fail(
             :exit_code => 2,
             :stdout => "/blah\n",
-            :stderr => "ERROR: /blah: No such file or directory\n"
+            :stderr => "ERROR: /blah: No such file or directory\n",
           )
         end
-        it 'knife deps /roles/x.json reports an error' do
-          knife('deps /roles/x.json').should_fail(
+        it "knife deps /roles/x.json reports an error" do
+          knife("deps /roles/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/roles/x.json\n",
-            :stderr => "ERROR: /roles/x.json: No such file or directory\n"
+            :stderr => "ERROR: /roles/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /nodes/x.json reports an error' do
-          knife('deps /nodes/x.json').should_fail(
+        it "knife deps /nodes/x.json reports an error" do
+          knife("deps /nodes/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/nodes/x.json\n",
-            :stderr => "ERROR: /nodes/x.json: No such file or directory\n"
+            :stderr => "ERROR: /nodes/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /environments/x.json reports an error' do
-          knife('deps /environments/x.json').should_fail(
+        it "knife deps /environments/x.json reports an error" do
+          knife("deps /environments/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/environments/x.json\n",
-            :stderr => "ERROR: /environments/x.json: No such file or directory\n"
+            :stderr => "ERROR: /environments/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /cookbooks/x reports an error' do
-          knife('deps /cookbooks/x').should_fail(
+        it "knife deps /cookbooks/x reports an error" do
+          knife("deps /cookbooks/x").should_fail(
             :exit_code => 2,
             :stdout => "/cookbooks/x\n",
-            :stderr => "ERROR: /cookbooks/x: No such file or directory\n"
+            :stderr => "ERROR: /cookbooks/x: No such file or directory\n",
           )
         end
-        it 'knife deps /data_bags/bag/item reports an error' do
-          knife('deps /data_bags/bag/item').should_fail(
+        it "knife deps /data_bags/bag/item reports an error" do
+          knife("deps /data_bags/bag/item").should_fail(
             :exit_code => 2,
             :stdout => "/data_bags/bag/item\n",
-            :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n"
+            :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n",
           )
         end
       end
-      when_the_repository 'is missing a dependent cookbook' do
+      when_the_repository "is missing a dependent cookbook" do
         before do
-          file 'roles/starring.json', { 'run_list' => [ 'recipe[quiche]'] }
+          file "roles/starring.json", { "run_list" => [ "recipe[quiche]"] }
         end
-        it 'knife deps reports the cookbook, along with an error' do
-          knife('deps /roles/starring.json').should_fail(
+        it "knife deps reports the cookbook, along with an error" do
+          knife("deps /roles/starring.json").should_fail(
             :exit_code => 2,
             :stdout => "/cookbooks/quiche\n/roles/starring.json\n",
-            :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n"
+            :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n",
           )
         end
       end
-      when_the_repository 'is missing a dependent environment' do
+      when_the_repository "is missing a dependent environment" do
         before do
-          file 'nodes/mort.json', { 'chef_environment' => 'desert' }
+          file "nodes/mort.json", { "chef_environment" => "desert" }
         end
-        it 'knife deps reports the environment, along with an error' do
-          knife('deps /nodes/mort.json').should_fail(
+        it "knife deps reports the environment, along with an error" do
+          knife("deps /nodes/mort.json").should_fail(
             :exit_code => 2,
             :stdout => "/environments/desert.json\n/nodes/mort.json\n",
-            :stderr => "ERROR: /environments/desert.json: No such file or directory\n"
+            :stderr => "ERROR: /environments/desert.json: No such file or directory\n",
           )
         end
       end
-      when_the_repository 'is missing a dependent role' do
+      when_the_repository "is missing a dependent role" do
         before do
-          file 'roles/starring.json', { 'run_list' => [ 'role[minor]'] }
+          file "roles/starring.json", { "run_list" => [ "role[minor]"] }
         end
-        it 'knife deps reports the role, along with an error' do
-          knife('deps /roles/starring.json').should_fail(
+        it "knife deps reports the role, along with an error" do
+          knife("deps /roles/starring.json").should_fail(
             :exit_code => 2,
             :stdout => "/roles/minor.json\n/roles/starring.json\n",
-            :stderr => "ERROR: /roles/minor.json: No such file or directory\n"
+            :stderr => "ERROR: /roles/minor.json: No such file or directory\n",
           )
         end
       end
     end
-    context 'invalid objects' do
-      when_the_repository 'is empty' do
-        it 'knife deps / reports itself only' do
-          knife('deps /').should_succeed("/\n")
+    context "invalid objects" do
+      when_the_repository "is empty" do
+        it "knife deps / reports itself only" do
+          knife("deps /").should_succeed("/\n")
         end
-        it 'knife deps /roles reports an error' do
-          knife('deps /roles').should_fail(
+        it "knife deps /roles reports an error" do
+          knife("deps /roles").should_fail(
             :exit_code => 2,
             :stderr => "ERROR: /roles: No such file or directory\n",
-            :stdout => "/roles\n"
+            :stdout => "/roles\n",
           )
         end
       end
-      when_the_repository 'has a data bag' do
-        before { file 'data_bags/bag/item.json', '' }
-        it 'knife deps /data_bags/bag shows no dependencies' do
-          knife('deps /data_bags/bag').should_succeed("/data_bags/bag\n")
+      when_the_repository "has a data bag" do
+        before { file "data_bags/bag/item.json", "" }
+        it "knife deps /data_bags/bag shows no dependencies" do
+          knife("deps /data_bags/bag").should_succeed("/data_bags/bag\n")
         end
       end
-      when_the_repository 'has a cookbook' do
-        before { file 'cookbooks/blah/metadata.rb', 'name "blah"' }
-        it 'knife deps on a cookbook file shows no dependencies' do
-          knife('deps /cookbooks/blah/metadata.rb').should_succeed(
+      when_the_repository "has a cookbook" do
+        before { file "cookbooks/blah/metadata.rb", 'name "blah"' }
+        it "knife deps on a cookbook file shows no dependencies" do
+          knife("deps /cookbooks/blah/metadata.rb").should_succeed(
             "/cookbooks/blah/metadata.rb\n"
           )
         end
@@ -370,25 +364,25 @@ EOM
     end
   end
 
-  context 'remote' do
+  context "remote" do
     include_context "default config options"
 
-    when_the_chef_server 'has a role with no run_list' do
-      before { role 'starring', {} }
-      it 'knife deps reports no dependencies' do
-        knife('deps --remote /roles/starring.json').should_succeed "/roles/starring.json\n"
+    when_the_chef_server "has a role with no run_list" do
+      before { role "starring", {} }
+      it "knife deps reports no dependencies" do
+        knife("deps --remote /roles/starring.json").should_succeed "/roles/starring.json\n"
       end
     end
 
-    when_the_chef_server 'has a role with a default run_list' do
+    when_the_chef_server "has a role with a default run_list" do
       before do
-        role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
-        role 'minor', {}
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
-        cookbook 'soup', '1.0.0', { 'metadata.rb' => %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
+        role "starring", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+        role "minor", {}
+        cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+        cookbook "soup", "1.0.0", { "metadata.rb" => %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
       end
-      it 'knife deps reports all dependencies' do
-        knife('deps --remote /roles/starring.json').should_succeed <<EOM
+      it "knife deps reports all dependencies" do
+        knife("deps --remote /roles/starring.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -397,15 +391,15 @@ EOM
       end
     end
 
-    when_the_chef_server 'has a role with an env_run_list' do
+    when_the_chef_server "has a role with an env_run_list" do
       before do
-        role 'starring', { 'env_run_lists' => { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } }
-        role 'minor', {}
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
-        cookbook 'soup', '1.0.0', { 'metadata.rb' =>   %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
+        role "starring", { "env_run_lists" => { "desert" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} } }
+        role "minor", {}
+        cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+        cookbook "soup", "1.0.0", { "metadata.rb" =>   %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
       end
-      it 'knife deps reports all dependencies' do
-        knife('deps --remote /roles/starring.json').should_succeed <<EOM
+      it "knife deps reports all dependencies" do
+        knife("deps --remote /roles/starring.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -414,30 +408,30 @@ EOM
       end
     end
 
-    when_the_chef_server 'has a node with no environment or run_list' do
-      before { node 'mort', {} }
-      it 'knife deps reports just the node' do
-        knife('deps --remote /nodes/mort.json').should_succeed "/nodes/mort.json\n"
+    when_the_chef_server "has a node with no environment or run_list" do
+      before { node "mort", {} }
+      it "knife deps reports just the node" do
+        knife("deps --remote /nodes/mort.json").should_succeed "/nodes/mort.json\n"
       end
     end
-    when_the_chef_server 'has a node with an environment' do
+    when_the_chef_server "has a node with an environment" do
       before do
-        environment 'desert', {}
-        node 'mort', { 'chef_environment' => 'desert' }
+        environment "desert", {}
+        node "mort", { "chef_environment" => "desert" }
       end
-      it 'knife deps reports just the node' do
-        knife('deps --remote /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n"
+      it "knife deps reports just the node" do
+        knife("deps --remote /nodes/mort.json").should_succeed "/environments/desert.json\n/nodes/mort.json\n"
       end
     end
-    when_the_chef_server 'has a node with roles and recipes in its run_list' do
+    when_the_chef_server "has a node with roles and recipes in its run_list" do
       before do
-        role 'minor', {}
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
-        cookbook 'soup', '1.0.0', { 'metadata.rb' =>   %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
-        node 'mort', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
+        role "minor", {}
+        cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+        cookbook "soup", "1.0.0", { "metadata.rb" =>   %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
+        node "mort", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
       end
-      it 'knife deps reports just the node' do
-        knife('deps --remote /nodes/mort.json').should_succeed <<EOM
+      it "knife deps reports just the node" do
+        knife("deps --remote /nodes/mort.json").should_succeed <<EOM
 /roles/minor.json
 /cookbooks/quiche
 /cookbooks/soup
@@ -445,49 +439,49 @@ EOM
 EOM
       end
     end
-    when_the_chef_server 'has a cookbook with no dependencies' do
+    when_the_chef_server "has a cookbook with no dependencies" do
       before do
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
+        cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
       end
-      it 'knife deps reports just the cookbook' do
-        knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/quiche\n"
+      it "knife deps reports just the cookbook" do
+        knife("deps --remote /cookbooks/quiche").should_succeed "/cookbooks/quiche\n"
       end
     end
-    when_the_chef_server 'has a cookbook with dependencies' do
+    when_the_chef_server "has a cookbook with dependencies" do
       before do
-        cookbook 'kettle', '1.0.0', { 'metadata.rb' => %Q{name "kettle"\nversion "1.0.0"\n} }
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => 'name "quiche"
-depends "kettle"', 'recipes' => { 'default.rb' => '' } }
+        cookbook "kettle", "1.0.0", { "metadata.rb" => %Q{name "kettle"\nversion "1.0.0"\n} }
+        cookbook "quiche", "1.0.0", { "metadata.rb" => 'name "quiche"
+depends "kettle"', "recipes" => { "default.rb" => "" } }
       end
-      it 'knife deps reports the cookbook and its dependencies' do
-        knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
+      it "knife deps reports the cookbook and its dependencies" do
+        knife("deps --remote /cookbooks/quiche").should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n"
       end
     end
-    when_the_chef_server 'has a data bag' do
-      before { data_bag 'bag', { 'item' => {} } }
-      it 'knife deps reports just the data bag' do
-        knife('deps --remote /data_bags/bag/item.json').should_succeed "/data_bags/bag/item.json\n"
+    when_the_chef_server "has a data bag" do
+      before { data_bag "bag", { "item" => {} } }
+      it "knife deps reports just the data bag" do
+        knife("deps --remote /data_bags/bag/item.json").should_succeed "/data_bags/bag/item.json\n"
       end
     end
-    when_the_chef_server 'has an environment' do
-      before { environment 'desert', {} }
-      it 'knife deps reports just the environment' do
-        knife('deps --remote /environments/desert.json').should_succeed "/environments/desert.json\n"
+    when_the_chef_server "has an environment" do
+      before { environment "desert", {} }
+      it "knife deps reports just the environment" do
+        knife("deps --remote /environments/desert.json").should_succeed "/environments/desert.json\n"
       end
     end
-    when_the_chef_server 'has a deep dependency tree' do
+    when_the_chef_server "has a deep dependency tree" do
       before do
-        role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) }
-        role 'minor', {}
-        cookbook 'quiche', '1.0.0', { 'metadata.rb' => %Q{name "quiche"\nversion "1.0.0"\n}, 'recipes' => { 'default.rb' => '' } }
-        cookbook 'soup', '1.0.0', { 'metadata.rb' =>   %Q{name "soup"\nversion "1.0.0"\n}, 'recipes' => { 'chicken.rb' => '' } }
-        environment 'desert', {}
-        node 'mort', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] }
-        node 'bart', { 'run_list' => [ 'role[minor]' ] }
+        role "starring", { "run_list" => %w{role[minor] recipe[quiche] recipe[soup::chicken]} }
+        role "minor", {}
+        cookbook "quiche", "1.0.0", { "metadata.rb" => %Q{name "quiche"\nversion "1.0.0"\n}, "recipes" => { "default.rb" => "" } }
+        cookbook "soup", "1.0.0", { "metadata.rb" =>   %Q{name "soup"\nversion "1.0.0"\n}, "recipes" => { "chicken.rb" => "" } }
+        environment "desert", {}
+        node "mort", { "chef_environment" => "desert", "run_list" => [ "role[starring]" ] }
+        node "bart", { "run_list" => [ "role[minor]" ] }
       end
 
-      it 'knife deps reports all dependencies' do
-        knife('deps --remote /nodes/mort.json').should_succeed <<EOM
+      it "knife deps reports all dependencies" do
+        knife("deps --remote /nodes/mort.json").should_succeed <<EOM
 /environments/desert.json
 /roles/minor.json
 /cookbooks/quiche
@@ -496,8 +490,8 @@ depends "kettle"', 'recipes' => { 'default.rb' => '' } }
 /nodes/mort.json
 EOM
       end
-      it 'knife deps * reports all dependencies of all things' do
-        knife('deps --remote /nodes/*').should_succeed <<EOM
+      it "knife deps * reports all dependencies of all things" do
+        knife("deps --remote /nodes/*").should_succeed <<EOM
 /roles/minor.json
 /nodes/bart.json
 /environments/desert.json
@@ -507,8 +501,8 @@ EOM
 /nodes/mort.json
 EOM
       end
-      it 'knife deps a b reports all dependencies of a and b' do
-        knife('deps --remote /nodes/bart.json /nodes/mort.json').should_succeed <<EOM
+      it "knife deps a b reports all dependencies of a and b" do
+        knife("deps --remote /nodes/bart.json /nodes/mort.json").should_succeed <<EOM
 /roles/minor.json
 /nodes/bart.json
 /environments/desert.json
@@ -518,8 +512,8 @@ EOM
 /nodes/mort.json
 EOM
       end
-      it 'knife deps --tree /* shows dependencies in a tree' do
-        knife('deps --remote --tree /nodes/*').should_succeed <<EOM
+      it "knife deps --tree /* shows dependencies in a tree" do
+        knife("deps --remote --tree /nodes/*").should_succeed <<EOM
 /nodes/bart.json
   /roles/minor.json
 /nodes/mort.json
@@ -530,8 +524,8 @@ EOM
     /cookbooks/soup
 EOM
       end
-      it 'knife deps --tree --no-recurse shows only the first level of dependencies' do
-        knife('deps --remote --tree --no-recurse /nodes/*').should_succeed <<EOM
+      it "knife deps --tree --no-recurse shows only the first level of dependencies" do
+        knife("deps --remote --tree --no-recurse /nodes/*").should_succeed <<EOM
 /nodes/bart.json
   /roles/minor.json
 /nodes/mort.json
@@ -541,28 +535,28 @@ EOM
       end
     end
 
-    context 'circular dependencies' do
-      when_the_chef_server 'has cookbooks with circular dependencies' do
+    context "circular dependencies" do
+      when_the_chef_server "has cookbooks with circular dependencies" do
         before do
-          cookbook 'foo', '1.0.0', { 'metadata.rb'  => 'name "foo"
+          cookbook "foo", "1.0.0", { "metadata.rb"  => 'name "foo"
 depends "bar"' }
-          cookbook 'bar', '1.0.0', { 'metadata.rb'  => 'name "bar"
+          cookbook "bar", "1.0.0", { "metadata.rb"  => 'name "bar"
 depends "baz"' }
-          cookbook 'baz', '1.0.0', { 'metadata.rb'  => 'name "baz"
+          cookbook "baz", "1.0.0", { "metadata.rb"  => 'name "baz"
 depends "foo"' }
-          cookbook 'self', '1.0.0', { 'metadata.rb' => 'name "self"
+          cookbook "self", "1.0.0", { "metadata.rb" => 'name "self"
 depends "self"' }
         end
-        it 'knife deps prints each once' do
-          knife('deps --remote /cookbooks/foo /cookbooks/self').should_succeed <<EOM
+        it "knife deps prints each once" do
+          knife("deps --remote /cookbooks/foo /cookbooks/self").should_succeed <<EOM
 /cookbooks/baz
 /cookbooks/bar
 /cookbooks/foo
 /cookbooks/self
 EOM
         end
-        it 'knife deps --tree prints each once' do
-          knife('deps --remote --tree /cookbooks/foo /cookbooks/self').should_succeed <<EOM
+        it "knife deps --tree prints each once" do
+          knife("deps --remote --tree /cookbooks/foo /cookbooks/self").should_succeed <<EOM
 /cookbooks/foo
   /cookbooks/bar
     /cookbooks/baz
@@ -572,23 +566,23 @@ EOM
 EOM
         end
       end
-      when_the_chef_server 'has roles with circular dependencies' do
+      when_the_chef_server "has roles with circular dependencies" do
         before do
-          role 'foo', { 'run_list' => [ 'role[bar]' ] }
-          role 'bar', { 'run_list' => [ 'role[baz]' ] }
-          role 'baz', { 'run_list' => [ 'role[foo]' ] }
-          role 'self', { 'run_list' => [ 'role[self]' ] }
+          role "foo", { "run_list" => [ "role[bar]" ] }
+          role "bar", { "run_list" => [ "role[baz]" ] }
+          role "baz", { "run_list" => [ "role[foo]" ] }
+          role "self", { "run_list" => [ "role[self]" ] }
         end
-        it 'knife deps prints each once' do
-          knife('deps --remote /roles/foo.json /roles/self.json').should_succeed <<EOM
+        it "knife deps prints each once" do
+          knife("deps --remote /roles/foo.json /roles/self.json").should_succeed <<EOM
 /roles/baz.json
 /roles/bar.json
 /roles/foo.json
 /roles/self.json
 EOM
         end
-        it 'knife deps --tree prints each once' do
-          knife('deps --remote --tree /roles/foo.json /roles/self.json') do
+        it "knife deps --tree prints each once" do
+          knife("deps --remote --tree /roles/foo.json /roles/self.json") do
             expect(stdout).to eq("/roles/foo.json\n  /roles/bar.json\n    /roles/baz.json\n      /roles/foo.json\n/roles/self.json\n  /roles/self.json\n")
             expect(stderr).to eq("WARNING: No knife configuration file found\n")
           end
@@ -596,109 +590,109 @@ EOM
       end
     end
 
-    context 'missing objects' do
-      when_the_chef_server 'is empty' do
-        it 'knife deps /blah reports an error' do
-          knife('deps --remote /blah').should_fail(
+    context "missing objects" do
+      when_the_chef_server "is empty" do
+        it "knife deps /blah reports an error" do
+          knife("deps --remote /blah").should_fail(
             :exit_code => 2,
             :stdout => "/blah\n",
-            :stderr => "ERROR: /blah: No such file or directory\n"
+            :stderr => "ERROR: /blah: No such file or directory\n",
           )
         end
-        it 'knife deps /roles/x.json reports an error' do
-          knife('deps --remote /roles/x.json').should_fail(
+        it "knife deps /roles/x.json reports an error" do
+          knife("deps --remote /roles/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/roles/x.json\n",
-            :stderr => "ERROR: /roles/x.json: No such file or directory\n"
+            :stderr => "ERROR: /roles/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /nodes/x.json reports an error' do
-          knife('deps --remote /nodes/x.json').should_fail(
+        it "knife deps /nodes/x.json reports an error" do
+          knife("deps --remote /nodes/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/nodes/x.json\n",
-            :stderr => "ERROR: /nodes/x.json: No such file or directory\n"
+            :stderr => "ERROR: /nodes/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /environments/x.json reports an error' do
-          knife('deps --remote /environments/x.json').should_fail(
+        it "knife deps /environments/x.json reports an error" do
+          knife("deps --remote /environments/x.json").should_fail(
             :exit_code => 2,
             :stdout => "/environments/x.json\n",
-            :stderr => "ERROR: /environments/x.json: No such file or directory\n"
+            :stderr => "ERROR: /environments/x.json: No such file or directory\n",
           )
         end
-        it 'knife deps /cookbooks/x reports an error' do
-          knife('deps --remote /cookbooks/x').should_fail(
+        it "knife deps /cookbooks/x reports an error" do
+          knife("deps --remote /cookbooks/x").should_fail(
             :exit_code => 2,
             :stdout => "/cookbooks/x\n",
-            :stderr => "ERROR: /cookbooks/x: No such file or directory\n"
+            :stderr => "ERROR: /cookbooks/x: No such file or directory\n",
           )
         end
-        it 'knife deps /data_bags/bag/item reports an error' do
-          knife('deps --remote /data_bags/bag/item').should_fail(
+        it "knife deps /data_bags/bag/item reports an error" do
+          knife("deps --remote /data_bags/bag/item").should_fail(
             :exit_code => 2,
             :stdout => "/data_bags/bag/item\n",
-            :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n"
+            :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n",
           )
         end
       end
-      when_the_chef_server 'is missing a dependent cookbook' do
+      when_the_chef_server "is missing a dependent cookbook" do
         before do
-          role 'starring', { 'run_list' => [ 'recipe[quiche]'] }
+          role "starring", { "run_list" => [ "recipe[quiche]"] }
         end
-        it 'knife deps reports the cookbook, along with an error' do
-          knife('deps --remote /roles/starring.json').should_fail(
+        it "knife deps reports the cookbook, along with an error" do
+          knife("deps --remote /roles/starring.json").should_fail(
             :exit_code => 2,
             :stdout => "/cookbooks/quiche\n/roles/starring.json\n",
-            :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n"
+            :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n",
           )
         end
       end
-      when_the_chef_server 'is missing a dependent environment' do
+      when_the_chef_server "is missing a dependent environment" do
         before do
-          node 'mort', { 'chef_environment' => 'desert' }
+          node "mort", { "chef_environment" => "desert" }
         end
-        it 'knife deps reports the environment, along with an error' do
-          knife('deps --remote /nodes/mort.json').should_fail(
+        it "knife deps reports the environment, along with an error" do
+          knife("deps --remote /nodes/mort.json").should_fail(
             :exit_code => 2,
             :stdout => "/environments/desert.json\n/nodes/mort.json\n",
-            :stderr => "ERROR: /environments/desert.json: No such file or directory\n"
+            :stderr => "ERROR: /environments/desert.json: No such file or directory\n",
           )
         end
       end
-      when_the_chef_server 'is missing a dependent role' do
+      when_the_chef_server "is missing a dependent role" do
         before do
-          role 'starring', { 'run_list' => [ 'role[minor]'] }
+          role "starring", { "run_list" => [ "role[minor]"] }
         end
-        it 'knife deps reports the role, along with an error' do
-          knife('deps --remote /roles/starring.json').should_fail(
+        it "knife deps reports the role, along with an error" do
+          knife("deps --remote /roles/starring.json").should_fail(
             :exit_code => 2,
             :stdout => "/roles/minor.json\n/roles/starring.json\n",
-            :stderr => "ERROR: /roles/minor.json: No such file or directory\n"
+            :stderr => "ERROR: /roles/minor.json: No such file or directory\n",
           )
         end
       end
     end
-    context 'invalid objects' do
-      when_the_chef_server 'is empty' do
-        it 'knife deps / reports an error' do
-          knife('deps --remote /').should_succeed("/\n")
+    context "invalid objects" do
+      when_the_chef_server "is empty" do
+        it "knife deps / reports an error" do
+          knife("deps --remote /").should_succeed("/\n")
         end
-        it 'knife deps /roles reports an error' do
-          knife('deps --remote /roles').should_succeed("/roles\n")
+        it "knife deps /roles reports an error" do
+          knife("deps --remote /roles").should_succeed("/roles\n")
         end
       end
-      when_the_chef_server 'has a data bag' do
-        before { data_bag 'bag', { 'item' => {} } }
-        it 'knife deps /data_bags/bag shows no dependencies' do
-          knife('deps --remote /data_bags/bag').should_succeed("/data_bags/bag\n")
+      when_the_chef_server "has a data bag" do
+        before { data_bag "bag", { "item" => {} } }
+        it "knife deps /data_bags/bag shows no dependencies" do
+          knife("deps --remote /data_bags/bag").should_succeed("/data_bags/bag\n")
         end
       end
-      when_the_chef_server 'has a cookbook' do
+      when_the_chef_server "has a cookbook" do
         before do
-          cookbook 'blah', '1.0.0', { 'metadata.rb' => 'name "blah"' }
+          cookbook "blah", "1.0.0", { "metadata.rb" => 'name "blah"' }
         end
-        it 'knife deps on a cookbook file shows no dependencies' do
-          knife('deps --remote /cookbooks/blah/metadata.rb').should_succeed(
+        it "knife deps on a cookbook file shows no dependencies" do
+          knife("deps --remote /cookbooks/blah/metadata.rb").should_succeed(
             "/cookbooks/blah/metadata.rb\n"
           )
         end
@@ -706,7 +700,7 @@ EOM
     end
   end
 
-  it 'knife deps --no-recurse reports an error' do
-    knife('deps --no-recurse /').should_fail("ERROR: --no-recurse requires --tree\n")
+  it "knife deps --no-recurse reports an error" do
+    knife("deps --no-recurse /").should_fail("ERROR: --no-recurse requires --tree\n")
   end
 end
diff --git a/spec/integration/knife/diff_spec.rb b/spec/integration/knife/diff_spec.rb
index 4653834..b7d2f4d 100644
--- a/spec/integration/knife/diff_spec.rb
+++ b/spec/integration/knife/diff_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,38 +15,38 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/diff'
+require "support/shared/integration/integration_helper"
+require "chef/knife/diff"
 
-describe 'knife diff', :workstation do
+describe "knife diff", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
-  context 'without versioned cookbooks' do
+  context "without versioned cookbooks" do
     when_the_chef_server "has one of each thing" do
       before do
-        client 'x', '{}'
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => '{}' }
-        environment 'x', '{}'
-        node 'x', '{}'
-        role 'x', '{}'
-        user 'x', '{}'
+        client "x", "{}"
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => "{}" }
+        environment "x", "{}"
+        node "x", "{}"
+        role "x", "{}"
+        user "x", "{}"
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
         end
 
-        it 'knife diff reports everything as deleted' do
-          knife('diff --name-status /').should_succeed <<EOM
+        it "knife diff reports everything as deleted" do
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients/chef-validator.json
 D\t/clients/chef-webui.json
 D\t/clients/x.json
@@ -59,68 +59,68 @@ D\t/roles/x.json
 D\t/users/admin.json
 D\t/users/x.json
 EOM
+        end
       end
-    end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
 
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { "description" => "The default Chef environment" }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife diff reports no differences' do
-          knife('diff /').should_succeed ''
+        it "knife diff reports no differences" do
+          knife("diff /").should_succeed ""
         end
 
-        it 'knife diff /environments/nonexistent.json reports an error' do
-          knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
+        it "knife diff /environments/nonexistent.json reports an error" do
+          knife("diff /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
         end
 
-        it 'knife diff /environments/*.txt reports an error' do
-          knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
+        it "knife diff /environments/*.txt reports an error" do
+          knife("diff /environments/*.txt").should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "foo": "bar"
 }
 EOM
           end
 
-          it 'knife diff reports the role as different' do
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife diff reports the role as different" do
+            knife("diff --name-status /").should_succeed <<EOM
 M\t/roles/x.json
 EOM
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "as well as one extra copy of each thing" do
           before do
-            file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-            file 'cookbooks/x/blah.rb', ''
-            file 'cookbooks/y/metadata.rb', cb_metadata("y", "1.0.0")
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+            file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x/blah.rb", ""
+            file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
           end
 
-          it 'knife diff reports the new files as added' do
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife diff reports the new files as added" do
+            knife("diff --name-status /").should_succeed <<EOM
 A\t/clients/y.json
 A\t/cookbooks/x/blah.rb
 A\t/cookbooks/y
@@ -133,16 +133,16 @@ A\t/users/y.json
 EOM
           end
 
-          context 'when cwd is the data_bags directory' do
-            before { cwd 'data_bags' }
-            it 'knife diff reports different data bags' do
-              knife('diff --name-status').should_succeed <<EOM
+          context "when cwd is the data_bags directory" do
+            before { cwd "data_bags" }
+            it "knife diff reports different data bags" do
+              knife("diff --name-status").should_succeed <<EOM
 A\tx/z.json
 A\ty
 EOM
             end
-            it 'knife diff * reports different data bags' do
-              knife('diff --name-status *').should_succeed <<EOM
+            it "knife diff * reports different data bags" do
+              knife("diff --name-status *").should_succeed <<EOM
 A\tx/z.json
 A\ty
 EOM
@@ -151,9 +151,9 @@ EOM
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife diff reports everything as deleted' do
-          knife('diff --name-status /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife diff reports everything as deleted" do
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -166,51 +166,51 @@ EOM
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-        file 'cookbooks/x/onlyin1.0.0.rb', ''
+        file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x/onlyin1.0.0.rb", ""
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
         end
 
-        it 'knife diff /cookbooks/x shows differences' do
-          knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+        it "knife diff /cookbooks/x shows differences" do
+          knife("diff --name-status /cookbooks/x").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
 EOM
         end
 
-        it 'knife diff --diff-filter=MAT does not show deleted files' do
-          knife('diff --diff-filter=MAT --name-status /cookbooks/x').should_succeed <<EOM
+        it "knife diff --diff-filter=MAT does not show deleted files" do
+          knife("diff --diff-filter=MAT --name-status /cookbooks/x").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
 EOM
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
         end
-        it 'knife diff /cookbooks/x shows no differences' do
-          knife('diff --name-status /cookbooks/x').should_succeed ''
+        it "knife diff /cookbooks/x shows no differences" do
+          knife("diff --name-status /cookbooks/x").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
         end
 
-        it 'knife diff /cookbooks/x shows the differences' do
-          knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+        it "knife diff /cookbooks/x shows the differences" do
+          knife("diff --name-status /cookbooks/x").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
@@ -218,13 +218,13 @@ EOM
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
         end
 
-        it 'knife diff /cookbooks/x shows the differences' do
-          knife('diff --name-status /cookbooks/x').should_succeed <<EOM
+        it "knife diff /cookbooks/x shows the differences" do
+          knife("diff --name-status /cookbooks/x").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin0.9.9.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
@@ -233,22 +233,22 @@ EOM
       end
     end
 
-    context 'json diff tests' do
-      when_the_repository 'has an empty environment file' do
+    context "json diff tests" do
+      when_the_repository "has an empty environment file" do
         before do
-          file 'environments/x.json', {}
+          file "environments/x.json", {}
         end
 
-        when_the_chef_server 'has an empty environment' do
-          before { environment 'x', {} }
-          it 'knife diff returns no differences' do
-            knife('diff /environments/x.json').should_succeed ''
+        when_the_chef_server "has an empty environment" do
+          before { environment "x", {} }
+          it "knife diff returns no differences" do
+            knife("diff /environments/x.json").should_succeed ""
           end
         end
-        when_the_chef_server 'has an environment with a different value' do
-          before { environment 'x', { 'description' => 'hi' } }
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+        when_the_chef_server "has an environment with a different value" do
+          before { environment "x", { "description" => "hi" } }
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
 -  "name": "x",
 -  "description": "hi"
@@ -259,26 +259,26 @@ EOM
         end
       end
 
-      when_the_repository 'has an environment file with a value in it' do
+      when_the_repository "has an environment file with a value in it" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
 
-        when_the_chef_server 'has an environment with the same value' do
+        when_the_chef_server "has an environment with the same value" do
           before do
-            environment 'x', { 'description' => 'hi' }
+            environment "x", { "description" => "hi" }
           end
-          it 'knife diff returns no differences' do
-            knife('diff /environments/x.json').should_succeed ''
+          it "knife diff returns no differences" do
+            knife("diff /environments/x.json").should_succeed ""
           end
         end
-        when_the_chef_server 'has an environment with no value' do
+        when_the_chef_server "has an environment with no value" do
           before do
-            environment 'x', {}
+            environment "x", {}
           end
 
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
 -  "name": "x"
 \+  "name": "x",
@@ -287,12 +287,12 @@ EOM
 /)
           end
         end
-        when_the_chef_server 'has an environment with a different value' do
+        when_the_chef_server "has an environment with a different value" do
           before do
-            environment 'x', { 'description' => 'lo' }
+            environment "x", { "description" => "lo" }
           end
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
    "name": "x",
 -  "description": "lo"
@@ -304,14 +304,14 @@ EOM
       end
     end
 
-    when_the_chef_server 'has an environment' do
-      before { environment 'x', {} }
-      when_the_repository 'has an environment with bad JSON' do
-        before { file 'environments/x.json', '{' }
-        it 'knife diff reports an error and does a textual diff' do
+    when_the_chef_server "has an environment" do
+      before { environment "x", {} }
+      when_the_repository "has an environment with bad JSON" do
+        before { file "environments/x.json", "{" }
+        it "knife diff reports an error and does a textual diff" do
           error_text = "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF"
           error_match = Regexp.new(Regexp.escape(error_text))
-          knife('diff /environments/x.json').should_succeed(/-  "name": "x"/, :stderr => error_match)
+          knife("diff /environments/x.json").should_succeed(/-  "name": "x"/, :stderr => error_match)
         end
       end
     end
@@ -320,28 +320,28 @@ EOM
   with_versioned_cookbooks do
     when_the_chef_server "has one of each thing" do
       before do
-        client 'x', '{}'
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => '{}' }
-        environment 'x', '{}'
-        node 'x', '{}'
-        role 'x', '{}'
-        user 'x', '{}'
+        client "x", "{}"
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => "{}" }
+        environment "x", "{}"
+        node "x", "{}"
+        role "x", "{}"
+        user "x", "{}"
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
         end
 
-        it 'knife diff reports everything as deleted' do
-          knife('diff --name-status /').should_succeed <<EOM
+        it "knife diff reports everything as deleted" do
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients/chef-validator.json
 D\t/clients/chef-webui.json
 D\t/clients/x.json
@@ -354,68 +354,68 @@ D\t/roles/x.json
 D\t/users/admin.json
 D\t/users/x.json
 EOM
+        end
       end
-    end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { "description" => "The default Chef environment" }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife diff reports no differences' do
-          knife('diff /').should_succeed ''
+        it "knife diff reports no differences" do
+          knife("diff /").should_succeed ""
         end
 
-        it 'knife diff /environments/nonexistent.json reports an error' do
-          knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
+        it "knife diff /environments/nonexistent.json reports an error" do
+          knife("diff /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n"
         end
 
-        it 'knife diff /environments/*.txt reports an error' do
-          knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
+        it "knife diff /environments/*.txt reports an error" do
+          knife("diff /environments/*.txt").should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n"
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "foo": "bar"
 }
 EOM
           end
 
-          it 'knife diff reports the role as different' do
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife diff reports the role as different" do
+            knife("diff --name-status /").should_succeed <<EOM
 M\t/roles/x.json
 EOM
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "as well as one extra copy of each thing" do
           before do
-            file 'clients/y.json', {}
-            file 'cookbooks/x-1.0.0/blah.rb', ''
-            file 'cookbooks/x-2.0.0/metadata.rb', cb_metadata("x", "2.0.0")
-            file 'cookbooks/y-1.0.0/metadata.rb', cb_metadata("y", "1.0.0")
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', {}
+            file "clients/y.json", {}
+            file "cookbooks/x-1.0.0/blah.rb", ""
+            file "cookbooks/x-2.0.0/metadata.rb", cb_metadata("x", "2.0.0")
+            file "cookbooks/y-1.0.0/metadata.rb", cb_metadata("y", "1.0.0")
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", {}
           end
 
-          it 'knife diff reports the new files as added' do
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife diff reports the new files as added" do
+            knife("diff --name-status /").should_succeed <<EOM
 A\t/clients/y.json
 A\t/cookbooks/x-1.0.0/blah.rb
 A\t/cookbooks/x-2.0.0
@@ -429,16 +429,16 @@ A\t/users/y.json
 EOM
           end
 
-          context 'when cwd is the data_bags directory' do
-            before { cwd 'data_bags' }
-            it 'knife diff reports different data bags' do
-              knife('diff --name-status').should_succeed <<EOM
+          context "when cwd is the data_bags directory" do
+            before { cwd "data_bags" }
+            it "knife diff reports different data bags" do
+              knife("diff --name-status").should_succeed <<EOM
 A\tx/z.json
 A\ty
 EOM
             end
-            it 'knife diff * reports different data bags' do
-              knife('diff --name-status *').should_succeed <<EOM
+            it "knife diff * reports different data bags" do
+              knife("diff --name-status *").should_succeed <<EOM
 A\tx/z.json
 A\ty
 EOM
@@ -447,9 +447,9 @@ EOM
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife diff reports everything as deleted' do
-          knife('diff --name-status /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife diff reports everything as deleted" do
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -462,59 +462,59 @@ EOM
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
-        file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', ''
+        file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x-1.0.0/onlyin1.0.0.rb", ""
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
         end
 
-        it 'knife diff /cookbooks shows differences' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife diff /cookbooks shows differences" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x-1.0.1
 EOM
         end
 
-        it 'knife diff --diff-filter=MAT does not show deleted files' do
-          knife('diff --diff-filter=MAT --name-status /cookbooks').should_succeed ''
+        it "knife diff --diff-filter=MAT does not show deleted files" do
+          knife("diff --diff-filter=MAT --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
         end
-        it 'knife diff /cookbooks shows the differences' do
-          knife('diff --name-status /cookbooks').should_succeed "D\t/cookbooks/x-0.9.9\n"
+        it "knife diff /cookbooks shows the differences" do
+          knife("diff --name-status /cookbooks").should_succeed "D\t/cookbooks/x-0.9.9\n"
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => '' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "" }
         end
 
-        it 'knife diff /cookbooks shows the differences' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife diff /cookbooks shows the differences" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x-1.0.1
 A\t/cookbooks/x-1.0.0
 EOM
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => '' }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "" }
         end
 
-        it 'knife diff /cookbooks shows the differences' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife diff /cookbooks shows the differences" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x-0.9.9
 A\t/cookbooks/x-1.0.0
 EOM
@@ -522,19 +522,19 @@ EOM
       end
     end
 
-    context 'json diff tests' do
-      when_the_repository 'has an empty environment file' do
-        before { file 'environments/x.json', {} }
-        when_the_chef_server 'has an empty environment' do
-          before { environment 'x', {} }
-          it 'knife diff returns no differences' do
-            knife('diff /environments/x.json').should_succeed ''
+    context "json diff tests" do
+      when_the_repository "has an empty environment file" do
+        before { file "environments/x.json", {} }
+        when_the_chef_server "has an empty environment" do
+          before { environment "x", {} }
+          it "knife diff returns no differences" do
+            knife("diff /environments/x.json").should_succeed ""
           end
         end
-        when_the_chef_server 'has an environment with a different value' do
-          before { environment 'x', { 'description' => 'hi' } }
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+        when_the_chef_server "has an environment with a different value" do
+          before { environment "x", { "description" => "hi" } }
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
 -  "name": "x",
 -  "description": "hi"
@@ -545,23 +545,23 @@ EOM
         end
       end
 
-      when_the_repository 'has an environment file with a value in it' do
+      when_the_repository "has an environment file with a value in it" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
 
-        when_the_chef_server 'has an environment with the same value' do
+        when_the_chef_server "has an environment with the same value" do
           before do
-            environment 'x', { 'description' => 'hi' }
+            environment "x", { "description" => "hi" }
           end
-          it 'knife diff returns no differences' do
-            knife('diff /environments/x.json').should_succeed ''
+          it "knife diff returns no differences" do
+            knife("diff /environments/x.json").should_succeed ""
           end
         end
-        when_the_chef_server 'has an environment with no value' do
-          before { environment 'x', {} }
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+        when_the_chef_server "has an environment with no value" do
+          before { environment "x", {} }
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
 -  "name": "x"
 \+  "name": "x",
@@ -570,12 +570,12 @@ EOM
 /)
           end
         end
-        when_the_chef_server 'has an environment with a different value' do
+        when_the_chef_server "has an environment with a different value" do
           before do
-            environment 'x', { 'description' => 'lo' }
+            environment "x", { "description" => "lo" }
           end
-          it 'knife diff reports the difference', :skip => (RUBY_VERSION < "1.9") do
-            knife('diff /environments/x.json').should_succeed(/
+          it "knife diff reports the difference", :skip => (RUBY_VERSION < "1.9") do
+            knife("diff /environments/x.json").should_succeed(/
  {
    "name": "x",
 -  "description": "lo"
@@ -587,14 +587,14 @@ EOM
       end
     end
 
-    when_the_chef_server 'has an environment' do
-      before { environment 'x', {} }
-      when_the_repository 'has an environment with bad JSON' do
-        before { file 'environments/x.json', '{' }
-        it 'knife diff reports an error and does a textual diff' do
+    when_the_chef_server "has an environment" do
+      before { environment "x", {} }
+      when_the_repository "has an environment with bad JSON" do
+        before { file "environments/x.json", "{" }
+        it "knife diff reports an error and does a textual diff" do
           error_text = "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF"
           error_match = Regexp.new(Regexp.escape(error_text))
-          knife('diff /environments/x.json').should_succeed(/-  "name": "x"/, :stderr => error_match)
+          knife("diff /environments/x.json").should_succeed(/-  "name": "x"/, :stderr => error_match)
         end
       end
     end
diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb
index c87e6fe..2c9f64b 100644
--- a/spec/integration/knife/download_spec.rb
+++ b/spec/integration/knife/download_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,40 +15,40 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/download'
-require 'chef/knife/diff'
+require "support/shared/integration/integration_helper"
+require "chef/knife/download"
+require "chef/knife/diff"
 
-describe 'knife download', :workstation do
+describe "knife download", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
-  context 'without versioned cookbooks' do
+  context "without versioned cookbooks" do
     when_the_chef_server "has one of each thing" do
 
       before do
-        client 'x', {}
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => {} }
-        environment 'x', {}
-        node 'x', {}
-        role 'x', {}
-        user 'x', {}
+        client "x", {}
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => {} }
+        environment "x", {}
+        node "x", {}
+        role "x", {}
+        user "x", {}
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
         end
 
-        it 'knife download downloads everything' do
-          knife('download /').should_succeed <<EOM
+        it "knife download downloads everything" do
+          knife("download /").should_succeed <<EOM
 Created /clients/chef-validator.json
 Created /clients/chef-webui.json
 Created /clients/x.json
@@ -63,38 +63,38 @@ Created /roles/x.json
 Created /users/admin.json
 Created /users/x.json
 EOM
-          knife('diff --name-status /').should_succeed ''
+          knife("diff --name-status /").should_succeed ""
         end
       end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { "description" => "The default Chef environment" }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife download makes no changes' do
-          knife('download /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife download makes no changes" do
+          knife("download /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        it 'knife download --purge makes no changes' do
-          knife('download --purge /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife download --purge makes no changes" do
+          knife("download --purge /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "chef_type": "role",
   "default_attributes": {
@@ -113,20 +113,20 @@ EOM
 EOM
           end
 
-          it 'knife download changes the role' do
-            knife('download /').should_succeed "Updated /roles/x.json\n"
-            knife('diff --name-status /').should_succeed ''
+          it "knife download changes the role" do
+            knife("download /").should_succeed "Updated /roles/x.json\n"
+            knife("diff --name-status /").should_succeed ""
           end
 
-          it 'knife download --no-diff does not change the role' do
-            knife('download --no-diff /').should_succeed ''
-            knife('diff --name-status /').should_succeed "M\t/roles/x.json\n"
+          it "knife download --no-diff does not change the role" do
+            knife("download --no-diff /").should_succeed ""
+            knife("diff --name-status /").should_succeed "M\t/roles/x.json\n"
           end
         end
 
-        context 'except the role file is textually different, but not ACTUALLY different' do
+        context "except the role file is textually different, but not ACTUALLY different" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "chef_type": "role",
   "default_attributes": {
@@ -145,28 +145,28 @@ EOM
 EOM
           end
 
-          it 'knife download / does not change anything' do
-            knife('download /').should_succeed ''
-            knife('diff --name-status /').should_succeed ''
+          it "knife download / does not change anything" do
+            knife("download /").should_succeed ""
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "as well as one extra copy of each thing" do
           before do
-            file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-            file 'cookbooks/x/blah.rb', ''
-            file 'cookbooks/y/metadata.rb', cb_metadata("x", "1.0.0")
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+            file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x/blah.rb", ""
+            file "cookbooks/y/metadata.rb", cb_metadata("x", "1.0.0")
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
           end
 
-          it 'knife download does nothing' do
-            knife('download /').should_succeed ''
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife download does nothing" do
+            knife("download /").should_succeed ""
+            knife("diff --name-status /").should_succeed <<EOM
 A\t/clients/y.json
 A\t/cookbooks/x/blah.rb
 A\t/cookbooks/y
@@ -179,8 +179,8 @@ A\t/users/y.json
 EOM
           end
 
-          it 'knife download --purge deletes the extra files' do
-            knife('download --purge /').should_succeed <<EOM
+          it "knife download --purge deletes the extra files" do
+            knife("download --purge /").should_succeed <<EOM
 Deleted extra entry /clients/y.json (purge is on)
 Deleted extra entry /cookbooks/x/blah.rb (purge is on)
 Deleted extra entry /cookbooks/y (purge is on)
@@ -191,14 +191,14 @@ Deleted extra entry /nodes/y.json (purge is on)
 Deleted extra entry /roles/y.json (purge is on)
 Deleted extra entry /users/y.json (purge is on)
 EOM
-            knife('diff --name-status /').should_succeed ''
+            knife("diff --name-status /").should_succeed ""
           end
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife download creates the extra files' do
-          knife('download /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife download creates the extra files" do
+          knife("download /").should_succeed <<EOM
 Created /clients
 Created /clients/chef-validator.json
 Created /clients/chef-webui.json
@@ -220,11 +220,11 @@ Created /users
 Created /users/admin.json
 Created /users/x.json
 EOM
-          knife('diff --name-status /').should_succeed ''
+          knife("diff --name-status /").should_succeed ""
         end
 
-        it 'knife download --no-diff creates the extra files' do
-          knife('download --no-diff /').should_succeed <<EOM
+        it "knife download --no-diff creates the extra files" do
+          knife("download --no-diff /").should_succeed <<EOM
 Created /clients
 Created /clients/chef-validator.json
 Created /clients/chef-webui.json
@@ -246,41 +246,41 @@ Created /users
 Created /users/admin.json
 Created /users/x.json
 EOM
-          knife('diff --name-status /').should_succeed ''
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'when current directory is top level' do
+        context "when current directory is top level" do
           before do
-            cwd '.'
+            cwd "."
           end
 
-          it 'knife download with no parameters reports an error' do
-            knife('download').should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+          it "knife download with no parameters reports an error" do
+            knife("download").should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
           end
         end
       end
     end
 
     # Test download of an item when the other end doesn't even have the container
-    when_the_repository 'is empty' do
-      when_the_chef_server 'has two data bag items' do
+    when_the_repository "is empty" do
+      when_the_chef_server "has two data bag items" do
         before do
-          data_bag 'x', { 'y' => {}, 'z' => {} }
+          data_bag "x", { "y" => {}, "z" => {} }
         end
 
-        it 'knife download of one data bag item itself succeeds' do
-          knife('download /data_bags/x/y.json').should_succeed <<EOM
+        it "knife download of one data bag item itself succeeds" do
+          knife("download /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/z.json
 EOM
         end
 
-        it 'knife download /data_bags/x /data_bags/x/y.json downloads x once' do
-          knife('download /data_bags/x /data_bags/x/y.json').should_succeed <<EOM
+        it "knife download /data_bags/x /data_bags/x/y.json downloads x once" do
+          knife("download /data_bags/x /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags
 Created /data_bags/x
 Created /data_bags/x/y.json
@@ -290,285 +290,285 @@ EOM
       end
     end
 
-    when_the_repository 'has three data bag items' do
+    when_the_repository "has three data bag items" do
       before do
-        file 'data_bags/x/deleted.json', <<EOM
+        file "data_bags/x/deleted.json", <<EOM
 {
   "id": "deleted"
 }
 EOM
-        file 'data_bags/x/modified.json', <<EOM
+        file "data_bags/x/modified.json", <<EOM
 {
   "id": "modified"
 }
 EOM
-        file 'data_bags/x/unmodified.json', <<EOM
+        file "data_bags/x/unmodified.json", <<EOM
 {
   "id": "unmodified"
 }
 EOM
       end
 
-      when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do
+      when_the_chef_server "has a modified, unmodified, added and deleted data bag item" do
         before do
-          data_bag 'x', {
-            'added' => {},
-            'modified' => { 'foo' => 'bar' },
-            'unmodified' => {}
+          data_bag "x", {
+            "added" => {},
+            "modified" => { "foo" => "bar" },
+            "unmodified" => {},
           }
         end
 
-        it 'knife download of the modified file succeeds' do
-          knife('download /data_bags/x/modified.json').should_succeed <<EOM
+        it "knife download of the modified file succeeds" do
+          knife("download /data_bags/x/modified.json").should_succeed <<EOM
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the unmodified file does nothing' do
-          knife('download /data_bags/x/unmodified.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife download of the unmodified file does nothing" do
+          knife("download /data_bags/x/unmodified.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the added file succeeds' do
-          knife('download /data_bags/x/added.json').should_succeed <<EOM
+        it "knife download of the added file succeeds" do
+          knife("download /data_bags/x/added.json").should_succeed <<EOM
 Created /data_bags/x/added.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the deleted file does nothing' do
-          knife('download /data_bags/x/deleted.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife download of the deleted file does nothing" do
+          knife("download /data_bags/x/deleted.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download --purge of the deleted file deletes it' do
-          knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM
+        it "knife download --purge of the deleted file deletes it" do
+          knife("download --purge /data_bags/x/deleted.json").should_succeed <<EOM
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 EOM
         end
-        it 'knife download of the entire data bag downloads everything' do
-          knife('download /data_bags/x').should_succeed <<EOM
+        it "knife download of the entire data bag downloads everything" do
+          knife("download /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download --purge of the entire data bag downloads everything' do
-          knife('download --purge /data_bags/x').should_succeed <<EOM
+        it "knife download --purge of the entire data bag downloads everything" do
+          knife("download --purge /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed ''
+          knife("diff --name-status /data_bags").should_succeed ""
         end
-        context 'when cwd is the /data_bags directory' do
+        context "when cwd is the /data_bags directory" do
           before do
-            cwd 'data_bags'
+            cwd "data_bags"
           end
-          it 'knife download fails' do
-            knife('download').should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+          it "knife download fails" do
+            knife("download").should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
           end
-          it 'knife download --purge . downloads everything' do
-            knife('download --purge .').should_succeed <<EOM
+          it "knife download --purge . downloads everything" do
+            knife("download --purge .").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
-          it 'knife download --purge * downloads everything' do
-            knife('download --purge *').should_succeed <<EOM
+          it "knife download --purge * downloads everything" do
+            knife("download --purge *").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-        file 'cookbooks/x/z.rb', ''
+        file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x/z.rb", ""
       end
 
-      when_the_chef_server 'has a modified, added and deleted file for the cookbook' do
+      when_the_chef_server "has a modified, added and deleted file for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'metadata.rb' => cb_metadata("x", "1.0.0", "#extra content"), 'y.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "metadata.rb" => cb_metadata("x", "1.0.0", "#extra content"), "y.rb" => "hi" }
         end
 
-        it 'knife download of a modified file succeeds' do
-          knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of a modified file succeeds" do
+          knife("download /cookbooks/x/metadata.rb").should_succeed "Updated /cookbooks/x/metadata.rb\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x/y.rb
 A\t/cookbooks/x/z.rb
 EOM
         end
-        it 'knife download of a deleted file does nothing' do
-          knife('download /cookbooks/x/z.rb').should_succeed ''
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of a deleted file does nothing" do
+          knife("download /cookbooks/x/z.rb").should_succeed ""
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/y.rb
 A\t/cookbooks/x/z.rb
 EOM
         end
-        it 'knife download --purge of a deleted file succeeds' do
-          knife('download --purge /cookbooks/x/z.rb').should_succeed "Deleted extra entry /cookbooks/x/z.rb (purge is on)\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download --purge of a deleted file succeeds" do
+          knife("download --purge /cookbooks/x/z.rb").should_succeed "Deleted extra entry /cookbooks/x/z.rb (purge is on)\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/y.rb
 EOM
         end
-        it 'knife download of an added file succeeds' do
-          knife('download /cookbooks/x/y.rb').should_succeed "Created /cookbooks/x/y.rb\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of an added file succeeds" do
+          knife("download /cookbooks/x/y.rb").should_succeed "Created /cookbooks/x/y.rb\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 A\t/cookbooks/x/z.rb
 EOM
         end
-        it 'knife download of the cookbook itself succeeds' do
-          knife('download /cookbooks/x').should_succeed <<EOM
+        it "knife download of the cookbook itself succeeds" do
+          knife("download /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/metadata.rb
 Created /cookbooks/x/y.rb
 EOM
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 A\t/cookbooks/x/z.rb
 EOM
         end
-        it 'knife download --purge of the cookbook itself succeeds' do
-          knife('download --purge /cookbooks/x').should_succeed <<EOM
+        it "knife download --purge of the cookbook itself succeeds" do
+          knife("download --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/metadata.rb
 Created /cookbooks/x/y.rb
 Deleted extra entry /cookbooks/x/z.rb (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-        file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+        file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x/onlyin1.0.0.rb", "old_text"
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the latest version' do
-          knife('download --purge /cookbooks/x').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the latest version" do
+          knife("download --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/metadata.rb
 Created /cookbooks/x/onlyin1.0.1.rb
 Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the updated file' do
-          knife('download --purge /cookbooks/x').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the updated file" do
+          knife("download --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/onlyin1.0.0.rb
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the latest version' do
-          knife('download --purge /cookbooks/x').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the latest version" do
+          knife("download --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/metadata.rb
 Created /cookbooks/x/onlyin1.0.1.rb
 Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the old version' do
-          knife('download --purge /cookbooks/x').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the old version" do
+          knife("download --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x/metadata.rb
 Created /cookbooks/x/onlyin0.9.9.rb
 Deleted extra entry /cookbooks/x/onlyin1.0.0.rb (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'has an environment' do
+    when_the_chef_server "has an environment" do
       before do
-        environment 'x', {}
+        environment "x", {}
       end
-      when_the_repository 'has an environment with bad JSON' do
+      when_the_repository "has an environment with bad JSON" do
         before do
-          file 'environments/x.json', '{'
+          file "environments/x.json", "{"
         end
-        it 'knife download succeeds' do
+        it "knife download succeeds" do
           warning = <<-EOH
 WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF
                                        {
                      (right here) ------^
 
 EOH
-          knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n", :stderr => warning
-          knife('diff --name-status /environments/x.json').should_succeed ''
+          knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n", :stderr => warning
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
 
-      when_the_repository 'has the same environment with the wrong name in the file' do
+      when_the_repository "has the same environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
-        it 'knife download succeeds' do
-          knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife download succeeds" do
+          knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
 
-      when_the_repository 'has the same environment with no name in the file' do
+      when_the_repository "has the same environment with no name in the file" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
-        it 'knife download succeeds' do
-          knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife download succeeds" do
+          knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
     end
@@ -577,28 +577,28 @@ EOH
   with_versioned_cookbooks do
     when_the_chef_server "has one of each thing" do
       before do
-        client 'x', {}
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => {} }
-        environment 'x', {}
-        node 'x', {}
-        role 'x', {}
-        user 'x', {}
+        client "x", {}
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => {} }
+        environment "x", {}
+        node "x", {}
+        role "x", {}
+        user "x", {}
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
         end
 
-        it 'knife download downloads everything' do
-          knife('download /').should_succeed <<EOM
+        it "knife download downloads everything" do
+          knife("download /").should_succeed <<EOM
 Created /clients/chef-validator.json
 Created /clients/chef-webui.json
 Created /clients/x.json
@@ -613,49 +613,49 @@ Created /roles/x.json
 Created /users/admin.json
 Created /users/x.json
 EOM
-          knife('diff --name-status /').should_succeed ''
+          knife("diff --name-status /").should_succeed ""
         end
       end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { "description" => "The default Chef environment" }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife download makes no changes' do
-          knife('download /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife download makes no changes" do
+          knife("download /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        it 'knife download --purge makes no changes' do
-          knife('download --purge /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife download --purge makes no changes" do
+          knife("download --purge /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', { "description" => "blarghle" }
+            file "roles/x.json", { "description" => "blarghle" }
           end
 
-          it 'knife download changes the role' do
-            knife('download /').should_succeed "Updated /roles/x.json\n"
-            knife('diff --name-status /').should_succeed ''
+          it "knife download changes the role" do
+            knife("download /").should_succeed "Updated /roles/x.json\n"
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'except the role file is textually different, but not ACTUALLY different' do
+        context "except the role file is textually different, but not ACTUALLY different" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "chef_type": "role" ,
   "default_attributes": {
@@ -674,29 +674,29 @@ EOM
 EOM
           end
 
-          it 'knife download / does not change anything' do
-            knife('download /').should_succeed ''
-            knife('diff --name-status /').should_succeed ''
+          it "knife download / does not change anything" do
+            knife("download /").should_succeed ""
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "as well as one extra copy of each thing" do
           before do
-            file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-            file 'cookbooks/x-1.0.0/blah.rb', ''
-            file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"'
-            file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"'
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+            file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x-1.0.0/blah.rb", ""
+            file "cookbooks/x-2.0.0/metadata.rb", 'version "2.0.0"'
+            file "cookbooks/y-1.0.0/metadata.rb", 'version "1.0.0"'
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
           end
 
-          it 'knife download does nothing' do
-            knife('download /').should_succeed ''
-            knife('diff --name-status /').should_succeed <<EOM
+          it "knife download does nothing" do
+            knife("download /").should_succeed ""
+            knife("diff --name-status /").should_succeed <<EOM
 A\t/clients/y.json
 A\t/cookbooks/x-1.0.0/blah.rb
 A\t/cookbooks/x-2.0.0
@@ -710,8 +710,8 @@ A\t/users/y.json
 EOM
           end
 
-          it 'knife download --purge deletes the extra files' do
-            knife('download --purge /').should_succeed <<EOM
+          it "knife download --purge deletes the extra files" do
+            knife("download --purge /").should_succeed <<EOM
 Deleted extra entry /clients/y.json (purge is on)
 Deleted extra entry /cookbooks/x-1.0.0/blah.rb (purge is on)
 Deleted extra entry /cookbooks/x-2.0.0 (purge is on)
@@ -723,14 +723,14 @@ Deleted extra entry /nodes/y.json (purge is on)
 Deleted extra entry /roles/y.json (purge is on)
 Deleted extra entry /users/y.json (purge is on)
 EOM
-            knife('diff --name-status /').should_succeed ''
+            knife("diff --name-status /").should_succeed ""
           end
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife download creates the extra files' do
-          knife('download /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife download creates the extra files" do
+          knife("download /").should_succeed <<EOM
 Created /clients
 Created /clients/chef-validator.json
 Created /clients/chef-webui.json
@@ -752,324 +752,324 @@ Created /users
 Created /users/admin.json
 Created /users/x.json
 EOM
-          knife('diff --name-status /').should_succeed ''
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'when current directory is top level' do
+        context "when current directory is top level" do
           before do
-            cwd '.'
+            cwd "."
           end
-          it 'knife download with no parameters reports an error' do
-            knife('download').should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+          it "knife download with no parameters reports an error" do
+            knife("download").should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
           end
         end
       end
     end
 
     # Test download of an item when the other end doesn't even have the container
-    when_the_repository 'is empty' do
-      when_the_chef_server 'has two data bag items' do
+    when_the_repository "is empty" do
+      when_the_chef_server "has two data bag items" do
         before do
-          data_bag 'x', { 'y' => {}, 'z' => {} }
+          data_bag "x", { "y" => {}, "z" => {} }
         end
 
-        it 'knife download of one data bag item itself succeeds' do
-          knife('download /data_bags/x/y.json').should_succeed <<EOM
+        it "knife download of one data bag item itself succeeds" do
+          knife("download /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/z.json
 EOM
         end
       end
     end
 
-    when_the_repository 'has three data bag items' do
+    when_the_repository "has three data bag items" do
       before do
-        file 'data_bags/x/deleted.json', <<EOM
+        file "data_bags/x/deleted.json", <<EOM
 {
   "id": "deleted"
 }
 EOM
-        file 'data_bags/x/modified.json', <<EOM
+        file "data_bags/x/modified.json", <<EOM
 {
   "id": "modified"
 }
 EOM
-        file 'data_bags/x/unmodified.json', <<EOM
+        file "data_bags/x/unmodified.json", <<EOM
 {
   "id": "unmodified"
 }
 EOM
       end
 
-      when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do
+      when_the_chef_server "has a modified, unmodified, added and deleted data bag item" do
         before do
-          data_bag 'x', {
-            'added' => {},
-            'modified' => { 'foo' => 'bar' },
-            'unmodified' => {}
+          data_bag "x", {
+            "added" => {},
+            "modified" => { "foo" => "bar" },
+            "unmodified" => {},
           }
         end
 
-        it 'knife download of the modified file succeeds' do
-          knife('download /data_bags/x/modified.json').should_succeed <<EOM
+        it "knife download of the modified file succeeds" do
+          knife("download /data_bags/x/modified.json").should_succeed <<EOM
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the unmodified file does nothing' do
-          knife('download /data_bags/x/unmodified.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife download of the unmodified file does nothing" do
+          knife("download /data_bags/x/unmodified.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the added file succeeds' do
-          knife('download /data_bags/x/added.json').should_succeed <<EOM
+        it "knife download of the added file succeeds" do
+          knife("download /data_bags/x/added.json").should_succeed <<EOM
 Created /data_bags/x/added.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download of the deleted file does nothing' do
-          knife('download /data_bags/x/deleted.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife download of the deleted file does nothing" do
+          knife("download /data_bags/x/deleted.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download --purge of the deleted file deletes it' do
-          knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM
+        it "knife download --purge of the deleted file deletes it" do
+          knife("download --purge /data_bags/x/deleted.json").should_succeed <<EOM
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/added.json
 M\t/data_bags/x/modified.json
 EOM
         end
-        it 'knife download of the entire data bag downloads everything' do
-          knife('download /data_bags/x').should_succeed <<EOM
+        it "knife download of the entire data bag downloads everything" do
+          knife("download /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 A\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife download --purge of the entire data bag downloads everything' do
-          knife('download --purge /data_bags/x').should_succeed <<EOM
+        it "knife download --purge of the entire data bag downloads everything" do
+          knife("download --purge /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed ''
+          knife("diff --name-status /data_bags").should_succeed ""
         end
-        context 'when cwd is the /data_bags directory' do
+        context "when cwd is the /data_bags directory" do
           before do
-            cwd 'data_bags'
+            cwd "data_bags"
           end
-          it 'knife download fails' do
-            knife('download').should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
+          it "knife download fails" do
+            knife("download").should_fail "FATAL: Must specify at least one argument.  If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
           end
-          it 'knife download --purge . downloads everything' do
-            knife('download --purge .').should_succeed <<EOM
+          it "knife download --purge . downloads everything" do
+            knife("download --purge .").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
-          it 'knife download --purge * downloads everything' do
-            knife('download --purge *').should_succeed <<EOM
+          it "knife download --purge * downloads everything" do
+            knife("download --purge *").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x-1.0.0/metadata.rb', 'name "x"; version "1.0.0"#unmodified'
-        file 'cookbooks/x-1.0.0/z.rb', ''
+        file "cookbooks/x-1.0.0/metadata.rb", 'name "x"; version "1.0.0"#unmodified'
+        file "cookbooks/x-1.0.0/z.rb", ""
       end
 
-      when_the_chef_server 'has a modified, added and deleted file for the cookbook' do
+      when_the_chef_server "has a modified, added and deleted file for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'y.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "y.rb" => "hi" }
         end
 
-        it 'knife download of a modified file succeeds' do
-          knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of a modified file succeeds" do
+          knife("download /cookbooks/x-1.0.0/metadata.rb").should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x-1.0.0/y.rb
 A\t/cookbooks/x-1.0.0/z.rb
 EOM
         end
-        it 'knife download of a deleted file does nothing' do
-          knife('download /cookbooks/x-1.0.0/z.rb').should_succeed ''
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of a deleted file does nothing" do
+          knife("download /cookbooks/x-1.0.0/z.rb").should_succeed ""
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x-1.0.0/metadata.rb
 D\t/cookbooks/x-1.0.0/y.rb
 A\t/cookbooks/x-1.0.0/z.rb
 EOM
         end
-        it 'knife download --purge of a deleted file succeeds' do
-          knife('download --purge /cookbooks/x-1.0.0/z.rb').should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download --purge of a deleted file succeeds" do
+          knife("download --purge /cookbooks/x-1.0.0/z.rb").should_succeed "Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x-1.0.0/metadata.rb
 D\t/cookbooks/x-1.0.0/y.rb
 EOM
         end
-        it 'knife download of an added file succeeds' do
-          knife('download /cookbooks/x-1.0.0/y.rb').should_succeed "Created /cookbooks/x-1.0.0/y.rb\n"
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife download of an added file succeeds" do
+          knife("download /cookbooks/x-1.0.0/y.rb").should_succeed "Created /cookbooks/x-1.0.0/y.rb\n"
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x-1.0.0/metadata.rb
 A\t/cookbooks/x-1.0.0/z.rb
 EOM
         end
-        it 'knife download of the cookbook itself succeeds' do
-          knife('download /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife download of the cookbook itself succeeds" do
+          knife("download /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0/metadata.rb
 Created /cookbooks/x-1.0.0/y.rb
 EOM
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 A\t/cookbooks/x-1.0.0/z.rb
 EOM
         end
-        it 'knife download --purge of the cookbook itself succeeds' do
-          knife('download --purge /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife download --purge of the cookbook itself succeeds" do
+          knife("download --purge /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0/metadata.rb
 Created /cookbooks/x-1.0.0/y.rb
 Deleted extra entry /cookbooks/x-1.0.0/z.rb (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata("x", "1.0.0")
-        file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text'
+        file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x-1.0.0/onlyin1.0.0.rb", "old_text"
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the latest version' do
-          knife('download --purge /cookbooks').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the latest version" do
+          knife("download --purge /cookbooks").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0/onlyin1.0.0.rb
 Created /cookbooks/x-1.0.1
 Created /cookbooks/x-1.0.1/metadata.rb
 Created /cookbooks/x-1.0.1/onlyin1.0.1.rb
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks downloads the updated file' do
-          knife('download --purge /cookbooks').should_succeed <<EOM
+        it "knife download /cookbooks downloads the updated file" do
+          knife("download --purge /cookbooks").should_succeed <<EOM
 Created /cookbooks/x-0.9.9
 Created /cookbooks/x-0.9.9/metadata.rb
 Created /cookbooks/x-0.9.9/onlyin0.9.9.rb
 Updated /cookbooks/x-1.0.0/onlyin1.0.0.rb
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife download /cookbooks/x downloads the latest version' do
-          knife('download --purge /cookbooks').should_succeed <<EOM
+        it "knife download /cookbooks/x downloads the latest version" do
+          knife("download --purge /cookbooks").should_succeed <<EOM
 Created /cookbooks/x-1.0.1
 Created /cookbooks/x-1.0.1/metadata.rb
 Created /cookbooks/x-1.0.1/onlyin1.0.1.rb
 Deleted extra entry /cookbooks/x-1.0.0 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife download --purge /cookbooks downloads the old version and deletes the new version' do
-          knife('download --purge /cookbooks').should_succeed <<EOM
+        it "knife download --purge /cookbooks downloads the old version and deletes the new version" do
+          knife("download --purge /cookbooks").should_succeed <<EOM
 Created /cookbooks/x-0.9.9
 Created /cookbooks/x-0.9.9/metadata.rb
 Created /cookbooks/x-0.9.9/onlyin0.9.9.rb
 Deleted extra entry /cookbooks/x-1.0.0 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'has an environment' do
+    when_the_chef_server "has an environment" do
       before do
-        environment 'x', {}
+        environment "x", {}
       end
 
-      when_the_repository 'has the same environment with the wrong name in the file' do
+      when_the_repository "has the same environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
 
-        it 'knife download succeeds' do
-          knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife download succeeds" do
+          knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
 
-      when_the_repository 'has the same environment with no name in the file' do
+      when_the_repository "has the same environment with no name in the file" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
 
-        it 'knife download succeeds' do
-          knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife download succeeds" do
+          knife("download /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
     end
   end # with versioned cookbooks
 
-  when_the_chef_server 'has a cookbook' do
+  when_the_chef_server "has a cookbook" do
     before do
-      cookbook 'x', '1.0.0'
+      cookbook "x", "1.0.0"
     end
 
-    when_the_repository 'is empty' do
-      it 'knife download /cookbooks/x signs all requests' do
+    when_the_repository "is empty" do
+      it "knife download /cookbooks/x signs all requests" do
 
         # Check that BasicClient.request() always gets called with X-OPS-USERID
         original_new = Chef::HTTP::BasicClient.method(:new)
@@ -1077,13 +1077,13 @@ EOM
           new_result = original_new.call(*args)
           original_request = new_result.method(:request)
           expect(new_result).to receive(:request) { |method, url, body, headers, &response_handler|
-            expect(headers['X-OPS-USERID']).not_to be_nil
+            expect(headers["X-OPS-USERID"]).not_to be_nil
             original_request.call(method, url, body, headers, &response_handler)
           }.at_least(:once)
           new_result
         }.at_least(:once)
 
-        knife('download /cookbooks/x').should_succeed <<EOM
+        knife("download /cookbooks/x").should_succeed <<EOM
 Created /cookbooks
 Created /cookbooks/x
 Created /cookbooks/x/metadata.rb
@@ -1094,33 +1094,36 @@ EOM
 
   when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
     before do
-      organization 'foo' do
-        container 'x', {}
-        group 'x', {}
-      end
+      user "foo", {}
+      user "bar", {}
+      user "foobar", {}
+      organization "foo", { "full_name" => "Something" }
     end
 
     before :each do
-      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
     end
 
-    when_the_repository 'is empty' do
-      it 'knife download / downloads everything' do
-        knife('download /').should_succeed <<EOM
+    when_the_repository "has all the default stuff" do
+      before do
+        knife("download /").should_succeed <<EOM
 Created /acls
 Created /acls/clients
 Created /acls/clients/foo-validator.json
 Created /acls/containers
 Created /acls/containers/clients.json
 Created /acls/containers/containers.json
+Created /acls/containers/cookbook_artifacts.json
 Created /acls/containers/cookbooks.json
 Created /acls/containers/data.json
 Created /acls/containers/environments.json
 Created /acls/containers/groups.json
 Created /acls/containers/nodes.json
+Created /acls/containers/policies.json
+Created /acls/containers/policy_groups.json
 Created /acls/containers/roles.json
 Created /acls/containers/sandboxes.json
-Created /acls/containers/x.json
+Created /acls/cookbook_artifacts
 Created /acls/cookbooks
 Created /acls/data_bags
 Created /acls/environments
@@ -1130,8 +1133,9 @@ Created /acls/groups/admins.json
 Created /acls/groups/billing-admins.json
 Created /acls/groups/clients.json
 Created /acls/groups/users.json
-Created /acls/groups/x.json
 Created /acls/nodes
+Created /acls/policies
+Created /acls/policy_groups
 Created /acls/roles
 Created /acls/organization.json
 Created /clients
@@ -1139,14 +1143,17 @@ Created /clients/foo-validator.json
 Created /containers
 Created /containers/clients.json
 Created /containers/containers.json
+Created /containers/cookbook_artifacts.json
 Created /containers/cookbooks.json
 Created /containers/data.json
 Created /containers/environments.json
 Created /containers/groups.json
 Created /containers/nodes.json
+Created /containers/policies.json
+Created /containers/policy_groups.json
 Created /containers/roles.json
 Created /containers/sandboxes.json
-Created /containers/x.json
+Created /cookbook_artifacts
 Created /cookbooks
 Created /data_bags
 Created /environments
@@ -1156,14 +1163,151 @@ Created /groups/admins.json
 Created /groups/billing-admins.json
 Created /groups/clients.json
 Created /groups/users.json
-Created /groups/x.json
 Created /invitations.json
 Created /members.json
 Created /nodes
 Created /org.json
+Created /policies
+Created /policy_groups
 Created /roles
 EOM
-        knife('diff --name-status /').should_succeed ''
+      end
+
+      context "and the server has one of each thing" do
+        before do
+          # acl_for %w(organizations foo groups blah)
+          client "x", {}
+          cookbook "x", "1.0.0"
+          cookbook_artifact "x", "1x1", { "metadata.rb" => cb_metadata("x", "1.0.0") }
+          container "x", {}
+          data_bag "x", { "y" => {} }
+          environment "x", {}
+          group "x", {}
+          org_invite "foo"
+          org_member "bar"
+          node "x", {}
+          policy "x", "1.0.0", {}
+          policy "blah", "1.0.0", {}
+          policy_group "x", {
+            "policies" => {
+              "x" => { "revision_id" => "1.0.0" },
+              "blah" => { "revision_id" => "1.0.0" },
+            }
+          }
+          role "x", {}
+        end
+
+        before do
+          knife("download /acls /groups/clients.json /groups/users.json").should_succeed <<-EOM
+Created /acls/clients/x.json
+Created /acls/containers/x.json
+Created /acls/cookbook_artifacts/x.json
+Created /acls/cookbooks/x.json
+Created /acls/data_bags/x.json
+Created /acls/environments/x.json
+Created /acls/groups/x.json
+Created /acls/nodes/x.json
+Created /acls/policies/blah.json
+Created /acls/policies/x.json
+Created /acls/policy_groups/x.json
+Created /acls/roles/x.json
+Updated /groups/clients.json
+Updated /groups/users.json
+EOM
+        end
+
+        it "knife download / downloads everything" do
+          knife("download /").should_succeed <<EOM
+Created /clients/x.json
+Created /containers/x.json
+Created /cookbook_artifacts/x-1x1
+Created /cookbook_artifacts/x-1x1/metadata.rb
+Created /cookbooks/x
+Created /cookbooks/x/metadata.rb
+Created /data_bags/x
+Created /data_bags/x/y.json
+Created /environments/x.json
+Created /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Created /nodes/x.json
+Created /policies/blah-1.0.0.json
+Created /policies/x-1.0.0.json
+Created /policy_groups/x.json
+Created /roles/x.json
+EOM
+          knife("diff --name-status /").should_succeed ""
+        end
+
+        context "and the repository has an identical copy of each thing" do
+          before do
+            # TODO We have to upload acls for an existing group due to a lack of
+            # dependency detection during upload.  Fix that!
+            file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "containers/x.json", {}
+            file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+            file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.0")
+            file "data_bags/x/y.json", {}
+            file "environments/x.json", {}
+            file "groups/x.json", {}
+            file "invitations.json", [ "foo" ]
+            file "members.json", [ "bar" ]
+            file "nodes/x.json", {}
+            file "org.json", { "full_name" => "Something" }
+            file "policies/x-1.0.0.json", {}
+            file "policies/blah-1.0.0.json", {}
+            file "policy_groups/x.json", { "policies" => { "x" => { "revision_id" => "1.0.0" }, "blah" => { "revision_id" => "1.0.0" } } }
+            file "roles/x.json", {}
+          end
+
+          it "knife download makes no changes" do
+            knife("download /").should_succeed ""
+          end
+        end
+
+        context "and the repository has a slightly different copy of each thing" do
+          before do
+            # acl_for %w(organizations foo groups blah)
+            file "clients/x.json", { "validator" => true }
+            file "containers/x.json", {}
+            file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.1")
+            file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.1")
+            file "data_bags/x/y.json", { "a" => "b" }
+            file "environments/x.json", { "description" => "foo" }
+            file "groups/x.json", { "description" => "foo" }
+            file "groups/x.json", { "groups" => [ "admin" ] }
+            file "nodes/x.json", { "run_list" => [ "blah" ] }
+            file "org.json", { "full_name" => "Something Else " }
+            file "policies/x-1.0.0.json", { "run_list" => [ "blah" ] }
+            file "policy_groups/x.json", {
+              "policies" => {
+                "x" => { "revision_id" => "1.0.1" },
+                "y" => { "revision_id" => "1.0.0" },
+              }
+            }
+            file "roles/x.json", { "run_list" => [ "blah" ] }
+          end
+
+          it "knife download updates everything" do
+            knife("download /").should_succeed <<EOM
+Updated /clients/x.json
+Updated /cookbook_artifacts/x-1x1/metadata.rb
+Updated /cookbooks/x/metadata.rb
+Updated /data_bags/x/y.json
+Updated /environments/x.json
+Updated /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Updated /nodes/x.json
+Updated /org.json
+Created /policies/blah-1.0.0.json
+Updated /policies/x-1.0.0.json
+Updated /policy_groups/x.json
+Updated /roles/x.json
+EOM
+            knife("diff --name-status /").should_succeed ""
+          end
+        end
       end
     end
   end
diff --git a/spec/integration/knife/list_spec.rb b/spec/integration/knife/list_spec.rb
index 911b56e..a5446dc 100644
--- a/spec/integration/knife/list_spec.rb
+++ b/spec/integration/knife/list_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
 
-describe 'knife list', :workstation do
+describe "knife list", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
@@ -27,7 +27,7 @@ describe 'knife list', :workstation do
 
   when_the_chef_server "is empty" do
     it "knife list / returns all top level directories" do
-      knife('list /').should_succeed <<EOM
+      knife("list /").should_succeed <<-EOM
 /clients
 /cookbooks
 /data_bags
@@ -39,7 +39,7 @@ EOM
     end
 
     it "knife list -R / returns everything" do
-      knife('list -R /').should_succeed <<EOM
+      knife("list -R /").should_succeed <<-EOM
 /:
 clients
 cookbooks
@@ -72,24 +72,27 @@ EOM
 
   when_the_chef_server "has plenty of stuff in it" do
     before do
-      client 'client1', {}
-      client 'client2', {}
-      cookbook 'cookbook1', '1.0.0'
-      cookbook 'cookbook2', '1.0.1', { 'recipes' => { 'default.rb' => '' } }
-      data_bag 'bag1', { 'item1' => {}, 'item2' => {} }
-      data_bag 'bag2', { 'item1' => {}, 'item2' => {} }
-      environment 'environment1', {}
-      environment 'environment2', {}
-      node 'node1', {}
-      node 'node2', {}
-      role 'role1', {}
-      role 'role2', {}
-      user 'user1', {}
-      user 'user2', {}
+      client "client1", {}
+      client "client2", {}
+      cookbook "cookbook1", "1.0.0"
+      cookbook "cookbook2", "1.0.1", { "recipes" => { "default.rb" => "" } }
+      data_bag "bag1", { "item1" => {}, "item2" => {} }
+      data_bag "bag2", { "item1" => {}, "item2" => {} }
+      environment "environment1", {}
+      environment "environment2", {}
+      node "node1", {}
+      node "node2", {}
+      policy "policy1", "1.2.3", {}
+      policy "policy2", "1.2.3", {}
+      policy "policy2", "1.3.5", {}
+      role "role1", {}
+      role "role2", {}
+      user "user1", {}
+      user "user2", {}
     end
 
     it "knife list / returns all top level directories" do
-      knife('list /').should_succeed <<EOM
+      knife("list /").should_succeed <<-EOM
 /clients
 /cookbooks
 /data_bags
@@ -101,7 +104,7 @@ EOM
     end
 
     it "knife list -R / returns everything" do
-      knife('list -R /').should_succeed <<EOM
+      knife("list -R /").should_succeed <<-EOM
 /:
 clients
 cookbooks
@@ -164,7 +167,7 @@ EOM
     end
 
     it "knife list -R --flat / returns everything" do
-      knife('list -R --flat /').should_succeed <<EOM
+      knife("list -R --flat /").should_succeed <<-EOM
 /clients
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -202,7 +205,7 @@ EOM
     end
 
     it "knife list -Rfp / returns everything" do
-      knife('list -Rfp /').should_succeed <<EOM
+      knife("list -Rfp /").should_succeed <<-EOM
 /clients/
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -240,18 +243,18 @@ EOM
     end
 
     it "knife list /cookbooks returns the list of cookbooks" do
-      knife('list /cookbooks').should_succeed <<EOM
+      knife("list /cookbooks").should_succeed <<-EOM
 /cookbooks/cookbook1
 /cookbooks/cookbook2
 EOM
     end
 
     it "knife list /cookbooks/*2/*/*.rb returns the one file" do
-      knife('list /cookbooks/*2/*/*.rb').should_succeed "/cookbooks/cookbook2/recipes/default.rb\n"
+      knife("list /cookbooks/*2/*/*.rb").should_succeed "/cookbooks/cookbook2/recipes/default.rb\n"
     end
 
     it "knife list /**.rb returns all ruby files" do
-      knife('list /**.rb').should_succeed <<EOM
+      knife("list /**.rb").should_succeed <<-EOM
 /cookbooks/cookbook1/metadata.rb
 /cookbooks/cookbook2/metadata.rb
 /cookbooks/cookbook2/recipes/default.rb
@@ -259,7 +262,7 @@ EOM
     end
 
     it "knife list /cookbooks/**.rb returns all ruby files" do
-      knife('list /cookbooks/**.rb').should_succeed <<EOM
+      knife("list /cookbooks/**.rb").should_succeed <<-EOM
 /cookbooks/cookbook1/metadata.rb
 /cookbooks/cookbook2/metadata.rb
 /cookbooks/cookbook2/recipes/default.rb
@@ -267,7 +270,7 @@ EOM
     end
 
     it "knife list /**.json returns all json files" do
-      knife('list /**.json').should_succeed <<EOM
+      knife("list /**.json").should_succeed <<-EOM
 /clients/chef-validator.json
 /clients/chef-webui.json
 /clients/client1.json
@@ -290,7 +293,7 @@ EOM
     end
 
     it "knife list /data**.json returns all data bag json files" do
-      knife('list /data**.json').should_succeed <<EOM
+      knife("list /data**.json").should_succeed <<-EOM
 /data_bags/bag1/item1.json
 /data_bags/bag1/item2.json
 /data_bags/bag2/item1.json
@@ -299,30 +302,30 @@ EOM
     end
 
     it "knife list /environments/missing_file.json reports missing file" do
-      knife('list /environments/missing_file.json').should_fail "ERROR: /environments/missing_file.json: No such file or directory\n"
+      knife("list /environments/missing_file.json").should_fail "ERROR: /environments/missing_file.json: No such file or directory\n"
     end
 
     context "missing file/directory exact match tests" do
       it "knife list /blarghle reports missing directory" do
-        knife('list /blarghle').should_fail "ERROR: /blarghle: No such file or directory\n"
+        knife("list /blarghle").should_fail "ERROR: /blarghle: No such file or directory\n"
       end
 
       it "knife list /roles/blarghle reports missing directory" do
-        knife('list /roles/blarghle').should_fail "ERROR: /roles/blarghle: No such file or directory\n"
+        knife("list /roles/blarghle").should_fail "ERROR: /roles/blarghle: No such file or directory\n"
       end
 
       it "knife list /roles/blarghle/blorghle reports missing directory" do
-        knife('list /roles/blarghle/blorghle').should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
+        knife("list /roles/blarghle/blorghle").should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
       end
     end
 
-    context 'symlink tests' do
-      when_the_repository 'is empty' do
-        context 'when cwd is at the top of the repository' do
-          before { cwd '.' }
+    context "symlink tests" do
+      when_the_repository "is empty" do
+        context "when cwd is at the top of the repository" do
+          before { cwd "." }
 
           it "knife list -Rfp returns everything" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 clients/
 clients/chef-validator.json
 clients/chef-webui.json
@@ -361,13 +364,13 @@ EOM
         end
       end
 
-      when_the_repository 'has a cookbooks directory' do
-        before { directory 'cookbooks' }
-        context 'when cwd is in cookbooks/' do
-          before { cwd 'cookbooks' }
+      when_the_repository "has a cookbooks directory" do
+        before { directory "cookbooks" }
+        context "when cwd is in cookbooks/" do
+          before { cwd "cookbooks" }
 
           it "knife list -Rfp / returns everything" do
-            knife('list -Rfp /').should_succeed <<EOM
+            knife("list -Rfp /").should_succeed <<-EOM
 /clients/
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -405,7 +408,7 @@ EOM
           end
 
           it "knife list -Rfp .. returns everything" do
-            knife('list -Rfp ..').should_succeed <<EOM
+            knife("list -Rfp ..").should_succeed <<-EOM
 /clients/
 /clients/chef-validator.json
 /clients/chef-webui.json
@@ -443,7 +446,7 @@ EOM
           end
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 cookbook1/
 cookbook1/metadata.rb
 cookbook2/
@@ -455,14 +458,14 @@ EOM
         end
       end
 
-      when_the_repository 'has a cookbooks/cookbook2 directory' do
-        before { directory 'cookbooks/cookbook2' }
+      when_the_repository "has a cookbooks/cookbook2 directory" do
+        before { directory "cookbooks/cookbook2" }
 
-        context 'when cwd is in cookbooks/cookbook2' do
-          before { cwd 'cookbooks/cookbook2' }
+        context "when cwd is in cookbooks/cookbook2" do
+          before { cwd "cookbooks/cookbook2" }
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 metadata.rb
 recipes/
 recipes/default.rb
@@ -471,17 +474,17 @@ EOM
         end
       end
 
-      when_the_repository 'has a cookbooks directory and a symlinked cookbooks directory', :skip => (Chef::Platform.windows?) do
+      when_the_repository "has a cookbooks directory and a symlinked cookbooks directory", :skip => (Chef::Platform.windows?) do
         before do
-          directory 'cookbooks'
-          symlink 'symlinked', 'cookbooks'
+          directory "cookbooks"
+          symlink "symlinked", "cookbooks"
         end
 
-        context 'when cwd is in cookbooks/' do
-          before { cwd 'cookbooks' }
+        context "when cwd is in cookbooks/" do
+          before { cwd "cookbooks" }
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 cookbook1/
 cookbook1/metadata.rb
 cookbook2/
@@ -492,11 +495,11 @@ EOM
           end
         end
 
-        context 'when cwd is in symlinked/' do
-          before { cwd 'symlinked' }
+        context "when cwd is in symlinked/" do
+          before { cwd "symlinked" }
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 cookbook1/
 cookbook1/metadata.rb
 cookbook2/
@@ -508,17 +511,17 @@ EOM
         end
       end
 
-      when_the_repository 'has a real_cookbooks directory and a cookbooks symlink to it', :skip => (Chef::Platform.windows?) do
+      when_the_repository "has a real_cookbooks directory and a cookbooks symlink to it", :skip => (Chef::Platform.windows?) do
         before do
-          directory 'real_cookbooks'
-          symlink 'cookbooks', 'real_cookbooks'
+          directory "real_cookbooks"
+          symlink "cookbooks", "real_cookbooks"
         end
 
-        context 'when cwd is in real_cookbooks/' do
-          before { cwd 'real_cookbooks' }
+        context "when cwd is in real_cookbooks/" do
+          before { cwd "real_cookbooks" }
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 cookbook1/
 cookbook1/metadata.rb
 cookbook2/
@@ -529,11 +532,11 @@ EOM
           end
         end
 
-        context 'when cwd is in cookbooks/' do
-          before { cwd 'cookbooks' }
+        context "when cwd is in cookbooks/" do
+          before { cwd "cookbooks" }
 
           it "knife list -Rfp returns cookbooks" do
-            knife('list -Rfp').should_succeed <<EOM
+            knife("list -Rfp").should_succeed <<-EOM
 cookbook1/
 cookbook1/metadata.rb
 cookbook2/
@@ -550,50 +553,51 @@ EOM
   context "--local" do
     when_the_repository "is empty" do
       it "knife list --local / returns nothing" do
-        knife('list --local /').should_succeed ""
+        knife("list --local /").should_succeed ""
       end
 
       it "knife list /roles returns nothing" do
-        knife('list --local /roles').should_fail "ERROR: /roles: No such file or directory\n"
+        knife("list --local /roles").should_fail "ERROR: /roles: No such file or directory\n"
       end
     end
 
     when_the_repository "has a bunch of stuff" do
       before do
-        file 'clients/client1.json', {}
-        file 'clients/client2.json', {}
+        file "clients/client1.json", {}
+        file "clients/client2.json", {}
 
-        directory 'cookbooks/cookbook1' do
-          file 'metadata.rb', cb_metadata("cookbook1", "1.0.0")
+        directory "cookbooks/cookbook1" do
+          file "metadata.rb", cb_metadata("cookbook1", "1.0.0")
         end
-        directory 'cookbooks/cookbook2' do
-          file 'metadata.rb', cb_metadata("cookbook2", "2.0.0")
-          file 'recipes/default.rb', ''
+        directory "cookbooks/cookbook2" do
+          file "metadata.rb", cb_metadata("cookbook2", "2.0.0")
+          file "recipes/default.rb", ""
         end
 
-        directory 'data_bags' do
-          directory 'bag1' do
-            file 'item1.json', {}
-            file 'item2.json', {}
+        directory "data_bags" do
+          directory "bag1" do
+            file "item1.json", {}
+            file "item2.json", {}
           end
-          directory 'bag2' do
-            file 'item1.json', {}
-            file 'item2.json', {}
+          directory "bag2" do
+            file "item1.json", {}
+            file "item2.json", {}
           end
         end
 
-        file 'environments/environment1.json', {}
-        file 'environments/environment2.json', {}
-        file 'nodes/node1.json', {}
-        file 'nodes/node2.json', {}
-        file 'roles/role1.json', {}
-        file 'roles/role2.json', {}
-        file 'users/user1.json', {}
-        file 'users/user2.json', {}
+        file "environments/environment1.json", {}
+        file "environments/environment2.json", {}
+        file "nodes/node1.json", {}
+        file "nodes/node2.json", {}
+
+        file "roles/role1.json", {}
+        file "roles/role2.json", {}
+        file "users/user1.json", {}
+        file "users/user2.json", {}
       end
 
       it "knife list -Rfp / returns everything" do
-        knife('list -Rp --local --flat /').should_succeed <<EOM
+        knife("list -Rp --local --flat /").should_succeed <<-EOM
 /clients/
 /clients/client1.json
 /clients/client2.json
@@ -628,15 +632,15 @@ EOM
 
       context "missing file/directory tests" do
         it "knife list --local /blarghle reports missing directory" do
-          knife('list --local /blarghle').should_fail "ERROR: /blarghle: No such file or directory\n"
+          knife("list --local /blarghle").should_fail "ERROR: /blarghle: No such file or directory\n"
         end
 
         it "knife list /roles/blarghle reports missing directory" do
-          knife('list --local /roles/blarghle').should_fail "ERROR: /roles/blarghle: No such file or directory\n"
+          knife("list --local /roles/blarghle").should_fail "ERROR: /roles/blarghle: No such file or directory\n"
         end
 
         it "knife list /roles/blarghle/blorghle reports missing directory" do
-          knife('list --local /roles/blarghle/blorghle').should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
+          knife("list --local /roles/blarghle/blorghle").should_fail "ERROR: /roles/blarghle/blorghle: No such file or directory\n"
         end
       end
     end
@@ -644,19 +648,20 @@ EOM
 
   when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
     before do
-      organization 'foo'
+      organization "foo"
     end
 
     before :each do
-      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
     end
 
-    context 'and is empty' do
+    context "and is empty" do
       it "knife list / returns all top level directories" do
-        knife('list /').should_succeed <<EOM
+        knife("list /").should_succeed <<-EOM
 /acls
 /clients
 /containers
+/cookbook_artifacts
 /cookbooks
 /data_bags
 /environments
@@ -665,16 +670,19 @@ EOM
 /members.json
 /nodes
 /org.json
+/policies
+/policy_groups
 /roles
 EOM
       end
 
       it "knife list -R / returns everything" do
-        knife('list -R /').should_succeed <<EOM
+        knife("list -R /").should_succeed <<-EOM
 /:
 acls
 clients
 containers
+cookbook_artifacts
 cookbooks
 data_bags
 environments
@@ -683,17 +691,22 @@ invitations.json
 members.json
 nodes
 org.json
+policies
+policy_groups
 roles
 
 /acls:
 clients
 containers
+cookbook_artifacts
 cookbooks
 data_bags
 environments
 groups
 nodes
 organization.json
+policies
+policy_groups
 roles
 
 /acls/clients:
@@ -702,14 +715,19 @@ foo-validator.json
 /acls/containers:
 clients.json
 containers.json
+cookbook_artifacts.json
 cookbooks.json
 data.json
 environments.json
 groups.json
 nodes.json
+policies.json
+policy_groups.json
 roles.json
 sandboxes.json
 
+/acls/cookbook_artifacts:
+
 /acls/cookbooks:
 
 /acls/data_bags:
@@ -725,6 +743,10 @@ users.json
 
 /acls/nodes:
 
+/acls/policies:
+
+/acls/policy_groups:
+
 /acls/roles:
 
 /clients:
@@ -733,14 +755,19 @@ foo-validator.json
 /containers:
 clients.json
 containers.json
+cookbook_artifacts.json
 cookbooks.json
 data.json
 environments.json
 groups.json
 nodes.json
+policies.json
+policy_groups.json
 roles.json
 sandboxes.json
 
+/cookbook_artifacts:
+
 /cookbooks:
 
 /data_bags:
@@ -756,27 +783,22 @@ users.json
 
 /nodes:
 
+/policies:
+
+/policy_groups:
+
 /roles:
 EOM
       end
     end
-  end
-
-  when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
-    before do
-      organization 'foo'
-    end
-
-    before :each do
-      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
-    end
 
-    it 'knife list -R / returns everything' do
-      knife('list -R /').should_succeed <<EOM
+    it "knife list -R / returns everything" do
+      knife("list -R /").should_succeed <<-EOM
 /:
 acls
 clients
 containers
+cookbook_artifacts
 cookbooks
 data_bags
 environments
@@ -785,17 +807,22 @@ invitations.json
 members.json
 nodes
 org.json
+policies
+policy_groups
 roles
 
 /acls:
 clients
 containers
+cookbook_artifacts
 cookbooks
 data_bags
 environments
 groups
 nodes
 organization.json
+policies
+policy_groups
 roles
 
 /acls/clients:
@@ -804,14 +831,19 @@ foo-validator.json
 /acls/containers:
 clients.json
 containers.json
+cookbook_artifacts.json
 cookbooks.json
 data.json
 environments.json
 groups.json
 nodes.json
+policies.json
+policy_groups.json
 roles.json
 sandboxes.json
 
+/acls/cookbook_artifacts:
+
 /acls/cookbooks:
 
 /acls/data_bags:
@@ -827,6 +859,10 @@ users.json
 
 /acls/nodes:
 
+/acls/policies:
+
+/acls/policy_groups:
+
 /acls/roles:
 
 /clients:
@@ -835,14 +871,19 @@ foo-validator.json
 /containers:
 clients.json
 containers.json
+cookbook_artifacts.json
 cookbooks.json
 data.json
 environments.json
 groups.json
 nodes.json
+policies.json
+policy_groups.json
 roles.json
 sandboxes.json
 
+/cookbook_artifacts:
+
 /cookbooks:
 
 /data_bags:
@@ -858,8 +899,169 @@ users.json
 
 /nodes:
 
+/policies:
+
+/policy_groups:
+
 /roles:
 EOM
     end
+
+    context "has plenty of stuff in it" do
+      before do
+        client "client1", {}
+        client "client2", {}
+        container "container1", {}
+        container "container2", {}
+        cookbook "cookbook1", "1.0.0"
+        cookbook "cookbook2", "1.0.1", { "recipes" => { "default.rb" => "" } }
+        cookbook_artifact "cookbook_artifact1", "1x1"
+        cookbook_artifact "cookbook_artifact2", "2x2", { "recipes" => { "default.rb" => "" } }
+        data_bag "bag1", { "item1" => {}, "item2" => {} }
+        data_bag "bag2", { "item1" => {}, "item2" => {} }
+        environment "environment1", {}
+        environment "environment2", {}
+        group "group1", {}
+        group "group2", {}
+        node "node1", {}
+        node "node2", {}
+        org_invite "user1"
+        org_member "user2"
+        policy "policy1", "1.2.3", {}
+        policy "policy2", "1.2.3", {}
+        policy "policy2", "1.3.5", {}
+        policy_group "policy_group1", { "policies" => { "policy1" => { "revision_id" => "1.2.3" } } }
+        policy_group "policy_group2", { "policies" => { "policy2" => { "revision_id" => "1.3.5" } } }
+        role "role1", {}
+        role "role2", {}
+        user "user1", {}
+        user "user2", {}
+      end
+
+      it "knife list -Rfp / returns everything" do
+        knife("list -Rfp /").should_succeed <<-EOM
+/acls/
+/acls/clients/
+/acls/clients/client1.json
+/acls/clients/client2.json
+/acls/clients/foo-validator.json
+/acls/containers/
+/acls/containers/clients.json
+/acls/containers/container1.json
+/acls/containers/container2.json
+/acls/containers/containers.json
+/acls/containers/cookbook_artifacts.json
+/acls/containers/cookbooks.json
+/acls/containers/data.json
+/acls/containers/environments.json
+/acls/containers/groups.json
+/acls/containers/nodes.json
+/acls/containers/policies.json
+/acls/containers/policy_groups.json
+/acls/containers/roles.json
+/acls/containers/sandboxes.json
+/acls/cookbook_artifacts/
+/acls/cookbook_artifacts/cookbook_artifact1.json
+/acls/cookbook_artifacts/cookbook_artifact2.json
+/acls/cookbooks/
+/acls/cookbooks/cookbook1.json
+/acls/cookbooks/cookbook2.json
+/acls/data_bags/
+/acls/data_bags/bag1.json
+/acls/data_bags/bag2.json
+/acls/environments/
+/acls/environments/_default.json
+/acls/environments/environment1.json
+/acls/environments/environment2.json
+/acls/groups/
+/acls/groups/admins.json
+/acls/groups/billing-admins.json
+/acls/groups/clients.json
+/acls/groups/group1.json
+/acls/groups/group2.json
+/acls/groups/users.json
+/acls/nodes/
+/acls/nodes/node1.json
+/acls/nodes/node2.json
+/acls/organization.json
+/acls/policies/
+/acls/policies/policy1.json
+/acls/policies/policy2.json
+/acls/policy_groups/
+/acls/policy_groups/policy_group1.json
+/acls/policy_groups/policy_group2.json
+/acls/roles/
+/acls/roles/role1.json
+/acls/roles/role2.json
+/clients/
+/clients/client1.json
+/clients/client2.json
+/clients/foo-validator.json
+/containers/
+/containers/clients.json
+/containers/container1.json
+/containers/container2.json
+/containers/containers.json
+/containers/cookbook_artifacts.json
+/containers/cookbooks.json
+/containers/data.json
+/containers/environments.json
+/containers/groups.json
+/containers/nodes.json
+/containers/policies.json
+/containers/policy_groups.json
+/containers/roles.json
+/containers/sandboxes.json
+/cookbook_artifacts/
+/cookbook_artifacts/cookbook_artifact1-1x1/
+/cookbook_artifacts/cookbook_artifact1-1x1/metadata.rb
+/cookbook_artifacts/cookbook_artifact2-2x2/
+/cookbook_artifacts/cookbook_artifact2-2x2/metadata.rb
+/cookbook_artifacts/cookbook_artifact2-2x2/recipes/
+/cookbook_artifacts/cookbook_artifact2-2x2/recipes/default.rb
+/cookbooks/
+/cookbooks/cookbook1/
+/cookbooks/cookbook1/metadata.rb
+/cookbooks/cookbook2/
+/cookbooks/cookbook2/metadata.rb
+/cookbooks/cookbook2/recipes/
+/cookbooks/cookbook2/recipes/default.rb
+/data_bags/
+/data_bags/bag1/
+/data_bags/bag1/item1.json
+/data_bags/bag1/item2.json
+/data_bags/bag2/
+/data_bags/bag2/item1.json
+/data_bags/bag2/item2.json
+/environments/
+/environments/_default.json
+/environments/environment1.json
+/environments/environment2.json
+/groups/
+/groups/admins.json
+/groups/billing-admins.json
+/groups/clients.json
+/groups/group1.json
+/groups/group2.json
+/groups/users.json
+/invitations.json
+/members.json
+/nodes/
+/nodes/node1.json
+/nodes/node2.json
+/org.json
+/policies/
+/policies/policy1-1.2.3.json
+/policies/policy2-1.2.3.json
+/policies/policy2-1.3.5.json
+/policy_groups/
+/policy_groups/policy_group1.json
+/policy_groups/policy_group2.json
+/roles/
+/roles/role1.json
+/roles/role2.json
+EOM
+      end
+    end
   end
 end
diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb
index 75fc8fa..9078bf0 100644
--- a/spec/integration/knife/raw_spec.rb
+++ b/spec/integration/knife/raw_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,12 +15,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/raw'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/raw"
+require "chef/knife/show"
 
-describe 'knife raw', :workstation do
+describe "knife raw", :workstation do
   include IntegrationSupport
   include KnifeSupport
   include AppServerSupport
@@ -29,17 +29,17 @@ describe 'knife raw', :workstation do
 
   when_the_chef_server "has one of each thing" do
     before do
-      client 'x', '{}'
-      cookbook 'x', '1.0.0'
-      data_bag 'x', { 'y' => '{}' }
-      environment 'x', '{}'
-      node 'x', '{}'
-      role 'x', '{}'
-      user 'x', '{}'
+      client "x", "{}"
+      cookbook "x", "1.0.0"
+      data_bag "x", { "y" => "{}" }
+      environment "x", "{}"
+      node "x", "{}"
+      role "x", "{}"
+      user "x", "{}"
     end
 
-    it 'knife raw /nodes/x returns the node', :skip => (RUBY_VERSION < "1.9") do
-      knife('raw /nodes/x').should_succeed <<EOM
+    it "knife raw /nodes/x returns the node", :skip => (RUBY_VERSION < "1.9") do
+      knife("raw /nodes/x").should_succeed <<EOM
 {
   "name": "x",
   "json_class": "Chef::Node",
@@ -64,12 +64,12 @@ describe 'knife raw', :workstation do
 EOM
     end
 
-    it 'knife raw /blarghle returns 404' do
-      knife('raw /blarghle').should_fail(/ERROR: Server responded with error 404 "Not Found\s*"/)
+    it "knife raw /blarghle returns 404" do
+      knife("raw /blarghle").should_fail(/ERROR: Server responded with error 404 "Not Found\s*"/)
     end
 
-    it 'knife raw -m DELETE /roles/x succeeds', :skip => (RUBY_VERSION < "1.9") do
-      knife('raw -m DELETE /roles/x').should_succeed <<EOM
+    it "knife raw -m DELETE /roles/x succeeds", :skip => (RUBY_VERSION < "1.9") do
+      knife("raw -m DELETE /roles/x").should_succeed <<EOM
 {
   "name": "x",
   "description": "",
@@ -89,11 +89,11 @@ EOM
   }
 }
 EOM
-      knife('show /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
+      knife("show /roles/x.json").should_fail "ERROR: /roles/x.json: No such file or directory\n"
     end
 
-    it 'knife raw -m PUT -i blah.txt /roles/x succeeds', :skip => (RUBY_VERSION < "1.9") do
-      Tempfile.open('raw_put_input') do |file|
+    it "knife raw -m PUT -i blah.txt /roles/x succeeds", :skip => (RUBY_VERSION < "1.9") do
+      Tempfile.open("raw_put_input") do |file|
         file.write <<EOM
 {
   "name": "x",
@@ -136,7 +136,7 @@ EOM
   }
 }
 EOM
-        knife('show /roles/x.json').should_succeed <<EOM
+        knife("show /roles/x.json").should_succeed <<EOM
 /roles/x.json:
 {
   "name": "x",
@@ -146,8 +146,8 @@ EOM
       end
     end
 
-    it 'knife raw -m POST -i blah.txt /roles succeeds', :skip => (RUBY_VERSION < "1.9") do
-      Tempfile.open('raw_put_input') do |file|
+    it "knife raw -m POST -i blah.txt /roles succeeds", :skip => (RUBY_VERSION < "1.9") do
+      Tempfile.open("raw_put_input") do |file|
         file.write <<EOM
 {
   "name": "y",
@@ -172,7 +172,7 @@ EOM
   "uri": "#{Chef::Config.chef_server_url}/roles/y"
 }
 EOM
-        knife('show /roles/y.json').should_succeed <<EOM
+        knife("show /roles/y.json").should_succeed <<EOM
 /roles/y.json:
 {
   "name": "y",
@@ -182,11 +182,11 @@ EOM
       end
     end
 
-    context 'When a server returns raw json' do
+    context "When a server returns raw json" do
       before :each do
         Chef::Config.chef_server_url = "http://localhost:9018"
         app = lambda do |env|
-          [200, {'Content-Type' => 'application/json' }, ['{ "x": "y", "a": "b" }'] ]
+          [200, { "Content-Type" => "application/json" }, ['{ "x": "y", "a": "b" }'] ]
         end
         @raw_server, @raw_server_thread = start_app_server(app, 9018)
       end
@@ -196,8 +196,8 @@ EOM
         @raw_server_thread.kill if @raw_server_thread
       end
 
-      it 'knife raw /blah returns the prettified json', :skip => (RUBY_VERSION < "1.9") do
-        knife('raw /blah').should_succeed <<EOM
+      it "knife raw /blah returns the prettified json", :skip => (RUBY_VERSION < "1.9") do
+        knife("raw /blah").should_succeed <<EOM
 {
   "x": "y",
   "a": "b"
@@ -205,18 +205,18 @@ EOM
 EOM
       end
 
-      it 'knife raw --no-pretty /blah returns the raw json' do
-        knife('raw --no-pretty /blah').should_succeed <<EOM
+      it "knife raw --no-pretty /blah returns the raw json" do
+        knife("raw --no-pretty /blah").should_succeed <<EOM
 { "x": "y", "a": "b" }
 EOM
       end
     end
 
-    context 'When a server returns text' do
+    context "When a server returns text" do
       before :each do
         Chef::Config.chef_server_url = "http://localhost:9018"
         app = lambda do |env|
-          [200, {'Content-Type' => 'text' }, ['{ "x": "y", "a": "b" }'] ]
+          [200, { "Content-Type" => "text" }, ['{ "x": "y", "a": "b" }'] ]
         end
         @raw_server, @raw_server_thread = start_app_server(app, 9018)
       end
@@ -226,14 +226,14 @@ EOM
         @raw_server_thread.kill if @raw_server_thread
       end
 
-      it 'knife raw /blah returns the raw text' do
-        knife('raw /blah').should_succeed(<<EOM)
+      it "knife raw /blah returns the raw text" do
+        knife("raw /blah").should_succeed(<<EOM)
 { "x": "y", "a": "b" }
 EOM
       end
 
-      it 'knife raw --no-pretty /blah returns the raw text' do
-        knife('raw --no-pretty /blah').should_succeed(<<EOM)
+      it "knife raw --no-pretty /blah returns the raw text" do
+        knife("raw --no-pretty /blah").should_succeed(<<EOM)
 { "x": "y", "a": "b" }
 EOM
       end
diff --git a/spec/integration/knife/redirection_spec.rb b/spec/integration/knife/redirection_spec.rb
index 77bda99..29c1ee6 100644
--- a/spec/integration/knife/redirection_spec.rb
+++ b/spec/integration/knife/redirection_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,26 +15,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/list'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/list"
 
-describe 'redirection', :workstation do
+describe "redirection", :workstation do
   include IntegrationSupport
   include KnifeSupport
   include AppServerSupport
 
   include_context "default config options"
 
-  when_the_chef_server 'has a role' do
-    before { role 'x', {} }
+  when_the_chef_server "has a role" do
+    before { role "x", {} }
 
-    context 'and another server redirects to it with 302' do
+    context "and another server redirects to it with 302" do
       before :each do
         real_chef_server_url = Chef::Config.chef_server_url
         Chef::Config.chef_server_url = "http://localhost:9018"
         app = lambda do |env|
-          [302, {'Content-Type' => 'text','Location' => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ]
+          [302, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ["302 found"] ]
         end
         @redirector_server, @redirector_server_thread = start_app_server(app, 9018)
       end
@@ -44,8 +44,8 @@ describe 'redirection', :workstation do
         @redirector_thread.kill if @redirector_thread
       end
 
-      it 'knife list /roles returns the role' do
-        knife('list /roles').should_succeed "/roles/x.json\n"
+      it "knife list /roles returns the role" do
+        knife("list /roles").should_succeed "/roles/x.json\n"
       end
     end
   end
diff --git a/spec/integration/knife/serve_spec.rb b/spec/integration/knife/serve_spec.rb
index 7bf7d29..72f0bb5 100644
--- a/spec/integration/knife/serve_spec.rb
+++ b/spec/integration/knife/serve_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,34 +15,34 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/serve'
-require 'chef/server_api'
+require "support/shared/integration/integration_helper"
+require "chef/knife/serve"
+require "chef/server_api"
 
-describe 'knife serve', :workstation do
+describe "knife serve", :workstation do
   include IntegrationSupport
   include KnifeSupport
   include AppServerSupport
 
-  when_the_repository 'also has one of each thing' do
-    before { file 'nodes/x.json', { 'foo' => 'bar' } }
+  when_the_repository "also has one of each thing" do
+    before { file "nodes/x.json", { "foo" => "bar" } }
 
-    it 'knife serve serves up /nodes/x' do
+    it "knife serve serves up /nodes/x" do
       exception = nil
       t = Thread.new do
         begin
-          knife('serve --chef-zero-port=8890')
+          knife("serve --chef-zero-port=8890")
         rescue
           exception = $!
         end
       end
       begin
         Chef::Config.log_level = :debug
-        Chef::Config.chef_server_url = 'http://localhost:8890'
+        Chef::Config.chef_server_url = "http://localhost:8890"
         Chef::Config.node_name = nil
         Chef::Config.client_key = nil
         api = Chef::ServerAPI.new
-        expect(api.get('nodes/x')['name']).to eq('x')
+        expect(api.get("nodes/x")["name"]).to eq("x")
       rescue
         if exception
           raise exception
diff --git a/spec/integration/knife/show_spec.rb b/spec/integration/knife/show_spec.rb
index 8f1887e..ed4802f 100644
--- a/spec/integration/knife/show_spec.rb
+++ b/spec/integration/knife/show_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'support/shared/context/config'
-require 'chef/knife/show'
+require "support/shared/integration/integration_helper"
+require "support/shared/context/config"
+require "chef/knife/show"
 
-describe 'knife show', :workstation do
+describe "knife show", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
@@ -27,81 +27,81 @@ describe 'knife show', :workstation do
 
   when_the_chef_server "has one of each thing" do
     before do
-      client 'x', '{}'
-      cookbook 'x', '1.0.0'
-      data_bag 'x', { 'y' => '{}' }
-      environment 'x', '{}'
-      node 'x', '{}'
-      role 'x', '{}'
-      user 'x', '{}'
+      client "x", "{}"
+      cookbook "x", "1.0.0"
+      data_bag "x", { "y" => "{}" }
+      environment "x", "{}"
+      node "x", "{}"
+      role "x", "{}"
+      user "x", "{}"
     end
 
-    when_the_repository 'also has one of each thing' do
+    when_the_repository "also has one of each thing" do
       before do
-        file 'clients/x.json', { 'foo' => 'bar' }
-        file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
-        file 'data_bags/x/y.json', { 'foo' => 'bar' }
-        file 'environments/_default.json', { 'foo' => 'bar' }
-        file 'environments/x.json', { 'foo' => 'bar' }
-        file 'nodes/x.json', { 'foo' => 'bar' }
-        file 'roles/x.json', { 'foo' => 'bar' }
-        file 'users/x.json', { 'foo' => 'bar' }
+        file "clients/x.json", { "foo" => "bar" }
+        file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+        file "data_bags/x/y.json", { "foo" => "bar" }
+        file "environments/_default.json", { "foo" => "bar" }
+        file "environments/x.json", { "foo" => "bar" }
+        file "nodes/x.json", { "foo" => "bar" }
+        file "roles/x.json", { "foo" => "bar" }
+        file "users/x.json", { "foo" => "bar" }
       end
 
-      it 'knife show /cookbooks/x/metadata.rb shows the remote version' do
-        knife('show /cookbooks/x/metadata.rb').should_succeed <<EOM
+      it "knife show /cookbooks/x/metadata.rb shows the remote version" do
+        knife("show /cookbooks/x/metadata.rb").should_succeed <<EOM
 /cookbooks/x/metadata.rb:
 name "x"; version "1.0.0"
 EOM
       end
-      it 'knife show --local /cookbooks/x/metadata.rb shows the local version' do
-        knife('show --local /cookbooks/x/metadata.rb').should_succeed <<EOM
+      it "knife show --local /cookbooks/x/metadata.rb shows the local version" do
+        knife("show --local /cookbooks/x/metadata.rb").should_succeed <<EOM
 /cookbooks/x/metadata.rb:
 name "x"; version "1.0.0"
 EOM
       end
-      it 'knife show /data_bags/x/y.json shows the remote version' do
-        knife('show /data_bags/x/y.json').should_succeed <<EOM
+      it "knife show /data_bags/x/y.json shows the remote version" do
+        knife("show /data_bags/x/y.json").should_succeed <<EOM
 /data_bags/x/y.json:
 {
   "id": "y"
 }
 EOM
       end
-      it 'knife show --local /data_bags/x/y.json shows the local version' do
-        knife('show --local /data_bags/x/y.json').should_succeed <<EOM
+      it "knife show --local /data_bags/x/y.json shows the local version" do
+        knife("show --local /data_bags/x/y.json").should_succeed <<EOM
 /data_bags/x/y.json:
 {
   "foo": "bar"
 }
 EOM
       end
-      it 'knife show /environments/x.json shows the remote version', :skip => (RUBY_VERSION < "1.9") do
-        knife('show /environments/x.json').should_succeed <<EOM
+      it "knife show /environments/x.json shows the remote version", :skip => (RUBY_VERSION < "1.9") do
+        knife("show /environments/x.json").should_succeed <<EOM
 /environments/x.json:
 {
   "name": "x"
 }
 EOM
       end
-      it 'knife show --local /environments/x.json shows the local version' do
-        knife('show --local /environments/x.json').should_succeed <<EOM
+      it "knife show --local /environments/x.json shows the local version" do
+        knife("show --local /environments/x.json").should_succeed <<EOM
 /environments/x.json:
 {
   "foo": "bar"
 }
 EOM
       end
-      it 'knife show /roles/x.json shows the remote version', :skip => (RUBY_VERSION < "1.9") do
-        knife('show /roles/x.json').should_succeed <<EOM
+      it "knife show /roles/x.json shows the remote version", :skip => (RUBY_VERSION < "1.9") do
+        knife("show /roles/x.json").should_succeed <<EOM
 /roles/x.json:
 {
   "name": "x"
 }
 EOM
       end
-      it 'knife show --local /roles/x.json shows the local version' do
-        knife('show --local /roles/x.json').should_succeed <<EOM
+      it "knife show --local /roles/x.json shows the local version" do
+        knife("show --local /roles/x.json").should_succeed <<EOM
 /roles/x.json:
 {
   "foo": "bar"
@@ -109,34 +109,34 @@ EOM
 EOM
       end
       # show directory
-      it 'knife show /data_bags/x fails' do
-        knife('show /data_bags/x').should_fail "ERROR: /data_bags/x: is a directory\n"
+      it "knife show /data_bags/x fails" do
+        knife("show /data_bags/x").should_fail "ERROR: /data_bags/x: is a directory\n"
       end
-      it 'knife show --local /data_bags/x fails' do
-        knife('show --local /data_bags/x').should_fail "ERROR: /data_bags/x: is a directory\n"
+      it "knife show --local /data_bags/x fails" do
+        knife("show --local /data_bags/x").should_fail "ERROR: /data_bags/x: is a directory\n"
       end
       # show nonexistent file
-      it 'knife show /environments/nonexistent.json fails' do
-        knife('show /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+      it "knife show /environments/nonexistent.json fails" do
+        knife("show /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
       end
-      it 'knife show --local /environments/nonexistent.json fails' do
-        knife('show --local /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
+      it "knife show --local /environments/nonexistent.json fails" do
+        knife("show --local /environments/nonexistent.json").should_fail "ERROR: /environments/nonexistent.json: No such file or directory\n"
       end
     end
   end
 
-  when_the_chef_server 'has a hash with multiple keys' do
+  when_the_chef_server "has a hash with multiple keys" do
     before do
-      environment 'x', {
-        'default_attributes' => { 'foo' => 'bar' },
-        'cookbook_versions' => { 'blah' => '= 1.0.0'},
-        'override_attributes' => { 'x' => 'y' },
-        'description' => 'woo',
-        'name' => 'x'
+      environment "x", {
+        "default_attributes" => { "foo" => "bar" },
+        "cookbook_versions" => { "blah" => "= 1.0.0" },
+        "override_attributes" => { "x" => "y" },
+        "description" => "woo",
+        "name" => "x",
       }
     end
-    it 'knife show shows the attributes in a predetermined order', :skip => (RUBY_VERSION < "1.9") do
-      knife('show /environments/x.json').should_succeed <<EOM
+    it "knife show shows the attributes in a predetermined order", :skip => (RUBY_VERSION < "1.9") do
+      knife("show /environments/x.json").should_succeed <<EOM
 /environments/x.json:
 {
   "name": "x",
@@ -155,10 +155,10 @@ EOM
     end
   end
 
-  when_the_repository 'has an environment with bad JSON' do
-    before { file 'environments/x.json', '{' }
-    it 'knife show succeeds' do
-      knife('show --local /environments/x.json').should_succeed <<EOM
+  when_the_repository "has an environment with bad JSON" do
+    before { file "environments/x.json", "{" }
+    it "knife show succeeds" do
+      knife("show --local /environments/x.json").should_succeed <<EOM
 /environments/x.json:
 {
 EOM
diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb
index cef4f54..6f8dce5 100644
--- a/spec/integration/knife/upload_spec.rb
+++ b/spec/integration/knife/upload_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,44 +15,44 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'support/shared/integration/integration_helper'
-require 'chef/knife/upload'
-require 'chef/knife/diff'
-require 'chef/knife/raw'
-require 'chef/json_compat'
+require "support/shared/integration/integration_helper"
+require "chef/knife/upload"
+require "chef/knife/diff"
+require "chef/knife/raw"
+require "chef/json_compat"
 
-describe 'knife upload', :workstation do
+describe "knife upload", :workstation do
   include IntegrationSupport
   include KnifeSupport
 
-  context 'without versioned cookbooks' do
+  context "without versioned cookbooks" do
 
     when_the_chef_server "has one of each thing" do
 
       before do
-        client 'x', {}
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => {} }
-        environment 'x', {}
-        node 'x', {}
-        role 'x', {}
-        user 'x', {}
+        client "x", {}
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => {} }
+        environment "x", {}
+        node "x", {}
+        role "x", {}
+        user "x", {}
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
-        end
-
-        it 'knife upload does nothing' do
-          knife('upload /').should_succeed ''
-          knife('diff --name-status /').should_succeed <<EOM
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
+        end
+
+        it "knife upload does nothing" do
+          knife("upload /").should_succeed ""
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients/chef-validator.json
 D\t/clients/chef-webui.json
 D\t/clients/x.json
@@ -67,8 +67,8 @@ D\t/users/x.json
 EOM
         end
 
-        it 'knife upload --purge deletes everything' do
-          knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
+        it "knife upload --purge deletes everything" do
+          knife("upload --purge /").should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
 Deleted extra entry /clients/chef-validator.json (purge is on)
 Deleted extra entry /clients/chef-webui.json (purge is on)
 Deleted extra entry /clients/x.json (purge is on)
@@ -80,56 +80,56 @@ Deleted extra entry /roles/x.json (purge is on)
 Deleted extra entry /users/admin.json (purge is on)
 Deleted extra entry /users/x.json (purge is on)
 EOM
-        knife('diff --name-status /').should_succeed <<EOM
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/environments/_default.json
 EOM
         end
       end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
 
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { "description" => "The default Chef environment" }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife upload makes no changes' do
-          knife('upload /cookbooks/x').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife upload makes no changes" do
+          knife("upload /cookbooks/x").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        it 'knife upload --purge makes no changes' do
-          knife('upload --purge /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife upload --purge makes no changes" do
+          knife("upload --purge /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', { 'description' => 'blarghle' }
+            file "roles/x.json", { "description" => "blarghle" }
           end
 
-          it 'knife upload changes the role' do
-            knife('upload /').should_succeed "Updated /roles/x.json\n"
-            knife('diff --name-status /').should_succeed ''
+          it "knife upload changes the role" do
+            knife("upload /").should_succeed "Updated /roles/x.json\n"
+            knife("diff --name-status /").should_succeed ""
           end
-          it 'knife upload --no-diff does not change the role' do
-            knife('upload --no-diff /').should_succeed ''
-            knife('diff --name-status /').should_succeed "M\t/roles/x.json\n"
+          it "knife upload --no-diff does not change the role" do
+            knife("upload --no-diff /").should_succeed ""
+            knife("diff --name-status /").should_succeed "M\t/roles/x.json\n"
           end
         end
 
-        context 'except the role file is textually different, but not ACTUALLY different' do
+        context "except the role file is textually different, but not ACTUALLY different" do
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "chef_type": "role",
   "default_attributes":  {
@@ -148,27 +148,45 @@ EOM
 EOM
           end
 
-          it 'knife upload / does not change anything' do
-            knife('upload /').should_succeed ''
-            knife('diff --name-status /').should_succeed ''
+          it "knife upload / does not change anything" do
+            knife("upload /").should_succeed ""
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "when cookbook metadata has a self-dependency" do
           before do
-            file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-            file 'cookbooks/x/blah.rb', ''
-            file 'cookbooks/y/metadata.rb', cb_metadata("y", "1.0.0")
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x/metadata.rb", "name 'x'; version '1.0.0'; depends 'x'"
           end
 
-          it 'knife upload adds the new files' do
-            knife('upload /').should_succeed <<EOM
+          it "should warn", :chef_lt_13_only do
+            knife("upload /cookbooks").should_succeed(
+              stdout: "Updated /cookbooks/x\n",
+              stderr: "WARN: Ignoring self-dependency in cookbook x, please remove it (in the future this will be fatal).\n",
+            )
+            knife("diff --name-status /").should_succeed ""
+          end
+          it "should fail in Chef 13", :chef_gte_13_only do
+            knife("upload /cookbooks").should_fail ""
+            # FIXME: include the error message here
+          end
+        end
+
+        context "as well as one extra copy of each thing" do
+          before do
+            file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x/blah.rb", ""
+            file "cookbooks/y/metadata.rb", cb_metadata("y", "1.0.0")
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          end
+
+          it "knife upload adds the new files" do
+            knife("upload /").should_succeed <<EOM
 Created /clients/y.json
 Updated /cookbooks/x
 Created /cookbooks/y
@@ -180,11 +198,11 @@ Created /nodes/y.json
 Created /roles/y.json
 Created /users/y.json
 EOM
-            knife('diff --name-status /').should_succeed ''
+            knife("diff /").should_succeed ""
           end
 
-          it 'knife upload --no-diff adds the new files' do
-            knife('upload --no-diff /').should_succeed <<EOM
+          it "knife upload --no-diff adds the new files" do
+            knife("upload --no-diff /").should_succeed <<EOM
 Created /clients/y.json
 Updated /cookbooks/x
 Created /cookbooks/y
@@ -196,15 +214,15 @@ Created /nodes/y.json
 Created /roles/y.json
 Created /users/y.json
 EOM
-            knife('diff --name-status /').should_succeed ''
+            knife("diff --name-status /").should_succeed ""
           end
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife upload does nothing' do
-          knife('upload /').should_succeed ''
-          knife('diff --name-status /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife upload does nothing" do
+          knife("upload /").should_succeed ""
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -215,8 +233,8 @@ D\t/users
 EOM
         end
 
-        it 'knife upload --purge deletes nothing' do
-          knife('upload --purge /').should_fail <<EOM
+        it "knife upload --purge deletes nothing" do
+          knife("upload --purge /").should_fail <<EOM
 ERROR: /clients cannot be deleted.
 ERROR: /cookbooks cannot be deleted.
 ERROR: /data_bags cannot be deleted.
@@ -225,7 +243,7 @@ ERROR: /nodes cannot be deleted.
 ERROR: /roles cannot be deleted.
 ERROR: /users cannot be deleted.
 EOM
-          knife('diff --name-status /').should_succeed <<EOM
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -236,178 +254,178 @@ D\t/users
 EOM
         end
 
-        context 'when current directory is top level' do
+        context "when current directory is top level" do
           before do
-            cwd '.'
+            cwd "."
           end
 
-          it 'knife upload with no parameters reports an error' do
-            knife('upload').should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+          it "knife upload with no parameters reports an error" do
+            knife("upload").should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
           end
         end
       end
     end
 
-    when_the_chef_server 'is empty' do
-      when_the_repository 'has a data bag item' do
+    when_the_chef_server "is empty" do
+      when_the_repository "has a data bag item" do
 
         before do
-          file 'data_bags/x/y.json', { 'foo' => 'bar' }
+          file "data_bags/x/y.json", { "foo" => "bar" }
         end
 
-        it 'knife upload of the data bag uploads only the values in the data bag item and no other' do
-          knife('upload /data_bags/x/y.json').should_succeed <<EOM
+        it "knife upload of the data bag uploads only the values in the data bag item and no other" do
+          knife("upload /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 EOM
-          expect(Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false).keys.sort).to eq([ 'foo', 'id' ])
+          expect(Chef::JSONCompat.parse(knife("raw /data/x/y").stdout, :create_additions => false).keys.sort).to eq([ "foo", "id" ])
         end
 
-        it 'knife upload /data_bags/x /data_bags/x/y.json uploads x once' do
-          knife('upload /data_bags/x /data_bags/x/y.json').should_succeed <<EOM
+        it "knife upload /data_bags/x /data_bags/x/y.json uploads x once" do
+          knife("upload /data_bags/x /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
         end
       end
 
-      when_the_repository 'has a data bag item with keys chef_type and data_bag' do
+      when_the_repository "has a data bag item with keys chef_type and data_bag" do
 
         before do
-          file 'data_bags/x/y.json', { 'chef_type' => 'aaa', 'data_bag' => 'bbb' }
+          file "data_bags/x/y.json", { "chef_type" => "aaa", "data_bag" => "bbb" }
         end
 
-        it 'upload preserves chef_type and data_bag' do
-          knife('upload /data_bags/x/y.json').should_succeed <<EOM
+        it "upload preserves chef_type and data_bag" do
+          knife("upload /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed ''
-          result = Chef::JSONCompat.parse(knife('raw /data/x/y').stdout, :create_additions => false)
-          expect(result.keys.sort).to eq([ 'chef_type', 'data_bag', 'id' ])
-          expect(result['chef_type']).to eq('aaa')
-          expect(result['data_bag']).to eq('bbb')
+          knife("diff --name-status /data_bags").should_succeed ""
+          result = Chef::JSONCompat.parse(knife("raw /data/x/y").stdout, :create_additions => false)
+          expect(result.keys.sort).to eq([ "chef_type", "data_bag", "id" ])
+          expect(result["chef_type"]).to eq("aaa")
+          expect(result["data_bag"]).to eq("bbb")
         end
       end
 
       # Test upload of an item when the other end doesn't even have the container
-      when_the_repository 'has two data bag items' do
+      when_the_repository "has two data bag items" do
         before do
-          file 'data_bags/x/y.json', {}
-          file 'data_bags/x/z.json', {}
+          file "data_bags/x/y.json", {}
+          file "data_bags/x/z.json", {}
         end
-        it 'knife upload of one data bag item itself succeeds' do
-          knife('upload /data_bags/x/y.json').should_succeed <<EOM
+        it "knife upload of one data bag item itself succeeds" do
+          knife("upload /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 A\t/data_bags/x/z.json
 EOM
         end
       end
     end
 
-    when_the_chef_server 'has three data bag items' do
+    when_the_chef_server "has three data bag items" do
 
       before do
-        data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} }
+        data_bag "x", { "deleted" => {}, "modified" => {}, "unmodified" => {} }
       end
 
-      when_the_repository 'has a modified, unmodified, added and deleted data bag item' do
+      when_the_repository "has a modified, unmodified, added and deleted data bag item" do
         before do
-          file 'data_bags/x/added.json', {}
-          file 'data_bags/x/modified.json', { 'foo' => 'bar' }
-          file 'data_bags/x/unmodified.json', {}
+          file "data_bags/x/added.json", {}
+          file "data_bags/x/modified.json", { "foo" => "bar" }
+          file "data_bags/x/unmodified.json", {}
         end
 
-        it 'knife upload of the modified file succeeds' do
-          knife('upload /data_bags/x/modified.json').should_succeed <<EOM
+        it "knife upload of the modified file succeeds" do
+          knife("upload /data_bags/x/modified.json").should_succeed <<EOM
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the unmodified file does nothing' do
-          knife('upload /data_bags/x/unmodified.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife upload of the unmodified file does nothing" do
+          knife("upload /data_bags/x/unmodified.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the added file succeeds' do
-          knife('upload /data_bags/x/added.json').should_succeed <<EOM
+        it "knife upload of the added file succeeds" do
+          knife("upload /data_bags/x/added.json").should_succeed <<EOM
 Created /data_bags/x/added.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 EOM
         end
-        it 'knife upload of the deleted file does nothing' do
-          knife('upload /data_bags/x/deleted.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife upload of the deleted file does nothing" do
+          knife("upload /data_bags/x/deleted.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload --purge of the deleted file deletes it' do
-          knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM
+        it "knife upload --purge of the deleted file deletes it" do
+          knife("upload --purge /data_bags/x/deleted.json").should_succeed <<EOM
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the entire data bag uploads everything' do
-          knife('upload /data_bags/x').should_succeed <<EOM
+        it "knife upload of the entire data bag uploads everything" do
+          knife("upload /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife upload --purge of the entire data bag uploads everything' do
-          knife('upload --purge /data_bags/x').should_succeed <<EOM
+        it "knife upload --purge of the entire data bag uploads everything" do
+          knife("upload --purge /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed ''
+          knife("diff --name-status /data_bags").should_succeed ""
         end
-        context 'when cwd is the /data_bags directory' do
+        context "when cwd is the /data_bags directory" do
 
           before do
-            cwd 'data_bags'
+            cwd "data_bags"
           end
 
-          it 'knife upload fails' do
-            knife('upload').should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+          it "knife upload fails" do
+            knife("upload").should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
           end
 
-          it 'knife upload --purge . uploads everything' do
-            knife('upload --purge .').should_succeed <<EOM
+          it "knife upload --purge . uploads everything" do
+            knife("upload --purge .").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
-          it 'knife upload --purge * uploads everything' do
-            knife('upload --purge *').should_succeed <<EOM
+          it "knife upload --purge * uploads everything" do
+            knife("upload --purge *").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
         end
       end
@@ -416,128 +434,128 @@ EOM
     # Cookbook upload is a funny thing ... direct cookbook upload works, but
     # upload of a file is designed not to work at present.  Make sure that is the
     # case.
-    when_the_chef_server 'has a cookbook' do
+    when_the_chef_server "has a cookbook" do
 
       before do
-        cookbook 'x', '1.0.0', { 'z.rb' => '' }
+        cookbook "x", "1.0.0", { "z.rb" => "" }
       end
 
-      when_the_repository 'has a modified, extra and missing file for the cookbook' do
+      when_the_repository "has a modified, extra and missing file for the cookbook" do
         before do
-          file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0", "#modified")
-          file 'cookbooks/x/y.rb', 'hi'
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "#modified")
+          file "cookbooks/x/y.rb", "hi"
         end
 
-        it 'knife upload of any individual file fails' do
-          knife('upload /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n"
-          knife('upload /cookbooks/x/y.rb').should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n"
-          knife('upload --purge /cookbooks/x/z.rb').should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n"
+        it "knife upload of any individual file fails" do
+          knife("upload /cookbooks/x/metadata.rb").should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n"
+          knife("upload /cookbooks/x/y.rb").should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n"
+          knife("upload --purge /cookbooks/x/z.rb").should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n"
         end
         # TODO this is a bit of an inconsistency: if we didn't specify --purge,
         # technically we shouldn't have deleted missing files.  But ... cookbooks
         # are a special case.
-        it 'knife upload of the cookbook itself succeeds' do
-          knife('upload /cookbooks/x').should_succeed <<EOM
+        it "knife upload of the cookbook itself succeeds" do
+          knife("upload /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
-        it 'knife upload --purge of the cookbook itself succeeds' do
-          knife('upload /cookbooks/x').should_succeed <<EOM
+        it "knife upload --purge of the cookbook itself succeeds" do
+          knife("upload /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
-      when_the_repository 'has a missing file for the cookbook' do
+      when_the_repository "has a missing file for the cookbook" do
 
         before do
-          file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
         end
 
-        it 'knife upload of the cookbook succeeds' do
-          knife('upload /cookbooks/x').should_succeed <<EOM
+        it "knife upload of the cookbook succeeds" do
+          knife("upload /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
-      when_the_repository 'has an extra file for the cookbook' do
+      when_the_repository "has an extra file for the cookbook" do
 
         before do
-          file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
-          file 'cookbooks/x/z.rb', ''
-          file 'cookbooks/x/blah.rb', ''
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+          file "cookbooks/x/z.rb", ""
+          file "cookbooks/x/blah.rb", ""
         end
 
-        it 'knife upload of the cookbook succeeds' do
-          knife('upload /cookbooks/x').should_succeed <<EOM
+        it "knife upload of the cookbook succeeds" do
+          knife("upload /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_repository 'has a different file in the cookbook' do
+      when_the_repository "has a different file in the cookbook" do
         before do
-          file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
         end
 
-        it 'knife upload --freeze freezes the cookbook' do
-          knife('upload --freeze /cookbooks/x').should_succeed <<EOM
+        it "knife upload --freeze freezes the cookbook" do
+          knife("upload --freeze /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
           # Modify a file and attempt to upload
-          file 'cookbooks/x/metadata.rb', 'name "x"; version "1.0.0"#different'
-          knife('upload /cookbooks/x').should_fail "ERROR: /cookbooks failed to write: Cookbook x is frozen\n"
+          file "cookbooks/x/metadata.rb", 'name "x"; version "1.0.0"#different'
+          knife("upload /cookbooks/x").should_fail "ERROR: /cookbooks failed to write: Cookbook x is frozen\n"
         end
       end
     end
 
-    when_the_chef_server 'has a frozen cookbook' do
+    when_the_chef_server "has a frozen cookbook" do
       before do
-        cookbook 'frozencook', '1.0.0', {}, :frozen => true
+        cookbook "frozencook", "1.0.0", {}, :frozen => true
       end
 
-      when_the_repository 'has an update to said cookbook' do
+      when_the_repository "has an update to said cookbook" do
 
         before do
-          file 'cookbooks/frozencook/metadata.rb', cb_metadata("frozencook", "1.0.0", "# This is different")
+          file "cookbooks/frozencook/metadata.rb", cb_metadata("frozencook", "1.0.0", "# This is different")
         end
 
-        it 'knife upload fails to upload the frozen cookbook' do
-          knife('upload /cookbooks/frozencook').should_fail "ERROR: /cookbooks failed to write: Cookbook frozencook is frozen\n"
+        it "knife upload fails to upload the frozen cookbook" do
+          knife("upload /cookbooks/frozencook").should_fail "ERROR: /cookbooks failed to write: Cookbook frozencook is frozen\n"
         end
-        it 'knife upload --force uploads the frozen cookbook' do
-          knife('upload --force /cookbooks/frozencook').should_succeed <<EOM
+        it "knife upload --force uploads the frozen cookbook" do
+          knife("upload --force /cookbooks/frozencook").should_succeed <<EOM
 Updated /cookbooks/frozencook
 EOM
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x/metadata.rb', cb_metadata('x', '1.0.0')
-        file 'cookbooks/x/onlyin1.0.0.rb', 'old_text'
+        file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x/onlyin1.0.0.rb", "old_text"
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the local version' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the local version" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
 EOM
-          knife('upload --purge /cookbooks/x').should_succeed <<EOM
+          knife("upload --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
@@ -545,35 +563,35 @@ EOM
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the local version' do
-          knife('upload --purge /cookbooks/x').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the local version" do
+          knife("upload --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the local version' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the local version" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
 EOM
-          knife('upload --purge /cookbooks/x').should_succeed <<EOM
+          knife("upload --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x/metadata.rb
 D\t/cookbooks/x/onlyin1.0.1.rb
 A\t/cookbooks/x/onlyin1.0.0.rb
@@ -581,31 +599,31 @@ EOM
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', {  'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "0.9.9", {  "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the new version' do
-          knife('upload --purge /cookbooks/x').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the new version" do
+          knife("upload --purge /cookbooks/x").should_succeed <<EOM
 Updated /cookbooks/x
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'has an environment' do
+    when_the_chef_server "has an environment" do
       before do
-        environment 'x', {}
+        environment "x", {}
       end
 
-      when_the_repository 'has an environment with bad JSON' do
+      when_the_repository "has an environment with bad JSON" do
         before do
-          file 'environments/x.json', '{'
+          file "environments/x.json", "{"
         end
 
-        it 'knife upload tries and fails' do
+        it "knife upload tries and fails" do
           error1 = <<-EOH
 WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF
                                        {
@@ -622,62 +640,75 @@ WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error
                      (right here) ------^
 
 EOH
-          knife('upload /environments/x.json').should_fail(error1)
-          knife('diff --name-status /environments/x.json').should_succeed("M\t/environments/x.json\n", :stderr => warn)
+          knife("upload /environments/x.json").should_fail(error1)
+          knife("diff --name-status /environments/x.json").should_succeed("M\t/environments/x.json\n", :stderr => warn)
         end
       end
 
-      when_the_repository 'has the same environment with the wrong name in the file' do
+      when_the_repository "has the same environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
-        it 'knife upload fails' do
-          knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
-          knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n"
+        it "knife upload fails" do
+          knife("upload /environments/x.json").should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
+          knife("diff --name-status /environments/x.json").should_succeed "M\t/environments/x.json\n"
         end
       end
 
-      when_the_repository 'has the same environment with no name in the file' do
+      when_the_repository "has the same environment with no name in the file" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'is empty' do
+    when_the_chef_server "is empty" do
 
-      when_the_repository 'has an environment with the wrong name in the file' do
+      when_the_repository "has an environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
-        it 'knife upload fails' do
-          knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
-          knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n"
+        it "knife upload fails" do
+          knife("upload /environments/x.json").should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
+          knife("diff --name-status /environments/x.json").should_succeed "A\t/environments/x.json\n"
         end
       end
 
-      when_the_repository 'has an environment with no name in the file' do
+      when_the_repository "has an environment with no name in the file" do
 
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /environments/x.json").should_succeed "Created /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
 
-      when_the_repository 'has a data bag with no id in the file' do
+      when_the_repository "has a data bag with no id in the file" do
         before do
-          file 'data_bags/bag/x.json', { 'foo' => 'bar' }
+          file "data_bags/bag/x.json", { "foo" => "bar" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
-          knife('diff --name-status /data_bags/bag/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /data_bags/bag/x.json").should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
+          knife("diff --name-status /data_bags/bag/x.json").should_succeed ""
+        end
+      end
+    end
+    when_the_chef_server "is empty" do
+      when_the_repository "has a cookbook with an invalid chef_version constraint in it" do
+        before do
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
+        end
+        it "knife upload succeeds" do
+          knife("upload /cookbooks/x").should_succeed <<EOM
+Created /cookbooks/x
+EOM
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
@@ -687,29 +718,29 @@ EOH
     when_the_chef_server "has one of each thing" do
 
       before do
-        client 'x', {}
-        cookbook 'x', '1.0.0'
-        data_bag 'x', { 'y' => {} }
-        environment 'x', {}
-        node 'x', {}
-        role 'x', {}
-        user 'x', {}
+        client "x", {}
+        cookbook "x", "1.0.0"
+        data_bag "x", { "y" => {} }
+        environment "x", {}
+        node "x", {}
+        role "x", {}
+        user "x", {}
       end
 
-      when_the_repository 'has only top-level directories' do
+      when_the_repository "has only top-level directories" do
         before do
-          directory 'clients'
-          directory 'cookbooks'
-          directory 'data_bags'
-          directory 'environments'
-          directory 'nodes'
-          directory 'roles'
-          directory 'users'
-        end
-
-        it 'knife upload does nothing' do
-          knife('upload /').should_succeed ''
-          knife('diff --name-status /').should_succeed <<EOM
+          directory "clients"
+          directory "cookbooks"
+          directory "data_bags"
+          directory "environments"
+          directory "nodes"
+          directory "roles"
+          directory "users"
+        end
+
+        it "knife upload does nothing" do
+          knife("upload /").should_succeed ""
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients/chef-validator.json
 D\t/clients/chef-webui.json
 D\t/clients/x.json
@@ -724,8 +755,8 @@ D\t/users/x.json
 EOM
         end
 
-        it 'knife upload --purge deletes everything' do
-          knife('upload --purge /').should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
+        it "knife upload --purge deletes everything" do
+          knife("upload --purge /").should_succeed(<<EOM, :stderr => "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n")
 Deleted extra entry /clients/chef-validator.json (purge is on)
 Deleted extra entry /clients/chef-webui.json (purge is on)
 Deleted extra entry /clients/x.json (purge is on)
@@ -737,52 +768,52 @@ Deleted extra entry /roles/x.json (purge is on)
 Deleted extra entry /users/admin.json (purge is on)
 Deleted extra entry /users/x.json (purge is on)
 EOM
-          knife('diff --name-status /').should_succeed <<EOM
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/environments/_default.json
 EOM
         end
       end
 
-      when_the_repository 'has an identical copy of each thing' do
+      when_the_repository "has an identical copy of each thing" do
         before do
-          file 'clients/chef-validator.json', { 'validator' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
-          file 'data_bags/x/y.json', {}
-          file 'environments/_default.json', { 'description' => 'The default Chef environment' }
-          file 'environments/x.json', {}
-          file 'nodes/x.json', {}
-          file 'roles/x.json', {}
-          file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+          file "clients/chef-validator.json", { "validator" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/chef-webui.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/_default.json", { "description" => "The default Chef environment" }
+          file "environments/x.json", {}
+          file "nodes/x.json", {}
+          file "roles/x.json", {}
+          file "users/admin.json", { "admin" => true, "public_key" => ChefZero::PUBLIC_KEY }
+          file "users/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
         end
 
-        it 'knife upload makes no changes' do
-          knife('upload /cookbooks/x-1.0.0').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife upload makes no changes" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        it 'knife upload --purge makes no changes' do
-          knife('upload --purge /').should_succeed ''
-          knife('diff --name-status /').should_succeed ''
+        it "knife upload --purge makes no changes" do
+          knife("upload --purge /").should_succeed ""
+          knife("diff --name-status /").should_succeed ""
         end
 
-        context 'except the role file' do
+        context "except the role file" do
           before do
-            file 'roles/x.json', { 'description' => 'blarghle' }
+            file "roles/x.json", { "description" => "blarghle" }
           end
 
-          it 'knife upload changes the role' do
-            knife('upload /').should_succeed "Updated /roles/x.json\n"
-            knife('diff --name-status /').should_succeed ''
+          it "knife upload changes the role" do
+            knife("upload /").should_succeed "Updated /roles/x.json\n"
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'except the role file is textually different, but not ACTUALLY different' do
+        context "except the role file is textually different, but not ACTUALLY different" do
 
           before do
-            file 'roles/x.json', <<EOM
+            file "roles/x.json", <<EOM
 {
   "chef_type": "role",
   "default_attributes":  {
@@ -801,28 +832,28 @@ EOM
 EOM
           end
 
-          it 'knife upload / does not change anything' do
-            knife('upload /').should_succeed ''
-            knife('diff --name-status /').should_succeed ''
+          it "knife upload / does not change anything" do
+            knife("upload /").should_succeed ""
+            knife("diff --name-status /").should_succeed ""
           end
         end
 
-        context 'as well as one extra copy of each thing' do
+        context "as well as one extra copy of each thing" do
           before do
-            file 'clients/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-            file 'cookbooks/x-1.0.0/blah.rb', ''
-            file 'cookbooks/x-2.0.0/metadata.rb', cb_metadata('x', '2.0.0')
-            file 'cookbooks/y-1.0.0/metadata.rb', cb_metadata('y', '1.0.0')
-            file 'data_bags/x/z.json', {}
-            file 'data_bags/y/zz.json', {}
-            file 'environments/y.json', {}
-            file 'nodes/y.json', {}
-            file 'roles/y.json', {}
-            file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY }
+            file "clients/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
+            file "cookbooks/x-1.0.0/blah.rb", ""
+            file "cookbooks/x-2.0.0/metadata.rb", cb_metadata("x", "2.0.0")
+            file "cookbooks/y-1.0.0/metadata.rb", cb_metadata("y", "1.0.0")
+            file "data_bags/x/z.json", {}
+            file "data_bags/y/zz.json", {}
+            file "environments/y.json", {}
+            file "nodes/y.json", {}
+            file "roles/y.json", {}
+            file "users/y.json", { "public_key" => ChefZero::PUBLIC_KEY }
           end
 
-          it 'knife upload adds the new files' do
-            knife('upload /').should_succeed <<EOM
+          it "knife upload adds the new files" do
+            knife("upload /").should_succeed <<EOM
 Created /clients/y.json
 Updated /cookbooks/x-1.0.0
 Created /cookbooks/x-2.0.0
@@ -835,15 +866,15 @@ Created /nodes/y.json
 Created /roles/y.json
 Created /users/y.json
 EOM
-            knife('diff --name-status /').should_succeed ''
+            knife("diff --name-status /").should_succeed ""
           end
         end
       end
 
-      when_the_repository 'is empty' do
-        it 'knife upload does nothing' do
-          knife('upload /').should_succeed ''
-          knife('diff --name-status /').should_succeed <<EOM
+      when_the_repository "is empty" do
+        it "knife upload does nothing" do
+          knife("upload /").should_succeed ""
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -854,8 +885,8 @@ D\t/users
 EOM
         end
 
-        it 'knife upload --purge deletes nothing' do
-          knife('upload --purge /').should_fail <<EOM
+        it "knife upload --purge deletes nothing" do
+          knife("upload --purge /").should_fail <<EOM
 ERROR: /clients cannot be deleted.
 ERROR: /cookbooks cannot be deleted.
 ERROR: /data_bags cannot be deleted.
@@ -864,7 +895,7 @@ ERROR: /nodes cannot be deleted.
 ERROR: /roles cannot be deleted.
 ERROR: /users cannot be deleted.
 EOM
-          knife('diff --name-status /').should_succeed <<EOM
+          knife("diff --name-status /").should_succeed <<EOM
 D\t/clients
 D\t/cookbooks
 D\t/data_bags
@@ -875,130 +906,130 @@ D\t/users
 EOM
         end
 
-        context 'when current directory is top level' do
+        context "when current directory is top level" do
           before do
-            cwd '.'
+            cwd "."
           end
-          it 'knife upload with no parameters reports an error' do
-            knife('upload').should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+          it "knife upload with no parameters reports an error" do
+            knife("upload").should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
           end
         end
       end
     end
 
     # Test upload of an item when the other end doesn't even have the container
-    when_the_chef_server 'is empty' do
-      when_the_repository 'has two data bag items' do
+    when_the_chef_server "is empty" do
+      when_the_repository "has two data bag items" do
         before do
-          file 'data_bags/x/y.json', {}
-          file 'data_bags/x/z.json', {}
+          file "data_bags/x/y.json", {}
+          file "data_bags/x/z.json", {}
         end
 
-        it 'knife upload of one data bag item itself succeeds' do
-          knife('upload /data_bags/x/y.json').should_succeed <<EOM
+        it "knife upload of one data bag item itself succeeds" do
+          knife("upload /data_bags/x/y.json").should_succeed <<EOM
 Created /data_bags/x
 Created /data_bags/x/y.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 A\t/data_bags/x/z.json
 EOM
         end
       end
     end
 
-    when_the_chef_server 'has three data bag items' do
+    when_the_chef_server "has three data bag items" do
       before do
-        data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} }
+        data_bag "x", { "deleted" => {}, "modified" => {}, "unmodified" => {} }
       end
-      when_the_repository 'has a modified, unmodified, added and deleted data bag item' do
+      when_the_repository "has a modified, unmodified, added and deleted data bag item" do
         before do
-          file 'data_bags/x/added.json', {}
-          file 'data_bags/x/modified.json', { 'foo' => 'bar' }
-          file 'data_bags/x/unmodified.json', {}
+          file "data_bags/x/added.json", {}
+          file "data_bags/x/modified.json", { "foo" => "bar" }
+          file "data_bags/x/unmodified.json", {}
         end
 
-        it 'knife upload of the modified file succeeds' do
-          knife('upload /data_bags/x/modified.json').should_succeed <<EOM
+        it "knife upload of the modified file succeeds" do
+          knife("upload /data_bags/x/modified.json").should_succeed <<EOM
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the unmodified file does nothing' do
-          knife('upload /data_bags/x/unmodified.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife upload of the unmodified file does nothing" do
+          knife("upload /data_bags/x/unmodified.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the added file succeeds' do
-          knife('upload /data_bags/x/added.json').should_succeed <<EOM
+        it "knife upload of the added file succeeds" do
+          knife("upload /data_bags/x/added.json").should_succeed <<EOM
 Created /data_bags/x/added.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 EOM
         end
-        it 'knife upload of the deleted file does nothing' do
-          knife('upload /data_bags/x/deleted.json').should_succeed ''
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+        it "knife upload of the deleted file does nothing" do
+          knife("upload /data_bags/x/deleted.json").should_succeed ""
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload --purge of the deleted file deletes it' do
-          knife('upload --purge /data_bags/x/deleted.json').should_succeed <<EOM
+        it "knife upload --purge of the deleted file deletes it" do
+          knife("upload --purge /data_bags/x/deleted.json").should_succeed <<EOM
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 M\t/data_bags/x/modified.json
 A\t/data_bags/x/added.json
 EOM
         end
-        it 'knife upload of the entire data bag uploads everything' do
-          knife('upload /data_bags/x').should_succeed <<EOM
+        it "knife upload of the entire data bag uploads everything" do
+          knife("upload /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 EOM
-          knife('diff --name-status /data_bags').should_succeed <<EOM
+          knife("diff --name-status /data_bags").should_succeed <<EOM
 D\t/data_bags/x/deleted.json
 EOM
         end
-        it 'knife upload --purge of the entire data bag uploads everything' do
-          knife('upload --purge /data_bags/x').should_succeed <<EOM
+        it "knife upload --purge of the entire data bag uploads everything" do
+          knife("upload --purge /data_bags/x").should_succeed <<EOM
 Created /data_bags/x/added.json
 Updated /data_bags/x/modified.json
 Deleted extra entry /data_bags/x/deleted.json (purge is on)
 EOM
-          knife('diff --name-status /data_bags').should_succeed ''
+          knife("diff --name-status /data_bags").should_succeed ""
         end
-        context 'when cwd is the /data_bags directory' do
+        context "when cwd is the /data_bags directory" do
           before do
-            cwd 'data_bags'
+            cwd "data_bags"
           end
-          it 'knife upload fails' do
-            knife('upload').should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
+          it "knife upload fails" do
+            knife("upload").should_fail "FATAL: Must specify at least one argument.  If you want to upload everything in this directory, type \"knife upload .\"\n", :stdout => /USAGE/
           end
-          it 'knife upload --purge . uploads everything' do
-            knife('upload --purge .').should_succeed <<EOM
+          it "knife upload --purge . uploads everything" do
+            knife("upload --purge .").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
-          it 'knife upload --purge * uploads everything' do
-            knife('upload --purge *').should_succeed <<EOM
+          it "knife upload --purge * uploads everything" do
+            knife("upload --purge *").should_succeed <<EOM
 Created x/added.json
 Updated x/modified.json
 Deleted extra entry x/deleted.json (purge is on)
 EOM
-            knife('diff --name-status /data_bags').should_succeed ''
+            knife("diff --name-status /data_bags").should_succeed ""
           end
         end
       end
@@ -1007,256 +1038,275 @@ EOM
     # Cookbook upload is a funny thing ... direct cookbook upload works, but
     # upload of a file is designed not to work at present.  Make sure that is the
     # case.
-    when_the_chef_server 'has a cookbook' do
+    when_the_chef_server "has a cookbook" do
       before do
-        cookbook 'x', '1.0.0', { 'z.rb' => '' }
+        cookbook "x", "1.0.0", { "z.rb" => "" }
       end
 
-      when_the_repository 'has a modified, extra and missing file for the cookbook' do
+      when_the_repository "has a modified, extra and missing file for the cookbook" do
         before do
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0', '#modified')
-          file 'cookbooks/x-1.0.0/y.rb', 'hi'
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0", '#modified')
+          file "cookbooks/x-1.0.0/y.rb", "hi"
         end
 
-        it 'knife upload of any individual file fails' do
-          knife('upload /cookbooks/x-1.0.0/metadata.rb').should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n"
-          knife('upload /cookbooks/x-1.0.0/y.rb').should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n"
-          knife('upload --purge /cookbooks/x-1.0.0/z.rb').should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n"
+        it "knife upload of any individual file fails" do
+          knife("upload /cookbooks/x-1.0.0/metadata.rb").should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n"
+          knife("upload /cookbooks/x-1.0.0/y.rb").should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n"
+          knife("upload --purge /cookbooks/x-1.0.0/z.rb").should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n"
         end
 
         # TODO this is a bit of an inconsistency: if we didn't specify --purge,
         # technically we shouldn't have deleted missing files.  But ... cookbooks
         # are a special case.
-        it 'knife upload of the cookbook itself succeeds' do
-          knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife upload of the cookbook itself succeeds" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
 
-        it 'knife upload --purge of the cookbook itself succeeds' do
-          knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife upload --purge of the cookbook itself succeeds" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_repository 'has a missing file for the cookbook' do
+      when_the_repository "has a missing file for the cookbook" do
         before do
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', "1.0.0")
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
         end
 
-        it 'knife upload of the cookbook succeeds' do
-          knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife upload of the cookbook succeeds" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_repository 'has an extra file for the cookbook' do
+      when_the_repository "has an extra file for the cookbook" do
         before do
-          file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
-          file 'cookbooks/x-1.0.0/z.rb', ''
-          file 'cookbooks/x-1.0.0/blah.rb', ''
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+          file "cookbooks/x-1.0.0/z.rb", ""
+          file "cookbooks/x-1.0.0/blah.rb", ""
         end
 
-        it 'knife upload of the cookbook succeeds' do
-          knife('upload /cookbooks/x-1.0.0').should_succeed <<EOM
+        it "knife upload of the cookbook succeeds" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_repository 'has a cookbook' do
+    when_the_repository "has a cookbook" do
       before do
-        file 'cookbooks/x-1.0.0/metadata.rb', cb_metadata('x', '1.0.0')
-        file 'cookbooks/x-1.0.0/onlyin1.0.0.rb', 'old_text'
+        file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0")
+        file "cookbooks/x-1.0.0/onlyin1.0.0.rb", "old_text"
       end
 
-      when_the_chef_server 'has a later version for the cookbook' do
+      when_the_chef_server "has a later version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => '' }
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks uploads the local version' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks uploads the local version" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 M\t/cookbooks/x-1.0.0/onlyin1.0.0.rb
 D\t/cookbooks/x-1.0.1
 EOM
-          knife('upload --purge /cookbooks').should_succeed <<EOM
+          knife("upload --purge /cookbooks").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 Deleted extra entry /cookbooks/x-1.0.1 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook' do
+      when_the_chef_server "has an earlier version for the cookbook" do
         before do
-          cookbook 'x', '1.0.0', { 'onlyin1.0.0.rb' => ''}
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "1.0.0", { "onlyin1.0.0.rb" => "" }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
-        it 'knife upload /cookbooks uploads the local version' do
-          knife('upload --purge /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks uploads the local version" do
+          knife("upload --purge /cookbooks").should_succeed <<EOM
 Updated /cookbooks/x-1.0.0
 Deleted extra entry /cookbooks/x-0.9.9 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has a later version for the cookbook, and no current version' do
+      when_the_chef_server "has a later version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '1.0.1', { 'onlyin1.0.1.rb' => 'hi' }
+          cookbook "x", "1.0.1", { "onlyin1.0.1.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the local version' do
-          knife('diff --name-status /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the local version" do
+          knife("diff --name-status /cookbooks").should_succeed <<EOM
 D\t/cookbooks/x-1.0.1
 A\t/cookbooks/x-1.0.0
 EOM
-          knife('upload --purge /cookbooks').should_succeed <<EOM
+          knife("upload --purge /cookbooks").should_succeed <<EOM
 Created /cookbooks/x-1.0.0
 Deleted extra entry /cookbooks/x-1.0.1 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
 
-      when_the_chef_server 'has an earlier version for the cookbook, and no current version' do
+      when_the_chef_server "has an earlier version for the cookbook, and no current version" do
         before do
-          cookbook 'x', '0.9.9', { 'onlyin0.9.9.rb' => 'hi' }
+          cookbook "x", "0.9.9", { "onlyin0.9.9.rb" => "hi" }
         end
 
-        it 'knife upload /cookbooks/x uploads the new version' do
-          knife('upload --purge /cookbooks').should_succeed <<EOM
+        it "knife upload /cookbooks/x uploads the new version" do
+          knife("upload --purge /cookbooks").should_succeed <<EOM
 Created /cookbooks/x-1.0.0
 Deleted extra entry /cookbooks/x-0.9.9 (purge is on)
 EOM
-          knife('diff --name-status /cookbooks').should_succeed ''
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'has an environment' do
+    when_the_chef_server "has an environment" do
       before do
-        environment 'x', {}
+        environment "x", {}
       end
 
-      when_the_repository 'has the same environment with the wrong name in the file' do
+      when_the_repository "has the same environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
-        it 'knife upload fails' do
-          knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
-          knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n"
+        it "knife upload fails" do
+          knife("upload /environments/x.json").should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n"
+          knife("diff --name-status /environments/x.json").should_succeed "M\t/environments/x.json\n"
         end
       end
 
-      when_the_repository 'has the same environment with no name in the file' do
+      when_the_repository "has the same environment with no name in the file" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /environments/x.json").should_succeed "Updated /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
     end
 
-    when_the_chef_server 'is empty' do
+    when_the_chef_server "is empty" do
 
-      when_the_repository 'has an environment with the wrong name in the file' do
+      when_the_repository "has an environment with the wrong name in the file" do
         before do
-          file 'environments/x.json', { 'name' => 'y' }
+          file "environments/x.json", { "name" => "y" }
         end
-        it 'knife upload fails' do
-          knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
-          knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n"
+        it "knife upload fails" do
+          knife("upload /environments/x.json").should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n"
+          knife("diff --name-status /environments/x.json").should_succeed "A\t/environments/x.json\n"
         end
       end
 
-      when_the_repository 'has an environment with no name in the file' do
+      when_the_repository "has an environment with no name in the file" do
         before do
-          file 'environments/x.json', { 'description' => 'hi' }
+          file "environments/x.json", { "description" => "hi" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n"
-          knife('diff --name-status /environments/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /environments/x.json").should_succeed "Created /environments/x.json\n"
+          knife("diff --name-status /environments/x.json").should_succeed ""
         end
       end
 
-      when_the_repository 'has a data bag with no id in the file' do
+      when_the_repository "has a data bag with no id in the file" do
         before do
-          file 'data_bags/bag/x.json', { 'foo' => 'bar' }
+          file "data_bags/bag/x.json", { "foo" => "bar" }
         end
-        it 'knife upload succeeds' do
-          knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
-          knife('diff --name-status /data_bags/bag/x.json').should_succeed ''
+        it "knife upload succeeds" do
+          knife("upload /data_bags/bag/x.json").should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n"
+          knife("diff --name-status /data_bags/bag/x.json").should_succeed ""
+        end
+      end
+    end
+
+    when_the_chef_server "is empty" do
+      when_the_repository "has a cookbook with an invalid chef_version constraint in it" do
+        before do
+          file "cookbooks/x-1.0.0/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
+        end
+        it "knife upload succeeds" do
+          knife("upload /cookbooks/x-1.0.0").should_succeed <<EOM
+Created /cookbooks/x-1.0.0
+EOM
+          knife("diff --name-status /cookbooks").should_succeed ""
         end
       end
     end
   end # with versioned cookbooks
 
-  when_the_chef_server 'has a user' do
+  when_the_chef_server "has a user" do
     before do
-      user 'x', {}
+      user "x", {}
     end
 
-    when_the_repository 'has the same user with json_class in it' do
+    when_the_repository "has the same user with json_class in it" do
       before do
-        file 'users/x.json', { 'admin' => true, 'json_class' => 'Chef::WebUIUser' }
+        file "users/x.json", { "admin" => true, "json_class" => "Chef::WebUIUser" }
       end
-      it 'knife upload /users/x.json succeeds' do
-        knife('upload /users/x.json').should_succeed "Updated /users/x.json\n"
+      it "knife upload /users/x.json succeeds" do
+        knife("upload /users/x.json").should_succeed "Updated /users/x.json\n"
       end
     end
   end
 
   when_the_chef_server "is in Enterprise mode", :osc_compat => false, :single_org => false do
     before do
-      user 'foo', {}
-      user 'bar', {}
-      user 'foobar', {}
-      organization 'foo', { 'full_name' => 'Something'}
+      user "foo", {}
+      user "bar", {}
+      user "foobar", {}
+      organization "foo", { "full_name" => "Something" }
     end
 
     before :each do
-      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo')
+      Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, "/organizations/foo")
     end
 
-    context 'and has nothing but a single group named blah' do
-      group 'blah', {}
+    context "and has nothing but a single group named blah" do
+      group "blah", {}
 
-      when_the_repository 'has one of each thing' do
+      when_the_repository "has at least one of each thing" do
 
         before do
           # TODO We have to upload acls for an existing group due to a lack of
           # dependency detection during upload.  Fix that!
-          file 'acls/groups/blah.json', {}
-          file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY }
-          file 'containers/x.json', {}
-          file 'cookbooks/x/metadata.rb', cb_metadata("x", "1.0.0")
-          file 'data_bags/x/y.json', {}
-          file 'environments/x.json', {}
-          file 'groups/x.json', {}
-          file 'invitations.json', [ 'foo' ]
-          file 'members.json', [ 'bar' ]
-          file 'nodes/x.json', {}
-          file 'org.json', { 'full_name' => 'wootles' }
-          file 'roles/x.json', {}
-        end
-
-        it 'knife upload / uploads everything' do
-          knife('upload /').should_succeed <<EOM
+          file "acls/groups/blah.json", {}
+          file "clients/x.json", { "public_key" => ChefZero::PUBLIC_KEY }
+          file "containers/x.json", {}
+          file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0")
+          file "cookbook_artifacts/x-1x1/metadata.rb", cb_metadata("x", "1.0.0")
+          file "data_bags/x/y.json", {}
+          file "environments/x.json", {}
+          file "groups/x.json", {}
+          file "invitations.json", [ "foo" ]
+          file "members.json", [ "bar" ]
+          file "org.json", { "full_name" => "wootles" }
+          file "nodes/x.json", {}
+          file "policies/x-1.0.0.json", {}
+          file "policies/blah-1.0.0.json", {}
+          file "policy_groups/x.json", { "policies" => { "x" => { "revision_id" => "1.0.0" }, "blah" => { "revision_id" => "1.0.0" } } }
+          file "roles/x.json", {}
+        end
+
+        it "knife upload / uploads everything" do
+          knife("upload /").should_succeed <<EOM
 Updated /acls/groups/blah.json
 Created /clients/x.json
 Created /containers/x.json
+Created /cookbook_artifacts/x-1x1
 Created /cookbooks/x
 Created /data_bags/x
 Created /data_bags/x/y.json
@@ -1266,105 +1316,211 @@ Updated /invitations.json
 Updated /members.json
 Created /nodes/x.json
 Updated /org.json
+Created /policies/blah-1.0.0.json
+Created /policies/x-1.0.0.json
+Created /policy_groups/x.json
 Created /roles/x.json
 EOM
-          expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo' ])
-          expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+          expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "foo" ])
+          expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
+          knife("diff --name-status --diff-filter=AMT /").should_succeed ""
+        end
+
+        context "When the chef server has an identical copy of each thing" do
+          before do
+            file "invitations.json", [ "foo" ]
+            file "members.json", [ "bar" ]
+            file "org.json", { "full_name" => "Something" }
+
+            # acl_for %w(organizations foo groups blah)
+            client "x", {}
+            cookbook "x", "1.0.0"
+            cookbook_artifact "x", "1x1", "metadata.rb" => cb_metadata("x", "1.0.0")
+            container "x", {}
+            data_bag "x", { "y" => {} }
+            environment "x", {}
+            group "x", {}
+            org_invite "foo"
+            org_member "bar"
+            node "x", {}
+            policy "x", "1.0.0", {}
+            policy "blah", "1.0.0", {}
+            policy_group "x", {
+              "policies" => {
+                "x" => { "revision_id" => "1.0.0" },
+                "blah" => { "revision_id" => "1.0.0" },
+              }
+            }
+            role "x", {}
+          end
+
+          it "knife upload makes no changes" do
+            knife("upload /").should_succeed <<EOM
+Updated /acls/groups/blah.json
+EOM
+          end
+        end
+
+        context "When the chef server has a slightly different copy of the policy revision" do
+          before do
+            policy "x", "1.0.0", { "run_list" => [ "blah" ] }
+          end
+
+          it "should fail because policies are not updateable" do
+            knife("upload /policies/x-1.0.0.json").should_fail <<EOM
+ERROR: /policies/x-1.0.0.json cannot be updated: policy revisions are immutable once uploaded. If you want to change the policy, create a new revision with your changes.
+EOM
+          end
+        end
+
+        context "When the chef server has a slightly different copy of the cookbook artifact" do
+          before do
+            cookbook_artifact "x", "1x1", { "recipes" => { "default.rb" => "" } }
+          end
+
+          it "should fail because cookbook_artifacts cannot be updated" do
+            knife("upload /cookbook_artifacts/x-1x1").should_fail <<EOM
+ERROR: /cookbook_artifacts/x-1x1 cannot be updated: cookbook artifacts are immutable once uploaded.
+EOM
+          end
+        end
+
+        context "When the chef server has a slightly different copy of each thing (except policy revisions)" do
+          before do
+            # acl_for %w(organizations foo groups blah)
+            client "x", { "validator" => true }
+            container "x", {}
+            cookbook "x", "1.0.0", { "recipes" => { "default.rb" => "" } }
+            cookbook_artifact "x", "1x1", { "metadata.rb" => cb_metadata("x", "1.0.0") }
+            data_bag "x", { "y" => { "a" => "b" } }
+            environment "x", { "description" => "foo" }
+            group "x", { "groups" => [ "admin" ] }
+            node "x", { "run_list" => [ "blah" ] }
+            policy "x", "1.0.0", {}
+            policy "x", "1.0.1", {}
+            policy "y", "1.0.0", {}
+            policy_group "x", {
+              "policies" => {
+                "x" => { "revision_id" => "1.0.1" },
+                "y" => { "revision_id" => "1.0.0" },
+              }
+            }
+            role "x", { "run_list" => [ "blah" ] }
+          end
+
+          it "knife upload updates everything" do
+            knife("upload /").should_succeed <<EOM
+Updated /acls/groups/blah.json
+Updated /clients/x.json
+Updated /cookbooks/x
+Updated /data_bags/x/y.json
+Updated /environments/x.json
+Updated /groups/x.json
+Updated /invitations.json
+Updated /members.json
+Updated /nodes/x.json
+Updated /org.json
+Created /policies/blah-1.0.0.json
+Updated /policy_groups/x.json
+Updated /roles/x.json
+EOM
+            knife("diff --name-status --diff-filter=AMT /").should_succeed ""
+          end
         end
       end
 
-      when_the_repository 'has an org.json that does not change full_name' do
+      when_the_repository "has an org.json that does not change full_name" do
         before do
-          file 'org.json', { 'full_name' => 'Something' }
+          file "org.json", { "full_name" => "Something" }
         end
 
-        it 'knife upload / emits a warning for bar and adds foo and foobar' do
-          knife('upload /').should_succeed ''
-          expect(api.get('/')['full_name']).to eq('Something')
+        it "knife upload / emits a warning for bar and adds foo and foobar" do
+          knife("upload /").should_succeed ""
+          expect(api.get("/")["full_name"]).to eq("Something")
         end
       end
 
-      when_the_repository 'has an org.json that changes full_name' do
+      when_the_repository "has an org.json that changes full_name" do
         before do
-          file 'org.json', { 'full_name' => 'Something Else'}
+          file "org.json", { "full_name" => "Something Else" }
         end
 
-        it 'knife upload / emits a warning for bar and adds foo and foobar' do
-          knife('upload /').should_succeed "Updated /org.json\n"
-          expect(api.get('/')['full_name']).to eq('Something Else')
+        it "knife upload / emits a warning for bar and adds foo and foobar" do
+          knife("upload /").should_succeed "Updated /org.json\n"
+          expect(api.get("/")["full_name"]).to eq("Something Else")
         end
       end
 
-      context 'and has invited foo and bar is already a member' do
-        org_invite 'foo'
-        org_member 'bar'
+      context "and has invited foo and bar is already a member" do
+        org_invite "foo"
+        org_member "bar"
 
-        when_the_repository 'wants to invite foo, bar and foobar' do
+        when_the_repository "wants to invite foo, bar and foobar" do
           before do
-            file 'invitations.json', [ 'foo', 'bar', 'foobar' ]
+            file "invitations.json", [ "foo", "bar", "foobar" ]
           end
 
-          it 'knife upload / emits a warning for bar and invites foobar' do
-            knife('upload /').should_succeed "Updated /invitations.json\n", :stderr => "WARN: Could not invite bar to organization foo: User bar is already in organization foo\n"
-            expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo', 'foobar' ])
-            expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+          it "knife upload / emits a warning for bar and invites foobar" do
+            knife("upload /").should_succeed "Updated /invitations.json\n", :stderr => "WARN: Could not invite bar to organization foo: User bar is already in organization foo\n"
+            expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "foo", "foobar" ])
+            expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
           end
         end
 
-        when_the_repository 'wants to make foo, bar and foobar members' do
+        when_the_repository "wants to make foo, bar and foobar members" do
           before do
-            file 'members.json', [ 'foo', 'bar', 'foobar' ]
+            file "members.json", [ "foo", "bar", "foobar" ]
           end
 
-          it 'knife upload / emits a warning for bar and adds foo and foobar' do
-            knife('upload /').should_succeed "Updated /members.json\n"
-            expect(api.get('association_requests').map { |a| a['username'] }).to eq([ ])
-            expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar', 'foo', 'foobar' ])
+          it "knife upload / emits a warning for bar and adds foo and foobar" do
+            knife("upload /").should_succeed "Updated /members.json\n"
+            expect(api.get("association_requests").map { |a| a["username"] }).to eq([ ])
+            expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar", "foo", "foobar" ])
           end
         end
 
-        when_the_repository 'wants to invite foo and have bar as a member' do
+        when_the_repository "wants to invite foo and have bar as a member" do
           before do
-            file 'invitations.json', [ 'foo' ]
-            file 'members.json', [ 'bar' ]
+            file "invitations.json", [ "foo" ]
+            file "members.json", [ "bar" ]
           end
 
-          it 'knife upload / does nothing' do
-            knife('upload /').should_succeed ''
-            expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'foo' ])
-            expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar' ])
+          it "knife upload / does nothing" do
+            knife("upload /").should_succeed ""
+            expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "foo" ])
+            expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar" ])
           end
         end
       end
 
-      context 'and has invited bar and foo' do
-        org_invite 'bar', 'foo'
+      context "and has invited bar and foo" do
+        org_invite "bar", "foo"
 
-        when_the_repository 'wants to invite foo and bar (different order)' do
+        when_the_repository "wants to invite foo and bar (different order)" do
           before do
-            file 'invitations.json', [ 'foo', 'bar' ]
+            file "invitations.json", [ "foo", "bar" ]
           end
 
-          it 'knife upload / does nothing' do
-            knife('upload /').should_succeed ''
-            expect(api.get('association_requests').map { |a| a['username'] }).to eq([ 'bar', 'foo' ])
-            expect(api.get('users').map { |a| a['user']['username'] }).to eq([ ])
+          it "knife upload / does nothing" do
+            knife("upload /").should_succeed ""
+            expect(api.get("association_requests").map { |a| a["username"] }).to eq([ "bar", "foo" ])
+            expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ ])
           end
         end
       end
 
-      context 'and has already added bar and foo as members of the org' do
-        org_member 'bar', 'foo'
+      context "and has already added bar and foo as members of the org" do
+        org_member "bar", "foo"
 
-        when_the_repository 'wants to add foo and bar (different order)' do
+        when_the_repository "wants to add foo and bar (different order)" do
           before do
-            file 'members.json', [ 'foo', 'bar' ]
+            file "members.json", [ "foo", "bar" ]
           end
 
-          it 'knife upload / does nothing' do
-            knife('upload /').should_succeed ''
-            expect(api.get('association_requests').map { |a| a['username'] }).to eq([ ])
-            expect(api.get('users').map { |a| a['user']['username'] }).to eq([ 'bar', 'foo' ])
+          it "knife upload / does nothing" do
+            knife("upload /").should_succeed ""
+            expect(api.get("association_requests").map { |a| a["username"] }).to eq([ ])
+            expect(api.get("users").map { |a| a["user"]["username"] }).to eq([ "bar", "foo" ])
           end
         end
       end
diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb
index b4c4e6c..0fc2c33 100644
--- a/spec/integration/recipes/lwrp_inline_resources_spec.rb
+++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb
@@ -1,11 +1,11 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
 
 describe "LWRPs with inline resources" do
   include IntegrationSupport
   include Chef::Mixin::ShellOut
 
-  let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
+  let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
 
   # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
   # following constraints are satisfied:
@@ -18,41 +18,111 @@ describe "LWRPs with inline resources" do
   # cf. CHEF-4914
   let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
 
+  context "with a use_inline_resources provider with 'def action_a' instead of action :a" do
+    class LwrpInlineResourcesTest < Chef::Resource::LWRPBase
+      resource_name :lwrp_inline_resources_test
+      actions :a, :nothing
+      default_action :a
+      property :ran_a
+      class Provider < Chef::Provider::LWRPBase
+        provides :lwrp_inline_resources_test
+        use_inline_resources
+        def action_a
+          r = new_resource
+          ruby_block "run a" do
+            block { r.ran_a "ran a" }
+          end
+        end
+      end
+    end
+
+    it "this is totally a bug, but for backcompat purposes, it adds the resources to the main resource collection and does not get marked updated" do
+      r = nil
+      expect_recipe {
+        r = lwrp_inline_resources_test "hi"
+      }.to have_updated("ruby_block[run a]", :run)
+      expect(r.ran_a).to eq "ran a"
+    end
+  end
+
+  context "with an inline_resources provider with two actions, one calling the other" do
+    class LwrpInlineResourcesTest2 < Chef::Resource::LWRPBase
+      resource_name :lwrp_inline_resources_test2
+      actions :a, :b, :nothing
+      default_action :b
+      property :ran_a
+      property :ran_b
+      class Provider < Chef::Provider::LWRPBase
+        provides :lwrp_inline_resources_test2
+        use_inline_resources
+
+        action :a do
+          r = new_resource
+          ruby_block "run a" do
+            block { r.ran_a "ran a" }
+          end
+        end
+
+        action :b do
+          action_a
+          r = new_resource
+          # Grab ran_a right now, before we converge
+          ran_a = r.ran_a
+          ruby_block "run b" do
+            block { r.ran_b "ran b: ran_a value was #{ran_a.inspect}" }
+          end
+        end
+      end
+    end
+
+    it "resources declared in b are executed immediately inline" do
+      r = nil
+      expect_recipe {
+        r = lwrp_inline_resources_test2 "hi" do
+          action :b
+        end
+      }.to have_updated("lwrp_inline_resources_test2[hi]", :b).
+        and have_updated("ruby_block[run a]", :run).
+        and have_updated("ruby_block[run b]", :run)
+      expect(r.ran_b).to eq "ran b: ran_a value was \"ran a\""
+    end
+  end
+
   when_the_repository "has a cookbook with a nested LWRP" do
     before do
-      directory 'cookbooks/x' do
+      directory "cookbooks/x" do
 
-        file 'resources/do_nothing.rb', <<EOM
-actions :create, :nothing
-default_action :create
-EOM
-        file 'providers/do_nothing.rb', <<EOM
-action :create do
-end
-EOM
+        file "resources/do_nothing.rb", <<-EOM
+          actions :create, :nothing
+          default_action :create
+        EOM
+        file "providers/do_nothing.rb", <<-EOM
+          action :create do
+          end
+        EOM
 
-        file 'resources/my_machine.rb', <<EOM
-actions :create, :nothing
-default_action :create
-EOM
-        file 'providers/my_machine.rb', <<EOM
-use_inline_resources
-action :create do
-  x_do_nothing 'a'
-  x_do_nothing 'b'
-end
-EOM
+        file "resources/my_machine.rb", <<-EOM
+          actions :create, :nothing
+          default_action :create
+        EOM
+        file "providers/my_machine.rb", <<-EOM
+          use_inline_resources
+          action :create do
+            x_do_nothing 'a'
+            x_do_nothing 'b'
+          end
+        EOM
 
-        file 'recipes/default.rb', <<EOM
-x_my_machine "me"
-x_my_machine "you"
-EOM
+        file "recipes/default.rb", <<-EOM
+          x_my_machine "me"
+          x_my_machine "you"
+        EOM
 
       end # directory 'cookbooks/x'
     end
 
     it "should complete with success" do
-      file 'config/client.rb', <<EOM
+      file "config/client.rb", <<EOM
 local_mode true
 cookbook_path "#{path_to('cookbooks')}"
 log_level :warn
diff --git a/spec/integration/recipes/lwrp_spec.rb b/spec/integration/recipes/lwrp_spec.rb
new file mode 100644
index 0000000..3bc008d
--- /dev/null
+++ b/spec/integration/recipes/lwrp_spec.rb
@@ -0,0 +1,53 @@
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+
+describe "LWRPs" do
+  include IntegrationSupport
+  include Chef::Mixin::ShellOut
+
+  let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
+
+  # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
+  # following constraints are satisfied:
+  # * Windows: windows can only run batch scripts as bare executables. Rubygems
+  # creates batch wrappers for installed gems, but we don't have batch wrappers
+  # in the source tree.
+  # * Other `chef-client` in PATH: A common case is running the tests on a
+  # machine that has omnibus chef installed. In that case we need to ensure
+  # we're running `chef-client` from the source tree and not the external one.
+  # cf. CHEF-4914
+  let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+
+  when_the_repository "has a cookbook named l-w-r-p" do
+    before do
+      directory "cookbooks/l-w-r-p" do
+
+        file "resources/foo.rb", <<EOM
+default_action :create
+EOM
+        file "providers/foo.rb", <<EOM
+action :create do
+end
+EOM
+
+        file "recipes/default.rb", <<EOM
+l_w_r_p_foo "me"
+EOM
+
+      end # directory 'cookbooks/x'
+    end
+
+    it "should complete with success" do
+      file "config/client.rb", <<EOM
+local_mode true
+cookbook_path "#{path_to('cookbooks')}"
+log_level :warn
+EOM
+
+      result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" --no-color -F doc -o 'l-w-r-p::default'", :cwd => chef_dir)
+      expect(result.stdout).to match(/\* l_w_r_p_foo\[me\] action create \(up to date\)/)
+      expect(result.stdout).not_to match(/WARN: You are overriding l_w_r_p_foo/)
+      result.error!
+    end
+  end
+end
diff --git a/spec/integration/recipes/provider_choice.rb b/spec/integration/recipes/provider_choice.rb
new file mode 100644
index 0000000..a9fc060
--- /dev/null
+++ b/spec/integration/recipes/provider_choice.rb
@@ -0,0 +1,37 @@
+require "support/shared/integration/integration_helper"
+
+describe "Recipe DSL methods" do
+  include IntegrationSupport
+
+  context "With resource class providing 'provider_thingy'" do
+    before :context do
+      class Chef::Resource::ProviderThingy < Chef::Resource
+        resource_name :provider_thingy
+        default_action :create
+        def to_s
+          "provider_thingy resource class"
+        end
+      end
+    end
+    context "And class Chef::Provider::ProviderThingy with no provides" do
+      before :context do
+        class Chef::Provider::ProviderThingy < Chef::Provider
+          def load_current_resource
+          end
+
+          def action_create
+            Chef::Log.warn("hello from #{self.class.name}")
+          end
+        end
+      end
+
+      it "provider_thingy 'blah' runs the provider and warns" do
+        recipe = converge {
+          provider_thingy "blah" do; end
+        }
+        expect(recipe.logged_warnings).to match /hello from Chef::Provider::ProviderThingy/
+        expect(recipe.logged_warnings).to match /you must use 'provides' to provide DSL/i
+      end
+    end
+  end
+end
diff --git a/spec/integration/recipes/recipe_dsl_spec.rb b/spec/integration/recipes/recipe_dsl_spec.rb
new file mode 100644
index 0000000..f96be7e
--- /dev/null
+++ b/spec/integration/recipes/recipe_dsl_spec.rb
@@ -0,0 +1,1519 @@
+require "support/shared/integration/integration_helper"
+
+describe "Recipe DSL methods" do
+  include IntegrationSupport
+
+  module Namer
+    extend self
+    attr_accessor :current_index
+  end
+
+  before(:all) { Namer.current_index = 1 }
+  before { Namer.current_index += 1 }
+
+  context "with resource 'base_thingy' declared as BaseThingy" do
+    before(:context) {
+
+      class BaseThingy < Chef::Resource
+        resource_name "base_thingy"
+        default_action :create
+
+        class<<self
+          attr_accessor :created_name
+          attr_accessor :created_resource
+          attr_accessor :created_provider
+        end
+
+        def provider
+          Provider
+        end
+        class Provider < Chef::Provider
+          def load_current_resource
+          end
+
+          def action_create
+            BaseThingy.created_name = new_resource.name
+            BaseThingy.created_resource = new_resource.class
+            BaseThingy.created_provider = self.class
+          end
+        end
+      end
+
+      # Modules to put stuff in
+      module RecipeDSLSpecNamespace; end
+      module RecipeDSLSpecNamespace::Bar; end
+
+    }
+
+    before :each do
+      BaseThingy.created_resource = nil
+      BaseThingy.created_provider = nil
+    end
+
+    it "creates base_thingy when you call base_thingy in a recipe" do
+      recipe = converge {
+        base_thingy "blah" do; end
+      }
+      expect(recipe.logged_warnings).to eq ""
+      expect(BaseThingy.created_name).to eq "blah"
+      expect(BaseThingy.created_resource).to eq BaseThingy
+    end
+
+    it "errors out when you call base_thingy do ... end in a recipe" do
+      expect_converge {
+        base_thingy do; end
+      }.to raise_error(ArgumentError, "You must supply a name when declaring a base_thingy resource")
+    end
+
+    it "emits a warning when you call base_thingy 'foo', 'bar' do ... end in a recipe" do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      recipe = converge {
+        base_thingy "foo", "bar" do
+        end
+      }
+      expect(recipe.logged_warnings).to match(/Cannot create resource base_thingy with more than one argument. All arguments except the name \("foo"\) will be ignored. This will cause an error in Chef 13. Arguments: \["foo", "bar"\]/)
+      expect(BaseThingy.created_name).to eq "foo"
+      expect(BaseThingy.created_resource).to eq BaseThingy
+    end
+
+    context "Deprecated automatic resource DSL" do
+      before do
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      end
+
+      context "with a resource 'backcompat_thingy' declared in Chef::Resource and Chef::Provider" do
+        before(:context) {
+
+          class Chef::Resource::BackcompatThingy < Chef::Resource
+            default_action :create
+          end
+          class Chef::Provider::BackcompatThingy < Chef::Provider
+            def load_current_resource
+            end
+
+            def action_create
+              BaseThingy.created_resource = new_resource.class
+              BaseThingy.created_provider = self.class
+            end
+          end
+
+        }
+
+        it "backcompat_thingy creates a Chef::Resource::BackcompatThingy" do
+          recipe = converge {
+            backcompat_thingy "blah" do; end
+          }
+          expect(BaseThingy.created_resource).to eq Chef::Resource::BackcompatThingy
+          expect(BaseThingy.created_provider).to eq Chef::Provider::BackcompatThingy
+        end
+
+        context "and another resource 'backcompat_thingy' in BackcompatThingy with 'provides'" do
+          before(:context) {
+
+            class RecipeDSLSpecNamespace::BackcompatThingy < BaseThingy
+              provides :backcompat_thingy
+              resource_name :backcompat_thingy
+            end
+
+          }
+
+          it "backcompat_thingy creates a BackcompatThingy" do
+            recipe = converge {
+              backcompat_thingy "blah" do; end
+            }
+            expect(recipe.logged_warnings).to match(/Class Chef::Provider::BackcompatThingy does not declare 'provides :backcompat_thingy'./)
+            expect(BaseThingy.created_resource).not_to be_nil
+          end
+        end
+      end
+
+      context "with a resource named RecipeDSLSpecNamespace::Bar::BarThingy" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::Bar::BarThingy < BaseThingy
+          end
+
+        }
+
+        it "bar_thingy does not work" do
+          expect_converge {
+            bar_thingy "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+      end
+
+      context "with a resource named Chef::Resource::NoNameThingy with resource_name nil" do
+        before(:context) {
+
+          class Chef::Resource::NoNameThingy < BaseThingy
+            resource_name nil
+          end
+
+        }
+
+        it "no_name_thingy does not work" do
+          expect_converge {
+            no_name_thingy "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+      end
+
+      context "with a resource named AnotherNoNameThingy with resource_name :another_thingy_name" do
+        before(:context) {
+
+          class AnotherNoNameThingy < BaseThingy
+            resource_name :another_thingy_name
+          end
+
+        }
+
+        it "another_no_name_thingy does not work" do
+          expect_converge {
+            another_no_name_thingy "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+
+        it "another_thingy_name works" do
+          recipe = converge {
+            another_thingy_name "blah" do; end
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq(AnotherNoNameThingy)
+        end
+      end
+
+      context "with a resource named AnotherNoNameThingy2 with resource_name :another_thingy_name2; resource_name :another_thingy_name3" do
+        before(:context) {
+
+          class AnotherNoNameThingy2 < BaseThingy
+            resource_name :another_thingy_name2
+            resource_name :another_thingy_name3
+          end
+
+        }
+
+        it "another_no_name_thingy does not work" do
+          expect_converge {
+            another_no_name_thingy2 "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+
+        it "another_thingy_name2 does not work" do
+          expect_converge {
+            another_thingy_name2 "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+
+        it "yet_another_thingy_name3 works" do
+          recipe = converge {
+            another_thingy_name3 "blah" do; end
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq(AnotherNoNameThingy2)
+        end
+      end
+
+      context "provides overriding resource_name" do
+        context "with a resource named AnotherNoNameThingy3 with provides :another_no_name_thingy3, os: 'blarghle'" do
+          before(:context) {
+
+            class AnotherNoNameThingy3 < BaseThingy
+              resource_name :another_no_name_thingy_3
+              provides :another_no_name_thingy3, os: "blarghle"
+            end
+
+          }
+
+          it "and os = linux, another_no_name_thingy3 does not work" do
+            expect_converge {
+              # TODO this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_no_name_thingy3 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_no_name_thingy3 works" do
+            recipe = converge {
+              # TODO this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_no_name_thingy3 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy3)
+          end
+        end
+
+        context "with a resource named AnotherNoNameThingy4 with two provides" do
+          before(:context) {
+
+            class AnotherNoNameThingy4 < BaseThingy
+              resource_name :another_no_name_thingy_4
+              provides :another_no_name_thingy4, os: "blarghle"
+              provides :another_no_name_thingy4, platform_family: "foo"
+            end
+
+          }
+
+          it "and os = linux, another_no_name_thingy4 does not work" do
+            expect_converge {
+              # TODO this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_no_name_thingy4 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_no_name_thingy4 works" do
+            recipe = converge {
+              # TODO this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_no_name_thingy4 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy4)
+          end
+
+          it "and platform_family = foo, another_no_name_thingy4 works" do
+            recipe = converge {
+              # TODO this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:platform_family] = "foo"
+              another_no_name_thingy4 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy4)
+          end
+        end
+
+        context "with a resource named AnotherNoNameThingy5, a different resource_name, and a provides with the original resource_name" do
+          before(:context) {
+
+            class AnotherNoNameThingy5 < BaseThingy
+              resource_name :another_thingy_name_for_another_no_name_thingy5
+              provides :another_no_name_thingy5, os: "blarghle"
+            end
+
+          }
+
+          it "and os = linux, another_no_name_thingy5 does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_no_name_thingy5 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_no_name_thingy5 works" do
+            recipe = converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_no_name_thingy5 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy5)
+          end
+
+          it "the new resource name can be used in a recipe" do
+            recipe = converge {
+              another_thingy_name_for_another_no_name_thingy5 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy5)
+          end
+        end
+
+        context "with a resource named AnotherNoNameThingy6, a provides with the original resource name, and a different resource_name" do
+          before(:context) {
+
+            class AnotherNoNameThingy6 < BaseThingy
+              provides :another_no_name_thingy6, os: "blarghle"
+              resource_name :another_thingy_name_for_another_no_name_thingy6
+            end
+
+          }
+
+          it "and os = linux, another_no_name_thingy6 does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_no_name_thingy6 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_no_name_thingy6 works" do
+            recipe = converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_no_name_thingy6 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy6)
+          end
+
+          it "the new resource name can be used in a recipe" do
+            recipe = converge {
+              another_thingy_name_for_another_no_name_thingy6 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy6)
+          end
+        end
+
+        context "with a resource named AnotherNoNameThingy7, a new resource_name, and provides with that new resource name" do
+          before(:context) {
+
+            class AnotherNoNameThingy7 < BaseThingy
+              resource_name :another_thingy_name_for_another_no_name_thingy7
+              provides :another_thingy_name_for_another_no_name_thingy7, os: "blarghle"
+            end
+
+          }
+
+          it "and os = linux, another_thingy_name_for_another_no_name_thingy7 does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_thingy_name_for_another_no_name_thingy7 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_thingy_name_for_another_no_name_thingy7 works" do
+            recipe = converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_thingy_name_for_another_no_name_thingy7 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy7)
+          end
+
+          it "the old resource name does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_no_name_thingy_7 "blah" do; end
+            }.to raise_error(NoMethodError)
+          end
+        end
+
+        # opposite order from the previous test (provides, then resource_name)
+        context "with a resource named AnotherNoNameThingy8, a provides with a new resource name, and resource_name with that new resource name" do
+          before(:context) {
+
+            class AnotherNoNameThingy8 < BaseThingy
+              provides :another_thingy_name_for_another_no_name_thingy8, os: "blarghle"
+              resource_name :another_thingy_name_for_another_no_name_thingy8
+            end
+
+          }
+
+          it "and os = linux, another_thingy_name_for_another_no_name_thingy8 does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_thingy_name_for_another_no_name_thingy8 "blah" do; end
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+          end
+
+          it "and os = blarghle, another_thingy_name_for_another_no_name_thingy8 works" do
+            recipe = converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "blarghle"
+              another_thingy_name_for_another_no_name_thingy8 "blah" do; end
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq (AnotherNoNameThingy8)
+          end
+
+          it "the old resource name does not work" do
+            expect_converge {
+              # this is an ugly way to test, make Cheffish expose node attrs
+              run_context.node.automatic[:os] = "linux"
+              another_thingy_name8 "blah" do; end
+            }.to raise_error(NoMethodError)
+          end
+        end
+      end
+    end
+
+    context "provides" do
+      context "when MySupplier provides :hemlock" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::MySupplier < BaseThingy
+            resource_name :hemlock
+          end
+
+        }
+
+        it "my_supplier does not work in a recipe" do
+          expect_converge {
+            my_supplier "blah" do; end
+          }.to raise_error(NoMethodError)
+        end
+
+        it "hemlock works in a recipe" do
+          expect_recipe {
+            hemlock "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::MySupplier
+        end
+      end
+
+      context "when Thingy3 has resource_name :thingy3" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
+            resource_name :thingy3
+          end
+
+        }
+
+        it "thingy3 works in a recipe" do
+          expect_recipe {
+            thingy3 "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+        end
+
+        context "and Thingy4 has resource_name :thingy3" do
+          before(:context) {
+
+            class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+              resource_name :thingy3
+            end
+
+          }
+
+          it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
+            recipe = converge {
+              thingy3 "blah" do; end
+            }
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+          end
+
+          it "thingy4 does not work in a recipe" do
+            expect_converge {
+              thingy4 "blah" do; end
+            }.to raise_error(NoMethodError)
+          end
+
+          it "resource_matching_short_name returns Thingy4" do
+            expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
+          end
+        end
+      end
+
+      context "when Thingy5 has resource_name :thingy5 and provides :thingy5reverse, :thingy5_2 and :thingy5_2reverse" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::Thingy5 < BaseThingy
+            resource_name :thingy5
+            provides :thingy5reverse
+            provides :thingy5_2
+            provides :thingy5_2reverse
+          end
+
+        }
+
+        it "thingy5 works in a recipe" do
+          expect_recipe {
+            thingy5 "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+        end
+
+        context "and Thingy6 provides :thingy5" do
+          before(:context) {
+
+            class RecipeDSLSpecNamespace::Thingy6 < BaseThingy
+              resource_name :thingy6
+              provides :thingy5
+            end
+
+          }
+
+          it "thingy6 works in a recipe and yields Thingy6" do
+            recipe = converge {
+              thingy6 "blah" do; end
+            }
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy6
+          end
+
+          it "thingy5 works in a recipe and yields Foo::Thingy5 (the alphabetical one)" do
+            recipe = converge {
+              thingy5 "blah" do; end
+            }
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+          end
+
+          it "resource_matching_short_name returns Thingy5" do
+            expect(Chef::Resource.resource_matching_short_name(:thingy5)).to eq RecipeDSLSpecNamespace::Thingy5
+          end
+
+          context "and AThingy5 provides :thingy5reverse" do
+            before(:context) {
+
+              class RecipeDSLSpecNamespace::AThingy5 < BaseThingy
+                resource_name :thingy5reverse
+              end
+
+            }
+
+            it "thingy5reverse works in a recipe and yields AThingy5 (the alphabetical one)" do
+              recipe = converge {
+                thingy5reverse "blah" do; end
+              }
+              expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::AThingy5
+            end
+          end
+
+          context "and ZRecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
+            before(:context) {
+
+              module ZRecipeDSLSpecNamespace
+                class Thingy5 < BaseThingy
+                  resource_name :thingy5_2
+                end
+              end
+
+            }
+
+            it "thingy5_2 works in a recipe and yields the RecipeDSLSpaceNamespace one (the alphabetical one)" do
+              recipe = converge {
+                thingy5_2 "blah" do; end
+              }
+              expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy5
+            end
+          end
+
+          context "and ARecipeDSLSpecNamespace::Thingy5 provides :thingy5_2" do
+            before(:context) {
+
+              module ARecipeDSLSpecNamespace
+                class Thingy5 < BaseThingy
+                  resource_name :thingy5_2reverse
+                end
+              end
+
+            }
+
+            it "thingy5_2reverse works in a recipe and yields the ARecipeDSLSpaceNamespace one (the alphabetical one)" do
+              recipe = converge {
+                thingy5_2reverse "blah" do; end
+              }
+              expect(BaseThingy.created_resource).to eq ARecipeDSLSpecNamespace::Thingy5
+            end
+          end
+        end
+
+        context "when Thingy3 has resource_name :thingy3" do
+          before(:context) {
+
+            class RecipeDSLSpecNamespace::Thingy3 < BaseThingy
+              resource_name :thingy3
+            end
+
+          }
+
+          it "thingy3 works in a recipe" do
+            expect_recipe {
+              thingy3 "blah" do; end
+            }.to emit_no_warnings_or_errors
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+          end
+
+          context "and Thingy4 has resource_name :thingy3" do
+            before(:context) {
+
+              class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+                resource_name :thingy3
+              end
+
+            }
+
+            it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
+              recipe = converge {
+                thingy3 "blah" do; end
+              }
+              expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+            end
+
+            it "thingy4 does not work in a recipe" do
+              expect_converge {
+                thingy4 "blah" do; end
+              }.to raise_error(NoMethodError)
+            end
+
+            it "resource_matching_short_name returns Thingy4" do
+              expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
+            end
+          end
+
+          context "and Thingy4 has resource_name :thingy3" do
+            before(:context) {
+
+              class RecipeDSLSpecNamespace::Thingy4 < BaseThingy
+                resource_name :thingy3
+              end
+
+            }
+
+            it "thingy3 works in a recipe and yields Thingy3 (the alphabetical one)" do
+              recipe = converge {
+                thingy3 "blah" do; end
+              }
+              expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy3
+            end
+
+            it "thingy4 does not work in a recipe" do
+              expect_converge {
+                thingy4 "blah" do; end
+              }.to raise_error(NoMethodError)
+            end
+
+            it "resource_matching_short_name returns Thingy4" do
+              expect(Chef::Resource.resource_matching_short_name(:thingy3)).to eq RecipeDSLSpecNamespace::Thingy3
+            end
+          end
+        end
+
+      end
+
+      context "when Thingy7 provides :thingy8" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::Thingy7 < BaseThingy
+            resource_name :thingy7
+            provides :thingy8
+          end
+
+        }
+
+        context "and Thingy8 has resource_name :thingy8" do
+          before(:context) {
+
+            class RecipeDSLSpecNamespace::Thingy8 < BaseThingy
+              resource_name :thingy8
+            end
+
+          }
+
+          it "thingy7 works in a recipe and yields Thingy7" do
+            recipe = converge {
+              thingy7 "blah" do; end
+            }
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
+          end
+
+          it "thingy8 works in a recipe and yields Thingy7 (alphabetical)" do
+            recipe = converge {
+              thingy8 "blah" do; end
+            }
+            expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy7
+          end
+
+          it "resource_matching_short_name returns Thingy8" do
+            expect(Chef::Resource.resource_matching_short_name(:thingy8)).to eq RecipeDSLSpecNamespace::Thingy8
+          end
+        end
+      end
+
+      context "when Thingy12 provides :thingy12, :twizzle and :twizzle2" do
+        before(:context) {
+
+          class RecipeDSLSpecNamespace::Thingy12 < BaseThingy
+            resource_name :thingy12
+            provides :twizzle
+            provides :twizzle2
+          end
+
+        }
+
+        it "thingy12 works in a recipe and yields Thingy12" do
+          expect_recipe {
+            thingy12 "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
+        end
+
+        it "twizzle works in a recipe and yields Thingy12" do
+          expect_recipe {
+            twizzle "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
+        end
+
+        it "twizzle2 works in a recipe and yields Thingy12" do
+          expect_recipe {
+            twizzle2 "blah" do; end
+          }.to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq RecipeDSLSpecNamespace::Thingy12
+        end
+      end
+
+      context "with platform-specific resources 'my_super_thingy_foo' and 'my_super_thingy_bar'" do
+        before(:context) {
+          class MySuperThingyFoo < BaseThingy
+            resource_name :my_super_thingy_foo
+            provides :my_super_thingy, platform: "foo"
+          end
+
+          class MySuperThingyBar < BaseThingy
+            resource_name :my_super_thingy_bar
+            provides :my_super_thingy, platform: "bar"
+          end
+        }
+
+        it "A run with platform 'foo' uses MySuperThingyFoo" do
+          r = Cheffish::ChefRun.new(chef_config)
+          r.client.run_context.node.automatic["platform"] = "foo"
+          r.compile_recipe {
+            my_super_thingy "blah" do; end
+          }
+          r.converge
+          expect(r).to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq MySuperThingyFoo
+        end
+
+        it "A run with platform 'bar' uses MySuperThingyBar" do
+          r = Cheffish::ChefRun.new(chef_config)
+          r.client.run_context.node.automatic["platform"] = "bar"
+          r.compile_recipe {
+            my_super_thingy "blah" do; end
+          }
+          r.converge
+          expect(r).to emit_no_warnings_or_errors
+          expect(BaseThingy.created_resource).to eq MySuperThingyBar
+        end
+
+        it "A run with platform 'x' reports that my_super_thingy is not supported" do
+          r = Cheffish::ChefRun.new(chef_config)
+          r.client.run_context.node.automatic["platform"] = "x"
+          expect {
+            r.compile_recipe {
+              my_super_thingy "blah" do; end
+            }
+          }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+        end
+      end
+
+      context "when Thingy10 provides :thingy10" do
+        before(:context) {
+          class RecipeDSLSpecNamespace::Thingy10 < BaseThingy
+            resource_name :thingy10
+          end
+        }
+
+        it "declaring a resource providing the same :thingy10 with override: true does not produce a warning" do
+          expect(Chef::Log).not_to receive(:warn)
+          class RecipeDSLSpecNamespace::Thingy10AlternateProvider < BaseThingy
+            provides :thingy10, override: true
+          end
+        end
+      end
+
+      context "when Thingy11 provides :thingy11" do
+        before(:context) {
+          class RecipeDSLSpecNamespace::Thingy11 < BaseThingy
+            resource_name :thingy10
+          end
+        }
+
+        it "declaring a resource providing the same :thingy11 with os: 'linux' does not produce a warning" do
+          expect(Chef::Log).not_to receive(:warn)
+          class RecipeDSLSpecNamespace::Thingy11AlternateProvider < BaseThingy
+            provides :thingy11, os: "linux"
+          end
+        end
+      end
+    end
+
+    context "with a resource named 'B' with resource name :two_classes_one_dsl" do
+      let(:two_classes_one_dsl) { :"two_classes_one_dsl#{Namer.current_index}" }
+      let(:resource_class) {
+        result = Class.new(BaseThingy) do
+          def self.name
+            "B"
+          end
+
+          def self.to_s; name; end
+
+          def self.inspect; name.inspect; end
+        end
+        result.resource_name two_classes_one_dsl
+        result
+      }
+      before { resource_class } # pull on it so it gets defined before the recipe runs
+
+      context "and another resource named 'A' with resource_name :two_classes_one_dsl" do
+        let(:resource_class_a) {
+          result = Class.new(BaseThingy) do
+            def self.name
+              "A"
+            end
+
+            def self.to_s; name; end
+
+            def self.inspect; name.inspect; end
+          end
+          result.resource_name two_classes_one_dsl
+          result
+        }
+        before { resource_class_a } # pull on it so it gets defined before the recipe runs
+
+        it "two_classes_one_dsl resolves to A (alphabetically earliest)" do
+          two_classes_one_dsl = self.two_classes_one_dsl
+          recipe = converge {
+            instance_eval("#{two_classes_one_dsl} 'blah'")
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq resource_class_a
+        end
+
+        it "resource_matching_short_name returns B" do
+          expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class_a
+        end
+      end
+
+      context "and another resource named 'Z' with resource_name :two_classes_one_dsl" do
+        let(:resource_class_z) {
+          result = Class.new(BaseThingy) do
+            def self.name
+              "Z"
+            end
+
+            def self.to_s; name; end
+
+            def self.inspect; name.inspect; end
+          end
+          result.resource_name two_classes_one_dsl
+          result
+        }
+        before { resource_class_z } # pull on it so it gets defined before the recipe runs
+
+        it "two_classes_one_dsl resolves to B (alphabetically earliest)" do
+          two_classes_one_dsl = self.two_classes_one_dsl
+          recipe = converge {
+            instance_eval("#{two_classes_one_dsl} 'blah'")
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq resource_class
+        end
+
+        it "resource_matching_short_name returns B" do
+          expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+        end
+
+        context "and a priority array [ Z, B ]" do
+          before do
+            Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z, resource_class ])
+          end
+
+          it "two_classes_one_dsl resolves to Z (respects the priority array)" do
+            two_classes_one_dsl = self.two_classes_one_dsl
+            recipe = converge {
+              instance_eval("#{two_classes_one_dsl} 'blah'")
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq resource_class_z
+          end
+
+          it "resource_matching_short_name returns B" do
+            expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+          end
+
+          context "when Z provides(:two_classes_one_dsl) { false }" do
+            before do
+              resource_class_z.provides(two_classes_one_dsl) { false }
+            end
+
+            it "two_classes_one_dsl resolves to B (picks the next thing in the priority array)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_resource).to eq resource_class
+            end
+
+            it "resource_matching_short_name returns B" do
+              expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+            end
+          end
+        end
+
+        context "and priority arrays [ B ] and [ Z ]" do
+          before do
+            Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class ])
+            Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z ])
+          end
+
+          it "two_classes_one_dsl resolves to Z (respects the most recent priority array)" do
+            two_classes_one_dsl = self.two_classes_one_dsl
+            recipe = converge {
+              instance_eval("#{two_classes_one_dsl} 'blah'")
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq resource_class_z
+          end
+
+          it "resource_matching_short_name returns B" do
+            expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+          end
+
+          context "when Z provides(:two_classes_one_dsl) { false }" do
+            before do
+              resource_class_z.provides(two_classes_one_dsl) { false }
+            end
+
+            it "two_classes_one_dsl resolves to B (picks the first match from the other priority array)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_resource).to eq resource_class
+            end
+
+            it "resource_matching_short_name returns B" do
+              expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+            end
+          end
+        end
+
+        context "and a priority array [ Z ]" do
+          before do
+            Chef.set_resource_priority_array(two_classes_one_dsl, [ resource_class_z ])
+          end
+
+          context "when Z provides(:two_classes_one_dsl) { false }" do
+            before do
+              resource_class_z.provides(two_classes_one_dsl) { false }
+            end
+
+            it "two_classes_one_dsl resolves to B (picks the first match outside the priority array)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_resource).to eq resource_class
+            end
+
+            it "resource_matching_short_name returns B" do
+              expect(Chef::Resource.resource_matching_short_name(two_classes_one_dsl)).to eq resource_class
+            end
+          end
+        end
+
+      end
+
+      context "and a provider named 'B' which provides :two_classes_one_dsl" do
+        before do
+          resource_class.send(:define_method, :provider) { nil }
+        end
+
+        let(:provider_class) {
+          result = Class.new(BaseThingy::Provider) do
+            def self.name
+              "B"
+            end
+
+            def self.to_s; name; end
+
+            def self.inspect; name.inspect; end
+          end
+          result.provides two_classes_one_dsl
+          result
+        }
+        before { provider_class } # pull on it so it gets defined before the recipe runs
+
+        context "and another provider named 'A'" do
+          let(:provider_class_a) {
+            result = Class.new(BaseThingy::Provider) do
+              def self.name
+                "A"
+              end
+
+              def self.to_s; name; end
+
+              def self.inspect; name.inspect; end
+            end
+            result
+          }
+          context "which provides :two_classes_one_dsl" do
+            before { provider_class_a.provides two_classes_one_dsl }
+
+            it "two_classes_one_dsl resolves to A (alphabetically earliest)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_provider).to eq provider_class_a
+            end
+          end
+          context "which provides(:two_classes_one_dsl) { false }" do
+            before { provider_class_a.provides(two_classes_one_dsl) { false } }
+
+            it "two_classes_one_dsl resolves to B (since A declined)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_provider).to eq provider_class
+            end
+          end
+        end
+
+        context "and another provider named 'Z'" do
+          let(:provider_class_z) {
+            result = Class.new(BaseThingy::Provider) do
+              def self.name
+                "Z"
+              end
+
+              def self.to_s; name; end
+
+              def self.inspect; name.inspect; end
+            end
+            result
+          }
+          before { provider_class_z } # pull on it so it gets defined before the recipe runs
+
+          context "which provides :two_classes_one_dsl" do
+            before { provider_class_z.provides two_classes_one_dsl }
+
+            it "two_classes_one_dsl resolves to B (alphabetically earliest)" do
+              two_classes_one_dsl = self.two_classes_one_dsl
+              recipe = converge {
+                instance_eval("#{two_classes_one_dsl} 'blah'")
+              }
+              expect(recipe.logged_warnings).to eq ""
+              expect(BaseThingy.created_provider).to eq provider_class
+            end
+
+            context "with a priority array [ Z, B ]" do
+              before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] }
+
+              it "two_classes_one_dsl resolves to Z (respects the priority map)" do
+                two_classes_one_dsl = self.two_classes_one_dsl
+                recipe = converge {
+                  instance_eval("#{two_classes_one_dsl} 'blah'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class_z
+              end
+            end
+          end
+
+          context "which provides(:two_classes_one_dsl) { false }" do
+            before { provider_class_z.provides(two_classes_one_dsl) { false } }
+
+            context "with a priority array [ Z, B ]" do
+              before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z, provider_class ] }
+
+              it "two_classes_one_dsl resolves to B (the next one in the priority map)" do
+                two_classes_one_dsl = self.two_classes_one_dsl
+                recipe = converge {
+                  instance_eval("#{two_classes_one_dsl} 'blah'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class
+              end
+            end
+
+            context "with priority arrays [ B ] and [ Z ]" do
+              before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class_z ] }
+              before { Chef.set_provider_priority_array two_classes_one_dsl, [ provider_class ] }
+
+              it "two_classes_one_dsl resolves to B (the one in the next priority map)" do
+                two_classes_one_dsl = self.two_classes_one_dsl
+                recipe = converge {
+                  instance_eval("#{two_classes_one_dsl} 'blah'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class
+              end
+            end
+          end
+        end
+      end
+
+      context "and another resource Blarghle with provides :two_classes_one_dsl, os: 'blarghle'" do
+        let(:resource_class_blarghle) {
+          result = Class.new(BaseThingy) do
+            def self.name
+              "Blarghle"
+            end
+
+            def self.to_s; name; end
+
+            def self.inspect; name.inspect; end
+          end
+          result.resource_name two_classes_one_dsl
+          result.provides two_classes_one_dsl, os: "blarghle"
+          result
+        }
+        before { resource_class_blarghle } # pull on it so it gets defined before the recipe runs
+
+        it "on os = blarghle, two_classes_one_dsl resolves to Blarghle" do
+          two_classes_one_dsl = self.two_classes_one_dsl
+          recipe = converge {
+            # this is an ugly way to test, make Cheffish expose node attrs
+            run_context.node.automatic[:os] = "blarghle"
+            instance_eval("#{two_classes_one_dsl} 'blah' do; end")
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq resource_class_blarghle
+        end
+
+        it "on os = linux, two_classes_one_dsl resolves to B" do
+          two_classes_one_dsl = self.two_classes_one_dsl
+          recipe = converge {
+            # this is an ugly way to test, make Cheffish expose node attrs
+            run_context.node.automatic[:os] = "linux"
+            instance_eval("#{two_classes_one_dsl} 'blah' do; end")
+          }
+          expect(recipe.logged_warnings).to eq ""
+          expect(BaseThingy.created_resource).to eq resource_class
+        end
+      end
+    end
+
+    context "with a resource MyResource" do
+      let(:resource_class) { Class.new(BaseThingy) do
+        def self.called_provides
+          @called_provides
+        end
+
+        def to_s
+          "MyResource"
+        end
+      end }
+      let(:my_resource) { :"my_resource#{Namer.current_index}" }
+      let(:blarghle_blarghle_little_star) { :"blarghle_blarghle_little_star#{Namer.current_index}" }
+
+      context "with resource_name :my_resource" do
+        before {
+          resource_class.resource_name my_resource
+        }
+
+        context "with provides? returning true to my_resource" do
+          before {
+            my_resource = self.my_resource
+            resource_class.define_singleton_method(:provides?) do |node, resource_name|
+              @called_provides = true
+              resource_name == my_resource
+            end
+          }
+
+          it "my_resource returns the resource and calls provides?, but does not emit a warning" do
+            dsl_name = self.my_resource
+            recipe = converge {
+              instance_eval("#{dsl_name} 'foo'")
+            }
+            expect(recipe.logged_warnings).to eq ""
+            expect(BaseThingy.created_resource).to eq resource_class
+            expect(resource_class.called_provides).to be_truthy
+          end
+        end
+
+        context "with provides? returning true to blarghle_blarghle_little_star and not resource_name" do
+          before do
+            blarghle_blarghle_little_star = self.blarghle_blarghle_little_star
+            resource_class.define_singleton_method(:provides?) do |node, resource_name|
+              @called_provides = true
+              resource_name == blarghle_blarghle_little_star
+            end
+          end
+
+          it "my_resource does not return the resource" do
+            dsl_name = self.my_resource
+            expect_converge {
+              instance_eval("#{dsl_name} 'foo'")
+            }.to raise_error(Chef::Exceptions::NoSuchResourceType)
+            expect(resource_class.called_provides).to be_truthy
+          end
+
+          it "blarghle_blarghle_little_star 'foo' returns the resource and emits a warning" do
+            Chef::Config[:treat_deprecation_warnings_as_errors] = false
+            dsl_name = self.blarghle_blarghle_little_star
+            recipe = converge {
+              instance_eval("#{dsl_name} 'foo'")
+            }
+            expect(recipe.logged_warnings).to include "WARN: #{resource_class}.provides? returned true when asked if it provides DSL #{dsl_name}, but provides :#{dsl_name} was never called!"
+            expect(BaseThingy.created_resource).to eq resource_class
+            expect(resource_class.called_provides).to be_truthy
+          end
+        end
+
+        context "and a provider" do
+          let(:provider_class) do
+            Class.new(BaseThingy::Provider) do
+              def self.name
+                "MyProvider"
+              end
+
+              def self.to_s; name; end
+
+              def self.inspect; name.inspect; end
+
+              def self.called_provides
+                @called_provides
+              end
+            end
+          end
+
+          before do
+            resource_class.send(:define_method, :provider) { nil }
+          end
+
+          context "that provides :my_resource" do
+            before do
+              provider_class.provides my_resource
+            end
+
+            context "with supports? returning true" do
+              before do
+                provider_class.define_singleton_method(:supports?) { |resource, action| true }
+              end
+
+              it "my_resource runs the provider and does not emit a warning" do
+                my_resource = self.my_resource
+                recipe = converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class
+              end
+
+              context "and another provider supporting :my_resource with supports? false" do
+                let(:provider_class2) do
+                  Class.new(BaseThingy::Provider) do
+                    def self.name
+                      "MyProvider2"
+                    end
+
+                    def self.to_s; name; end
+
+                    def self.inspect; name.inspect; end
+
+                    def self.called_provides
+                      @called_provides
+                    end
+                    provides my_resource
+                    def self.supports?(resource, action)
+                      false
+                    end
+                  end
+                end
+
+                it "my_resource runs the first provider" do
+                  my_resource = self.my_resource
+                  recipe = converge {
+                    instance_eval("#{my_resource} 'foo'")
+                  }
+                  expect(recipe.logged_warnings).to eq ""
+                  expect(BaseThingy.created_provider).to eq provider_class
+                end
+              end
+            end
+
+            context "with supports? returning false" do
+              before do
+                provider_class.define_singleton_method(:supports?) { |resource, action| false }
+              end
+
+              # TODO no warning? ick
+              it "my_resource runs the provider anyway" do
+                my_resource = self.my_resource
+                recipe = converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class
+              end
+
+              context "and another provider supporting :my_resource with supports? true" do
+                let(:provider_class2) do
+                  my_resource = self.my_resource
+                  Class.new(BaseThingy::Provider) do
+                    def self.name
+                      "MyProvider2"
+                    end
+
+                    def self.to_s; name; end
+
+                    def self.inspect; name.inspect; end
+
+                    def self.called_provides
+                      @called_provides
+                    end
+                    provides my_resource
+                    def self.supports?(resource, action)
+                      true
+                    end
+                  end
+                end
+                before { provider_class2 } # make sure the provider class shows up
+
+                it "my_resource runs the other provider" do
+                  my_resource = self.my_resource
+                  recipe = converge {
+                    instance_eval("#{my_resource} 'foo'")
+                  }
+                  expect(recipe.logged_warnings).to eq ""
+                  expect(BaseThingy.created_provider).to eq provider_class2
+                end
+              end
+            end
+          end
+
+          context "with provides? returning true" do
+            before {
+              my_resource = self.my_resource
+              provider_class.define_singleton_method(:provides?) do |node, resource|
+                @called_provides = true
+                resource.declared_type == my_resource
+              end
+            }
+
+            context "that provides :my_resource" do
+              before {
+                provider_class.provides my_resource
+              }
+
+              it "my_resource calls the provider (and calls provides?), but does not emit a warning" do
+                my_resource = self.my_resource
+                recipe = converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }
+                expect(recipe.logged_warnings).to eq ""
+                expect(BaseThingy.created_provider).to eq provider_class
+                expect(provider_class.called_provides).to be_truthy
+              end
+            end
+
+            context "that does not call provides :my_resource" do
+              it "my_resource calls the provider (and calls provides?), and emits a warning" do
+                Chef::Config[:treat_deprecation_warnings_as_errors] = false
+                my_resource = self.my_resource
+                recipe = converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }
+                expect(recipe.logged_warnings).to include("WARN: #{provider_class}.provides? returned true when asked if it provides DSL #{my_resource}, but provides :#{my_resource} was never called!")
+                expect(BaseThingy.created_provider).to eq provider_class
+                expect(provider_class.called_provides).to be_truthy
+              end
+            end
+          end
+
+          context "with provides? returning false to my_resource" do
+            before {
+              my_resource = self.my_resource
+              provider_class.define_singleton_method(:provides?) do |node, resource|
+                @called_provides = true
+                false
+              end
+            }
+
+            context "that provides :my_resource" do
+              before {
+                provider_class.provides my_resource
+              }
+
+              it "my_resource fails to find a provider (and calls provides)" do
+                my_resource = self.my_resource
+                expect_converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }.to raise_error(Chef::Exceptions::ProviderNotFound)
+                expect(provider_class.called_provides).to be_truthy
+              end
+            end
+
+            context "that does not provide :my_resource" do
+              it "my_resource fails to find a provider (and calls provides)" do
+                my_resource = self.my_resource
+                expect_converge {
+                  instance_eval("#{my_resource} 'foo'")
+                }.to raise_error(Chef::Exceptions::ProviderNotFound)
+                expect(provider_class.called_provides).to be_truthy
+              end
+            end
+          end
+        end
+      end
+    end
+  end
+
+  before(:all) { Namer.current_index = 0 }
+  before { Namer.current_index += 1 }
+
+  context "with an LWRP that declares actions" do
+    let(:resource_class) {
+      Class.new(Chef::Resource::LWRPBase) do
+        provides :"recipe_dsl_spec#{Namer.current_index}"
+        actions :create
+      end
+    }
+    let(:resource) {
+      resource_class.new("blah", run_context)
+    }
+    it "The actions are part of actions along with :nothing" do
+      expect(resource_class.actions).to eq [ :nothing, :create ]
+    end
+    it "The actions are part of allowed_actions along with :nothing" do
+      expect(resource.allowed_actions).to eq [ :nothing, :create ]
+    end
+
+    context "and a subclass that declares more actions" do
+      let(:subresource_class) {
+        Class.new(Chef::Resource::LWRPBase) do
+          provides :"recipe_dsl_spec_sub#{Namer.current_index}"
+          actions :delete
+        end
+      }
+      let(:subresource) {
+        subresource_class.new("subblah", run_context)
+      }
+
+      it "The parent class actions are not part of actions" do
+        expect(subresource_class.actions).to eq [ :nothing, :delete ]
+      end
+      it "The parent class actions are not part of allowed_actions" do
+        expect(subresource.allowed_actions).to eq [ :nothing, :delete ]
+      end
+      it "The parent class actions do not change" do
+        expect(resource_class.actions).to eq [ :nothing, :create ]
+        expect(resource.allowed_actions).to eq [ :nothing, :create ]
+      end
+    end
+  end
+
+  context "with a dynamically defined resource and regular provider" do
+    before(:context) do
+      Class.new(Chef::Resource) do
+        resource_name :lw_resource_with_hw_provider_test_case
+        default_action :create
+        attr_accessor :created_provider
+      end
+      class Chef::Provider::LwResourceWithHwProviderTestCase < Chef::Provider
+        def load_current_resource
+        end
+
+        def action_create
+          new_resource.created_provider = self.class
+        end
+      end
+    end
+
+    it "looks up the provider in Chef::Provider converting the resource name from snake case to camel case" do
+      resource = nil
+      recipe = converge {
+        resource = lw_resource_with_hw_provider_test_case "blah" do; end
+      }
+      expect(resource.created_provider).to eq(Chef::Provider::LwResourceWithHwProviderTestCase)
+    end
+  end
+end
diff --git a/spec/integration/recipes/remote_directory.rb b/spec/integration/recipes/remote_directory.rb
new file mode 100644
index 0000000..77fe183
--- /dev/null
+++ b/spec/integration/recipes/remote_directory.rb
@@ -0,0 +1,74 @@
+require "support/shared/integration/integration_helper"
+
+describe Chef::Resource::RemoteDirectory do
+  include IntegrationSupport
+  include Chef::Mixin::ShellOut
+
+  # Until Cheffish::RSpec has cookbook support, we have to run the whole client
+  let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
+
+  # Invoke `chef-client` as `ruby PATH/TO/chef-client`. This ensures the
+  # following constraints are satisfied:
+  # * Windows: windows can only run batch scripts as bare executables. Rubygems
+  # creates batch wrappers for installed gems, but we don't have batch wrappers
+  # in the source tree.
+  # * Other `chef-client` in PATH: A common case is running the tests on a
+  # machine that has omnibus chef installed. In that case we need to ensure
+  # we're running `chef-client` from the source tree and not the external one.
+  # cf. CHEF-4914
+  let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+
+  when_the_repository "has a cookbook with a source_dir with two subdirectories, each with one file and subdir in a different alphabetical order" do
+    before do
+      file "config/client.rb", <<-EOM
+        local_mode true
+        cookbook_path "#{path_to('cookbooks')}"
+      EOM
+      directory "cookbooks/test" do
+        directory "files/default/source_dir" do
+          directory "sub1" do
+            file "aaa", ""
+            file "zzz/file", ""
+          end
+          directory "sub2" do
+            file "aaa/file", ""
+            file "zzz", ""
+          end
+        end
+      end
+    end
+
+    context "and a recipe is run with a remote_directory that syncs source_dir with different mode and file_mode" do
+      let!(:dest_dir) { path_to("dest_dir") }
+      before do
+        directory "cookbooks/test" do
+          file "recipes/default.rb", <<-EOM
+             remote_directory #{dest_dir.inspect} do
+               source "source_dir"
+               mode "0754"
+               files_mode 0777
+             end
+          EOM
+        end
+        shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'test::default'", :cwd => chef_dir)
+      end
+
+      def mode_of(path)
+        path = path_to(path)
+        stat = File.stat(path)
+        (stat.mode & 0777).to_s(8)
+      end
+
+      it "creates all directories and files with the correct permissions" do
+        expect(mode_of("dest_dir/sub1")).to eq "754"
+        expect(mode_of("dest_dir/sub1/aaa")).to eq "777"
+        expect(mode_of("dest_dir/sub1/zzz")).to eq "754"
+        expect(mode_of("dest_dir/sub1/zzz/file")).to eq "777"
+        expect(mode_of("dest_dir/sub2")).to eq "754"
+        expect(mode_of("dest_dir/sub2/aaa")).to eq "754"
+        expect(mode_of("dest_dir/sub2/aaa/file")).to eq "777"
+        expect(mode_of("dest_dir/sub2/zzz")).to eq "777"
+      end
+    end
+  end
+end
diff --git a/spec/integration/recipes/resource_action_spec.rb b/spec/integration/recipes/resource_action_spec.rb
new file mode 100644
index 0000000..8f6f4b7
--- /dev/null
+++ b/spec/integration/recipes/resource_action_spec.rb
@@ -0,0 +1,569 @@
+require "support/shared/integration/integration_helper"
+
+# Houses any classes we declare
+module ResourceActionSpec
+
+  describe "Resource.action" do
+    include IntegrationSupport
+
+    shared_context "ActionJackson" do
+      it "the default action is the first declared action" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+        expect(ActionJackson.succeeded).to eq true
+      end
+
+      it "the action can access recipe DSL" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_recipe_dsl
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+        expect(ActionJackson.succeeded).to eq true
+      end
+
+      it "the action can access attributes" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_attribute
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_attribute
+        expect(ActionJackson.succeeded).to eq "foo!"
+      end
+
+      it "the action can access public methods" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_method
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_method
+        expect(ActionJackson.succeeded).to eq "foo_public!"
+      end
+
+      it "the action can access protected methods" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_protected_method
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_protected_method
+        expect(ActionJackson.succeeded).to eq "foo_protected!"
+      end
+
+      it "the action cannot access private methods" do
+        expect {
+          converge(<<-EOM, __FILE__, __LINE__ + 1)
+          #{resource_dsl} "hi" do
+            foo "foo!"
+            action :access_private_method
+          end
+        EOM
+        }.to raise_error(NameError)
+        expect(ActionJackson.ran_action).to eq :access_private_method
+      end
+
+      it "the action cannot access resource instance variables" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_instance_variable
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_instance_variable
+        expect(ActionJackson.succeeded).to be_nil
+      end
+
+      it "the action does not compile until the prior resource has converged" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        ruby_block "wow" do
+          block do
+            ResourceActionSpec::ActionJackson.ruby_block_converged = "ruby_block_converged!"
+          end
+        end
+
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_class_method
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_class_method
+        expect(ActionJackson.succeeded).to eq "ruby_block_converged!"
+      end
+
+      it "the action's resources converge before the next resource converges" do
+        converge <<-EOM, __FILE__, __LINE__ + 1
+        #{resource_dsl} "hi" do
+          foo "foo!"
+          action :access_attribute
+        end
+
+        ruby_block "wow" do
+          block do
+            ResourceActionSpec::ActionJackson.ruby_block_converged = ResourceActionSpec::ActionJackson.succeeded
+          end
+        end
+      EOM
+        expect(ActionJackson.ran_action).to eq :access_attribute
+        expect(ActionJackson.succeeded).to eq "foo!"
+        expect(ActionJackson.ruby_block_converged).to eq "foo!"
+      end
+    end
+
+    context "With resource 'action_jackson'" do
+      class ActionJackson < Chef::Resource
+        use_automatic_resource_name
+        def foo(value = nil)
+          @foo = value if value
+          @foo
+        end
+
+        def blarghle(value = nil)
+          @blarghle = value if value
+          @blarghle
+        end
+
+        class <<self
+          attr_accessor :ran_action
+          attr_accessor :succeeded
+          attr_accessor :ruby_block_converged
+        end
+
+        public
+
+        def foo_public
+          "foo_public!"
+        end
+
+        protected
+
+        def foo_protected
+          "foo_protected!"
+        end
+
+        private
+
+        def foo_private
+          "foo_private!"
+        end
+
+        public
+
+        action :access_recipe_dsl do
+          ActionJackson.ran_action = :access_recipe_dsl
+          ruby_block "hi there" do
+            block do
+              ActionJackson.succeeded = true
+            end
+          end
+        end
+        action :access_attribute do
+          ActionJackson.ran_action = :access_attribute
+          ActionJackson.succeeded = foo
+          ActionJackson.succeeded += " #{blarghle}" if blarghle
+          ActionJackson.succeeded += " #{bar}" if respond_to?(:bar)
+        end
+        action :access_attribute2 do
+          ActionJackson.ran_action = :access_attribute2
+          ActionJackson.succeeded = foo
+          ActionJackson.succeeded += " #{blarghle}" if blarghle
+          ActionJackson.succeeded += " #{bar}" if respond_to?(:bar)
+        end
+        action :access_method do
+          ActionJackson.ran_action = :access_method
+          ActionJackson.succeeded = foo_public
+        end
+        action :access_protected_method do
+          ActionJackson.ran_action = :access_protected_method
+          ActionJackson.succeeded = foo_protected
+        end
+        action :access_private_method do
+          ActionJackson.ran_action = :access_private_method
+          ActionJackson.succeeded = foo_private
+        end
+        action :access_instance_variable do
+          ActionJackson.ran_action = :access_instance_variable
+          ActionJackson.succeeded = @foo
+        end
+        action :access_class_method do
+          ActionJackson.ran_action = :access_class_method
+          ActionJackson.succeeded = ActionJackson.ruby_block_converged
+        end
+      end
+
+      before(:each) {
+        ActionJackson.ran_action = :error
+        ActionJackson.succeeded = :error
+        ActionJackson.ruby_block_converged = :error
+      }
+
+      it_behaves_like "ActionJackson" do
+        let(:resource_dsl) { :action_jackson }
+      end
+
+      it "Can retrieve ancestors of action class without crashing" do
+        converge { action_jackson "hi" }
+        expect { ActionJackson.action_class.ancestors.join(",") }.not_to raise_error
+      end
+
+      context "And 'action_jackgrandson' inheriting from ActionJackson and changing nothing" do
+        before(:context) {
+          class ActionJackgrandson < ActionJackson
+            use_automatic_resource_name
+          end
+        }
+
+        it_behaves_like "ActionJackson" do
+          let(:resource_dsl) { :action_jackgrandson }
+        end
+      end
+
+      context "And 'action_jackalope' inheriting from ActionJackson with an extra attribute, action and custom method" do
+        class ActionJackalope < ActionJackson
+          use_automatic_resource_name
+
+          def foo(value = nil)
+            @foo = "#{value}alope" if value
+            @foo
+          end
+
+          def bar(value = nil)
+            @bar = "#{value}alope" if value
+            @bar
+          end
+          class <<self
+            attr_accessor :load_current_resource_ran
+            attr_accessor :jackalope_ran
+          end
+          action :access_jackalope do
+            ActionJackalope.jackalope_ran = :access_jackalope
+            ActionJackalope.succeeded = "#{foo} #{blarghle} #{bar}"
+          end
+          action :access_attribute do
+            super()
+            ActionJackalope.jackalope_ran = :access_attribute
+            ActionJackalope.succeeded = ActionJackson.succeeded
+          end
+        end
+        before do
+          ActionJackalope.jackalope_ran = nil
+          ActionJackalope.load_current_resource_ran = nil
+        end
+
+        context "action_jackson still behaves the same" do
+          it_behaves_like "ActionJackson" do
+            let(:resource_dsl) { :action_jackson }
+          end
+        end
+
+        it "the default action remains the same even though new actions were specified first" do
+          converge {
+            action_jackalope "hi" do
+              foo "foo!"
+              bar "bar!"
+            end
+          }
+          expect(ActionJackson.ran_action).to eq :access_recipe_dsl
+          expect(ActionJackson.succeeded).to eq true
+        end
+
+        it "new actions run, and can access overridden, new, and overridden attributes" do
+          converge {
+            action_jackalope "hi" do
+              foo "foo!"
+              bar "bar!"
+              blarghle "blarghle!"
+              action :access_jackalope
+            end
+          }
+          expect(ActionJackalope.jackalope_ran).to eq :access_jackalope
+          expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
+        end
+
+        it "overridden actions run, call super, and can access overridden, new, and overridden attributes" do
+          converge {
+            action_jackalope "hi" do
+              foo "foo!"
+              bar "bar!"
+              blarghle "blarghle!"
+              action :access_attribute
+            end
+          }
+          expect(ActionJackson.ran_action).to eq :access_attribute
+          expect(ActionJackson.succeeded).to eq "foo!alope blarghle! bar!alope"
+          expect(ActionJackalope.jackalope_ran).to eq :access_attribute
+          expect(ActionJackalope.succeeded).to eq "foo!alope blarghle! bar!alope"
+        end
+
+        it "non-overridden actions run and can access overridden and non-overridden variables (but not necessarily new ones)" do
+          converge {
+            action_jackalope "hi" do
+              foo "foo!"
+              bar "bar!"
+              blarghle "blarghle!"
+              action :access_attribute2
+            end
+          }
+          expect(ActionJackson.ran_action).to eq :access_attribute2
+          expect(ActionJackson.succeeded).to eq("foo!alope blarghle! bar!alope").or(eq("foo!alope blarghle!"))
+        end
+      end
+    end
+
+    context "With a resource with no actions" do
+      class NoActionJackson < Chef::Resource
+        use_automatic_resource_name
+
+        def foo(value = nil)
+          @foo = value if value
+          @foo
+        end
+
+        class <<self
+          attr_accessor :action_was
+        end
+      end
+
+      it "the default action is :nothing" do
+        converge {
+          no_action_jackson "hi" do
+            foo "foo!"
+            NoActionJackson.action_was = action
+          end
+        }
+        expect(NoActionJackson.action_was).to eq [:nothing]
+      end
+    end
+
+    context "With a resource with action a-b-c d" do
+      class WeirdActionJackson < Chef::Resource
+        use_automatic_resource_name
+
+        class <<self
+          attr_accessor :action_was
+        end
+
+        action "a-b-c d" do
+          WeirdActionJackson.action_was = action
+        end
+      end
+
+      it "Running the action works" do
+        expect_recipe {
+          weird_action_jackson "hi"
+        }.to be_up_to_date
+        expect(WeirdActionJackson.action_was).to eq :"a-b-c d"
+      end
+    end
+
+    context "With a resource with property x" do
+      class ResourceActionSpecWithX < Chef::Resource
+        resource_name :resource_action_spec_with_x
+        property :x, default: 20
+        action :set do
+          # Access x during converge to ensure that we emit no warnings there
+          x
+        end
+      end
+
+      context "And another resource with a property x and an action that sets property x to its value" do
+        class ResourceActionSpecAlsoWithX < Chef::Resource
+          resource_name :resource_action_spec_also_with_x
+          property :x
+          action :set_x_to_x do
+            resource_action_spec_with_x "hi" do
+              x x
+            end
+          end
+          def self.x_warning_line
+            __LINE__ - 4
+          end
+          action :set_x_to_x_in_non_initializer do
+            r = resource_action_spec_with_x "hi" do
+              x 10
+            end
+            x_times_2 = r.x * 2
+          end
+          action :set_x_to_10 do
+            resource_action_spec_with_x "hi" do
+              x 10
+            end
+          end
+        end
+
+        attr_reader :x_warning_line
+
+        it "Using the enclosing resource to set x to x emits a warning that you're using the wrong x" do
+          recipe = converge {
+            resource_action_spec_also_with_x "hi" do
+              x 1
+              action :set_x_to_x
+            end
+          }
+          warnings = recipe.logs.lines.select { |l| l =~ /warn/i }
+          expect(warnings.size).to eq 1
+          expect(warnings[0]).to match(/property x is declared in both resource_action_spec_with_x\[hi\] and resource_action_spec_also_with_x\[hi\] action :set_x_to_x. Use new_resource.x instead. At #{__FILE__}:#{ResourceActionSpecAlsoWithX.x_warning_line}/)
+        end
+
+        it "Using the enclosing resource to set x to x outside the initializer emits no warning" do
+          expect_recipe {
+            resource_action_spec_also_with_x "hi" do
+              x 1
+              action :set_x_to_x_in_non_initializer
+            end
+          }.to emit_no_warnings_or_errors
+        end
+
+        it "Using the enclosing resource to set x to 10 emits no warning" do
+          expect_recipe {
+            resource_action_spec_also_with_x "hi" do
+              x 1
+              action :set_x_to_10
+            end
+          }.to emit_no_warnings_or_errors
+        end
+
+        it "Using the enclosing resource to set x to 10 emits no warning" do
+          expect_recipe {
+            r = resource_action_spec_also_with_x "hi"
+            r.x 1
+            r.action :set_x_to_10
+          }.to emit_no_warnings_or_errors
+        end
+      end
+
+    end
+
+    context "With a resource with a set_or_return property named group (same name as a resource)" do
+      class ResourceActionSpecWithGroupAction < Chef::Resource
+        resource_name :resource_action_spec_set_group_to_nil
+        action :set_group_to_nil do
+          # Access x during converge to ensure that we emit no warnings there
+          resource_action_spec_with_group "hi" do
+            group nil
+            action :nothing
+          end
+        end
+      end
+
+      class ResourceActionSpecWithGroup < Chef::Resource
+        resource_name :resource_action_spec_with_group
+        def group(value = nil)
+          set_or_return(:group, value, {})
+        end
+      end
+
+      it "Setting group to nil in an action does not emit a warning about it being defined in two places" do
+        expect_recipe {
+          resource_action_spec_set_group_to_nil "hi" do
+            action :set_group_to_nil
+          end
+        }.to emit_no_warnings_or_errors
+      end
+    end
+
+    context "When a resource has a property with the same name as another resource" do
+      class HasPropertyNamedTemplate < Chef::Resource
+        use_automatic_resource_name
+        property :template
+        action :create do
+          template "x" do
+            "blah"
+          end
+        end
+      end
+
+      it "Raises an error when attempting to use a template in the action" do
+        expect_converge {
+          has_property_named_template "hi"
+        }.to raise_error(/Property template of has_property_named_template\[hi\] cannot be passed a block! If you meant to create a resource named template instead, you'll need to first rename the property./)
+      end
+    end
+
+    context "When a resource declares methods in action_class and declare_action_class" do
+      class DeclaresActionClassMethods < Chef::Resource
+        use_automatic_resource_name
+        property :x
+        action :create do
+          new_resource.x = a + b + c + d
+        end
+        action_class do
+          def a
+            1
+          end
+        end
+        declare_action_class do
+          def b
+            2
+          end
+        end
+        action_class do
+          def c
+            3
+          end
+        end
+        declare_action_class do
+          def d
+            4
+          end
+        end
+      end
+
+      it "the methods are not available on the resource" do
+        expect { DeclaresActionClassMethods.new("hi").a }.to raise_error(NameError)
+        expect { DeclaresActionClassMethods.new("hi").b }.to raise_error(NameError)
+        expect { DeclaresActionClassMethods.new("hi").c }.to raise_error(NameError)
+        expect { DeclaresActionClassMethods.new("hi").d }.to raise_error(NameError)
+      end
+
+      it "the methods are available to the action" do
+        r = nil
+        expect_recipe {
+          r = declares_action_class_methods "hi"
+        }.to emit_no_warnings_or_errors
+        expect(r.x).to eq(10)
+      end
+
+      context "And a subclass also creates a method" do
+        class DeclaresActionClassMethodsToo < DeclaresActionClassMethods
+          use_automatic_resource_name
+          action :create do
+            new_resource.x a + b + c + d + e
+          end
+          action_class do
+            def e
+              5
+            end
+          end
+        end
+
+        it "the methods are not available on the resource" do
+          expect { DeclaresActionClassMethods.new("hi").a }.to raise_error(NameError)
+          expect { DeclaresActionClassMethods.new("hi").b }.to raise_error(NameError)
+          expect { DeclaresActionClassMethods.new("hi").c }.to raise_error(NameError)
+          expect { DeclaresActionClassMethods.new("hi").d }.to raise_error(NameError)
+          expect { DeclaresActionClassMethods.new("hi").e }.to raise_error(NameError)
+        end
+
+        it "the methods are available to the action" do
+          r = nil
+          expect_recipe {
+            r = declares_action_class_methods_too "hi"
+          }.to emit_no_warnings_or_errors
+          expect(r.x).to eq(15)
+        end
+      end
+    end
+  end
+
+end
diff --git a/spec/integration/recipes/resource_converge_if_changed_spec.rb b/spec/integration/recipes/resource_converge_if_changed_spec.rb
new file mode 100644
index 0000000..f1ea79d
--- /dev/null
+++ b/spec/integration/recipes/resource_converge_if_changed_spec.rb
@@ -0,0 +1,496 @@
+require "support/shared/integration/integration_helper"
+
+describe "Resource::ActionClass#converge_if_changed" do
+  include IntegrationSupport
+
+  module Namer
+    extend self
+    attr_accessor :current_index
+    def incrementing_value
+      @incrementing_value += 1
+      @incrementing_value
+    end
+    attr_writer :incrementing_value
+  end
+
+  before(:all) { Namer.current_index = 1 }
+  before { Namer.current_index += 1 }
+  before { Namer.incrementing_value = 0 }
+
+  context "when the resource has identity, state and control properties" do
+    let(:resource_name) { :"converge_if_changed_dsl#{Namer.current_index}" }
+    let(:resource_class) {
+      result = Class.new(Chef::Resource) do
+        def self.to_s; resource_name; end
+
+        def self.inspect; resource_name.inspect; end
+        property :identity1, identity: true, default: "default_identity1"
+        property :control1, desired_state: false, default: "default_control1"
+        property :state1, default: "default_state1"
+        property :state2, default: "default_state2"
+        attr_accessor :converged
+        def initialize(*args)
+          super
+          @converged = 0
+        end
+      end
+      result.resource_name resource_name
+      result
+    }
+    let(:converged_recipe) { converge(converge_recipe) }
+    let(:resource) { converged_recipe.resources.first }
+
+    context "and converge_if_changed with no parameters" do
+      before :each do
+        resource_class.action :create do
+          converge_if_changed do
+            new_resource.converged += 1
+          end
+        end
+      end
+
+      context "and current_resource with state1=current, state2=current" do
+        before :each do
+          resource_class.load_current_value do
+            state1 "current_state1"
+            state2 "current_state2"
+          end
+        end
+
+        context "and nothing is set" do
+          let(:converge_recipe) { "#{resource_name} 'blah'" }
+
+          it "the resource updates nothing" do
+            expect(resource.converged).to eq 0
+            expect(resource.updated?).to  be_falsey
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create (up to date)
+            EOM
+          end
+        end
+
+        context "and state1 is set to a new value" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+              end
+            EOM
+          }
+
+          it "the resource updates state1" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state1 to "new_state1" (was "current_state1")
+              EOM
+          end
+        end
+
+        context "and state1 and state2 are set to new values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates state1 and state2" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state1 to "new_state1" (was "current_state1")
+  -   set state2 to "new_state2" (was "current_state2")
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to new sensitive values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                sensitive true
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates state1 and state2" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state1 to (suppressed sensitive property)
+  -   set state2 to (suppressed sensitive property)
+EOM
+          end
+        end
+
+        context "and state1 is set to its current value but state2 is set to a new value" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'current_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates state2" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state2 to "new_state2" (was "current_state2")
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to their current values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'current_state1'
+                state2 'current_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates nothing" do
+            expect(resource.converged).to eq 0
+            expect(resource.updated?).to  be_falsey
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create (up to date)
+EOM
+          end
+        end
+
+        context "and identity1 and control1 are set to new values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                identity1 'new_identity1'
+                control1 'new_control1'
+              end
+            EOM
+          }
+
+          # Because the identity value is copied over to the new resource, by
+          # default they do not register as "changed"
+          it "the resource updates nothing" do
+            expect(resource.converged).to eq 0
+            expect(resource.updated?).to  be_falsey
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create (up to date)
+EOM
+          end
+        end
+      end
+
+      context "and current_resource with identity1=current, control1=current" do
+        before :each do
+          resource_class.load_current_value do
+            identity1 "current_identity1"
+            control1 "current_control1"
+          end
+        end
+
+        context "and identity1 and control1 are set to new values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                identity1 'new_identity1'
+                control1 'new_control1'
+              end
+            EOM
+          }
+
+          # Control values are not desired state and are therefore not considered
+          # a reason for converging.
+          it "the resource updates identity1" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update current_identity1
+  -   set identity1 to "new_identity1" (was "current_identity1")
+            EOM
+          end
+        end
+      end
+
+      context "and has no current_resource" do
+        before :each do
+          resource_class.load_current_value do
+            current_value_does_not_exist!
+          end
+        end
+
+        context "and nothing is set" do
+          let(:converge_recipe) { "#{resource_name} 'blah'" }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set identity1 to "default_identity1" (default value)
+  -   set state1    to "default_state1" (default value)
+  -   set state2    to "default_state2" (default value)
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set identity1 to "default_identity1" (default value)
+  -   set state1    to "new_state1"
+  -   set state2    to "new_state2"
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set with sensitive property" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                sensitive true
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set identity1 to (suppressed sensitive property) (default value)
+  -   set state1    to (suppressed sensitive property)
+  -   set state2    to (suppressed sensitive property)
+EOM
+          end
+        end
+      end
+    end
+
+    context "and separate converge_if_changed :state1 and converge_if_changed :state2" do
+      before :each do
+        resource_class.action :create do
+          converge_if_changed :state1 do
+            new_resource.converged += 1
+          end
+          converge_if_changed :state2 do
+            new_resource.converged += 1
+          end
+        end
+      end
+
+      context "and current_resource with state1=current, state2=current" do
+        before :each do
+          resource_class.load_current_value do
+            state1 "current_state1"
+            state2 "current_state2"
+          end
+        end
+
+        context "and nothing is set" do
+          let(:converge_recipe) { "#{resource_name} 'blah'" }
+
+          it "the resource updates nothing" do
+            expect(resource.converged).to eq 0
+            expect(resource.updated?).to  be_falsey
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create (up to date)
+EOM
+          end
+        end
+
+        context "and state1 is set to a new value" do
+
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+              end
+            EOM
+          }
+
+          it "the resource updates state1" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state1 to "new_state1" (was "current_state1")
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to new values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates state1 and state2" do
+            expect(resource.converged).to eq 2
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state1 to "new_state1" (was "current_state1")
+  - update default_identity1
+  -   set state2 to "new_state2" (was "current_state2")
+EOM
+          end
+        end
+
+        context "and state1 is set to its current value but state2 is set to a new value" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'current_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates state2" do
+            expect(resource.converged).to eq 1
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - update default_identity1
+  -   set state2 to "new_state2" (was "current_state2")
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to their current values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'current_state1'
+                state2 'current_state2'
+              end
+            EOM
+          }
+
+          it "the resource updates nothing" do
+            expect(resource.converged).to eq 0
+            expect(resource.updated?).to  be_falsey
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create (up to date)
+EOM
+          end
+        end
+      end
+
+      context "and no current_resource" do
+        before :each do
+          resource_class.load_current_value do
+            current_value_does_not_exist!
+          end
+        end
+
+        context "and nothing is set" do
+          let(:converge_recipe) {
+            "#{resource_name} 'blah'"
+          }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 2
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set state1 to "default_state1" (default value)
+  - create default_identity1
+  -   set state2 to "default_state2" (default value)
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to new values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 2
+            expect(resource.updated?).to  be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set state1 to "new_state1"
+  - create default_identity1
+  -   set state2 to "new_state2"
+EOM
+          end
+        end
+
+        context "and state1 and state2 are set to new sensitive values" do
+          let(:converge_recipe) {
+            <<-EOM
+              #{resource_name} 'blah' do
+                sensitive true
+                state1 'new_state1'
+                state2 'new_state2'
+              end
+            EOM
+          }
+
+          it "the resource is created" do
+            expect(resource.converged).to eq 2
+            expect(resource.updated?).to be_truthy
+            expect(converged_recipe.stdout).to eq <<-EOM
+* #{resource_name}[blah] action create
+  - create default_identity1
+  -   set state1 to (suppressed sensitive property)
+  - create default_identity1
+  -   set state2 to (suppressed sensitive property)
+EOM
+          end
+        end
+
+      end
+    end
+
+  end
+end
diff --git a/spec/integration/recipes/resource_load_spec.rb b/spec/integration/recipes/resource_load_spec.rb
new file mode 100644
index 0000000..b48eb2d
--- /dev/null
+++ b/spec/integration/recipes/resource_load_spec.rb
@@ -0,0 +1,208 @@
+require "support/shared/integration/integration_helper"
+
+describe "Resource.load_current_value" do
+  include IntegrationSupport
+
+  module Namer
+    extend self
+    attr_accessor :current_index
+    def incrementing_value
+      @incrementing_value += 1
+      @incrementing_value
+    end
+    attr_writer :incrementing_value
+  end
+
+  before(:all) { Namer.current_index = 1 }
+  before { Namer.current_index += 1 }
+  before { Namer.incrementing_value = 0 }
+
+  let(:resource_name) { :"load_current_value_dsl#{Namer.current_index}" }
+  let(:resource_class) {
+    result = Class.new(Chef::Resource) do
+      def self.to_s; resource_name; end
+
+      def self.inspect; resource_name.inspect; end
+      property :x, default: lazy { "default #{Namer.incrementing_value}" }
+      def self.created_x=(value)
+        @created = value
+      end
+
+      def self.created_x
+        @created
+      end
+      action :create do
+        new_resource.class.created_x = x
+      end
+    end
+    result.resource_name resource_name
+    result
+  }
+
+  # Pull on resource_class to initialize it
+  before { resource_class }
+
+  context "with a resource with load_current_value" do
+    before :each do
+      resource_class.load_current_value do
+        x "loaded #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+          select { |name, p| p.is_set?(self) }.
+          map { |name, p| "#{name}=#{p.get(self)}" }.
+          join(", ") })"
+      end
+    end
+
+    context "and a resource with x set to a desired value" do
+      let(:resource) do
+        e = self
+        r = nil
+        converge {
+          r = public_send(e.resource_name, "blah") do
+            x "desired"
+          end
+        }
+        r
+      end
+
+      it "current_resource is passed name but not x" do
+        expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
+      end
+
+      it "resource.current_value returns a different resource" do
+        expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
+        expect(resource.x).to eq "desired"
+      end
+
+      it "resource.current_value constructs the resource anew each time" do
+        expect(resource.current_value.x).to eq "loaded 2 (name=blah)"
+        expect(resource.current_value.x).to eq "loaded 3 (name=blah)"
+      end
+
+      it "the provider accesses the current value of x" do
+        expect(resource.class.created_x).to eq "desired"
+      end
+
+      context "and identity: :i and :d with desired_state: false" do
+        before {
+          resource_class.class_eval do
+            property :i, identity: true
+            property :d, desired_state: false
+          end
+        }
+
+        before {
+          resource.i "desired_i"
+          resource.d "desired_d"
+        }
+
+        it "i, name and d are passed to load_current_value, but not x" do
+          expect(resource.current_value.x).to eq "loaded 2 (d=desired_d, i=desired_i, name=blah)"
+        end
+      end
+
+      context "and name_property: :i and :d with desired_state: false" do
+        before {
+          resource_class.class_eval do
+            property :i, name_property: true
+            property :d, desired_state: false
+          end
+        }
+
+        before {
+          resource.i "desired_i"
+          resource.d "desired_d"
+        }
+
+        it "i, name and d are passed to load_current_value, but not x" do
+          expect(resource.current_value.x).to eq "loaded 2 (d=desired_d, i=desired_i, name=blah)"
+        end
+      end
+    end
+
+    context "and a resource with no values set" do
+      let(:resource) do
+        e = self
+        r = nil
+        converge {
+          r = public_send(e.resource_name, "blah") do
+          end
+        }
+        r
+      end
+
+      it "the provider accesses values from load_current_value" do
+        expect(resource.class.created_x).to eq "loaded 1 (name=blah)"
+      end
+    end
+
+    let (:subresource_name) {
+      :"load_current_value_subresource_dsl#{Namer.current_index}"
+    }
+    let (:subresource_class) {
+      r = Class.new(resource_class) do
+        property :y, default: lazy { "default_y #{Namer.incrementing_value}" }
+      end
+      r.resource_name subresource_name
+      r
+    }
+
+    # Pull on subresource_class to initialize it
+    before { subresource_class }
+
+    let(:subresource) do
+      e = self
+      r = nil
+      converge {
+        r = public_send(e.subresource_name, "blah") do
+          x "desired"
+        end
+      }
+      r
+    end
+
+    context "and a child resource class with no load_current_value" do
+      it "the parent load_current_value is used" do
+        expect(subresource.current_value.x).to eq "loaded 2 (name=blah)"
+      end
+      it "load_current_value yields a copy of the child class" do
+        expect(subresource.current_value).to be_kind_of(subresource_class)
+      end
+    end
+
+    context "And a child resource class with load_current_value" do
+      before {
+        subresource_class.load_current_value do
+          y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+            select { |name, p| p.is_set?(self) }.
+            map { |name, p| "#{name}=#{p.get(self)}" }.
+            join(", ") })"
+        end
+      }
+
+      it "the overridden load_current_value is used" do
+        current_resource = subresource.current_value
+        expect(current_resource.x).to eq "default 3"
+        expect(current_resource.y).to eq "loaded_y 2 (name=blah)"
+      end
+    end
+
+    context "and a child resource class with load_current_value calling super()" do
+      before {
+        subresource_class.load_current_value do
+          super()
+          y "loaded_y #{Namer.incrementing_value} (#{self.class.properties.sort_by { |name, p| name }.
+            select { |name, p| p.is_set?(self) }.
+            map { |name, p| "#{name}=#{p.get(self)}" }.
+            join(", ") })"
+        end
+      }
+
+      it "the original load_current_value is called as well as the child one" do
+        current_resource = subresource.current_value
+        expect(current_resource.x).to eq "loaded 3 (name=blah)"
+        expect(current_resource.y).to eq "loaded_y 4 (name=blah, x=loaded 3 (name=blah))"
+      end
+    end
+  end
+
+end
diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb
index f45933c..567f1a2 100644
--- a/spec/integration/solo/solo_spec.rb
+++ b/spec/integration/solo/solo_spec.rb
@@ -1,9 +1,9 @@
-require 'support/shared/integration/integration_helper'
-require 'chef/mixin/shell_out'
-require 'chef/run_lock'
-require 'chef/config'
-require 'timeout'
-require 'fileutils'
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+require "chef/run_lock"
+require "chef/config"
+require "timeout"
+require "fileutils"
 
 describe "chef-solo" do
   include IntegrationSupport
@@ -19,12 +19,12 @@ describe "chef-solo" do
 
   when_the_repository "has a cookbook with a basic recipe" do
     before do
-      file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
-      file 'cookbooks/x/recipes/default.rb', 'puts "ITWORKS"'
+      file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+      file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
     end
 
     it "should complete with success" do
-      file 'config/solo.rb', <<EOM
+      file "config/solo.rb", <<EOM
 cookbook_path "#{path_to('cookbooks')}"
 file_cache_path "#{path_to('config/cache')}"
 EOM
@@ -34,12 +34,12 @@ EOM
     end
 
     it "should evaluate its node.json file" do
-      file 'config/solo.rb', <<EOM
+      file "config/solo.rb", <<EOM
 cookbook_path "#{path_to('cookbooks')}"
 file_cache_path "#{path_to('config/cache')}"
 EOM
 
-      file 'config/node.json',<<-E
+      file "config/node.json", <<-E
 {"run_list":["x::default"]}
 E
 
@@ -52,15 +52,15 @@ E
 
   when_the_repository "has a cookbook with an undeclared dependency" do
     before do
-      file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
-      file 'cookbooks/x/recipes/default.rb', 'include_recipe "ancient::aliens"'
+      file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+      file "cookbooks/x/recipes/default.rb", 'include_recipe "ancient::aliens"'
 
-      file 'cookbooks/ancient/metadata.rb', cookbook_ancient_100_metadata_rb
-      file 'cookbooks/ancient/recipes/aliens.rb', 'print "it was aliens"'
+      file "cookbooks/ancient/metadata.rb", cookbook_ancient_100_metadata_rb
+      file "cookbooks/ancient/recipes/aliens.rb", 'print "it was aliens"'
     end
 
     it "should exit with an error" do
-      file 'config/solo.rb', <<EOM
+      file "config/solo.rb", <<EOM
 cookbook_path "#{path_to('cookbooks')}"
 file_cache_path "#{path_to('config/cache')}"
 EOM
@@ -70,13 +70,46 @@ EOM
     end
   end
 
+  when_the_repository "has a cookbook with an incompatible chef_version" do
+    before do
+      file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nchef_version '~> 999.0'")
+      file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
+      file "config/solo.rb", <<EOM
+cookbook_path "#{path_to('cookbooks')}"
+file_cache_path "#{path_to('config/cache')}"
+EOM
+    end
+
+    it "should exit with an error" do
+      result = shell_out("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir)
+      expect(result.exitstatus).to eq(1)
+      expect(result.stdout).to include("Chef::Exceptions::CookbookChefVersionMismatch")
+    end
+  end
+
+  when_the_repository "has a cookbook with an incompatible ohai_version" do
+    before do
+      file "cookbooks/x/metadata.rb", cb_metadata("x", "1.0.0", "\nohai_version '~> 999.0'")
+      file "cookbooks/x/recipes/default.rb", 'puts "ITWORKS"'
+      file "config/solo.rb", <<EOM
+cookbook_path "#{path_to('cookbooks')}"
+file_cache_path "#{path_to('config/cache')}"
+EOM
+    end
+
+    it "should exit with an error" do
+      result = shell_out("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir)
+      expect(result.exitstatus).to eq(1)
+      expect(result.stdout).to include("Chef::Exceptions::CookbookOhaiVersionMismatch")
+    end
+  end
 
   when_the_repository "has a cookbook with a recipe with sleep" do
     before do
-      directory 'logs'
-      file 'logs/runs.log', ''
-      file 'cookbooks/x/metadata.rb', cookbook_x_100_metadata_rb
-      file 'cookbooks/x/recipes/default.rb', <<EOM
+      directory "logs"
+      file "logs/runs.log", ""
+      file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+      file "cookbooks/x/recipes/default.rb", <<EOM
 ruby_block "sleeping" do
   block do
     sleep 5
@@ -86,7 +119,7 @@ EOM
     end
 
     it "while running solo concurrently" do
-      file 'config/solo.rb', <<EOM
+      file "config/solo.rb", <<EOM
 cookbook_path "#{path_to('cookbooks')}"
 file_cache_path "#{path_to('config/cache')}"
 EOM
@@ -115,15 +148,15 @@ EOM
       # Unfortunately file / directory helpers in integration tests
       # are implemented using before(:each) so we need to do all below
       # checks in one example.
-      run_log = File.read(path_to('logs/runs.log'))
+      run_log = File.read(path_to("logs/runs.log"))
 
       # both of the runs should succeed
-      expect(run_log.lines.reject {|l| !l.include? "INFO: Chef Run complete in"}.length).to eq(2)
+      expect(run_log.lines.reject { |l| !l.include? "INFO: Chef Run complete in" }.length).to eq(2)
 
       # second run should have a message which indicates it's waiting for the first run
-      pid_lines = run_log.lines.reject {|l| !l.include? "Chef-client pid:"}
+      pid_lines = run_log.lines.reject { |l| !l.include? "Chef-client pid:" }
       expect(pid_lines.length).to eq(2)
-      pids = pid_lines.map {|l| l.split(" ").last}
+      pids = pid_lines.map { |l| l.split(" ").last }
       expect(run_log).to include("Chef client #{pids[0]} is running, will wait for it to finish and then run.")
 
       # second run should start after first run ends
diff --git a/spec/scripts/ssl-serve.rb b/spec/scripts/ssl-serve.rb
index 24ed70a..c05aa2c 100644
--- a/spec/scripts/ssl-serve.rb
+++ b/spec/scripts/ssl-serve.rb
@@ -5,11 +5,10 @@
 # You can use it to test various HTTP behaviors in chef, like chef-client's
 # `-j` and `-c` options and remote_file with https connections.
 #
-require 'pp'
-require 'openssl'
-require 'webrick'
-require 'webrick/https'
-
+require "pp"
+require "openssl"
+require "webrick"
+require "webrick/https"
 
 $ssl = true
 
@@ -21,23 +20,21 @@ key = OpenSSL::PKey::RSA.new(key_text)
 
 server_opts = {}
 if $ssl
-server_opts.merge!( { :SSLEnable => true,
-                :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
-                :SSLCertificate => cert,
-                :SSLPrivateKey => key })
+  server_opts.merge!( { :SSLEnable => true,
+                        :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
+                        :SSLCertificate => cert,
+                        :SSLPrivateKey => key })
 end
 
-
-
 # 5 == debug, 3 == warning
 LOGGER = WEBrick::Log.new(STDOUT, 5)
 DEFAULT_OPTIONS = {
-  :server => 'webrick',
+  :server => "webrick",
   :Port => 9000,
-  :Host => 'localhost',
+  :Host => "localhost",
   :environment => :none,
   :Logger => LOGGER,
-  :DocumentRoot => File.expand_path("/tmp/chef-118-sampledata")
+  :DocumentRoot => File.expand_path("#{Dir.tmpdir}/chef-118-sampledata")
   #:AccessLog => [] # Remove this option to enable the access log when debugging.
 }
 
@@ -45,8 +42,6 @@ webrick_opts = DEFAULT_OPTIONS.merge(server_opts)
 pp :webrick_opts => webrick_opts
 
 server = WEBrick::HTTPServer.new(webrick_opts)
-trap 'INT' do server.shutdown end
+trap "INT" do server.shutdown end
 
 server.start
-
-
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index fb284c7..47432f5 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,16 +27,15 @@ end
 # Ruby 1.9 Compat
 $:.unshift File.expand_path("../..", __FILE__)
 
-
-require 'rubygems'
-require 'rspec/mocks'
+require "rubygems"
+require "rspec/mocks"
 
 $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
 $:.unshift(File.expand_path("../lib", __FILE__))
 $:.unshift(File.dirname(__FILE__))
 
 if ENV["COVERAGE"]
-  require 'simplecov'
+  require "simplecov"
   SimpleCov.start do
     add_filter "/spec/"
     add_group "Remote File", "remote_file"
@@ -46,30 +45,38 @@ if ENV["COVERAGE"]
   end
 end
 
-require 'chef'
-require 'chef/knife'
+require "chef"
+require "chef/knife"
+
+Dir["lib/chef/knife/**/*.rb"].
+  map { |f| f.gsub("lib/", "") }.
+  map { |f| f.gsub(%r{\.rb$}, "") }.
+  each { |f| require f }
+
+require "chef/resource_resolver"
+require "chef/provider_resolver"
 
-Dir['lib/chef/knife/**/*.rb'].
-  map {|f| f.gsub('lib/', '') }.
-  map {|f| f.gsub(%r[\.rb$], '') }.
-  each {|f| require f }
+require "chef/mixins"
+require "chef/dsl"
+require "chef/application"
+require "chef/applications"
 
-require 'chef/mixins'
-require 'chef/dsl'
-require 'chef/application'
-require 'chef/applications'
+require "chef/shell"
+require "chef/util/file_edit"
 
-require 'chef/shell'
-require 'chef/util/file_edit'
+require "chef/config"
 
-require 'chef/config'
+if ENV["CHEF_FIPS"] == "1"
+  Chef::Config.init_openssl
+end
 
 # If you want to load anything into the testing environment
 # without versioning it, add it to spec/support/local_gems.rb
-require 'spec/support/local_gems.rb' if File.exists?(File.join(File.dirname(__FILE__), 'support', 'local_gems.rb'))
+require "spec/support/local_gems.rb" if File.exists?(File.join(File.dirname(__FILE__), "support", "local_gems.rb"))
 
 # Explicitly require spec helpers that need to load first
-require 'spec/support/platform_helpers'
+require "spec/support/platform_helpers"
+require "spec/support/shared/unit/mock_shellout"
 
 # Autoloads support files
 # Excludes support/platforms by default
@@ -77,22 +84,27 @@ require 'spec/support/platform_helpers'
 Dir["spec/support/**/*.rb"].
   reject { |f| f =~ %r{^spec/support/platforms} }.
   reject { |f| f =~ %r{^spec/support/pedant} }.
-  map { |f| f.gsub(%r{.rb$}, '') }.
-  map { |f| f.gsub(%r[spec/], '')}.
+  map { |f| f.gsub(%r{.rb$}, "") }.
+  map { |f| f.gsub(%r{spec/}, "") }.
   each { |f| require f }
 
 OHAI_SYSTEM = Ohai::System.new
-OHAI_SYSTEM.all_plugins("platform")
-
-TEST_PLATFORM =
-  (OHAI_SYSTEM['platform'] ||
-  'unknown_test_platform').dup.freeze
-TEST_PLATFORM_VERSION =
-  (OHAI_SYSTEM['platform_version'] ||
-  'unknown_platform_version').dup.freeze
+OHAI_SYSTEM.all_plugins(["platform", "hostname", "languages/powershell"])
+
+test_node = Chef::Node.new
+test_node.automatic["os"] = (OHAI_SYSTEM["os"] || "unknown_os").dup.freeze
+test_node.automatic["platform_family"] = (OHAI_SYSTEM["platform_family"] || "unknown_platform_family").dup.freeze
+test_node.automatic["platform"] = (OHAI_SYSTEM["platform"] || "unknown_platform").dup.freeze
+test_node.automatic["platform_version"] = (OHAI_SYSTEM["platform_version"] || "unknown_platform_version").dup.freeze
+TEST_NODE = test_node.freeze
+TEST_OS = TEST_NODE["os"]
+TEST_PLATFORM = TEST_NODE["platform"]
+TEST_PLATFORM_VERSION = TEST_NODE["platform_version"]
+TEST_PLATFORM_FAMILY = TEST_NODE["platform_family"]
 
 RSpec.configure do |config|
   config.include(Matchers)
+  config.include(MockShellout::RSpec)
   config.filter_run :focus => true
   config.filter_run_excluding :external => true
 
@@ -112,24 +124,34 @@ RSpec.configure do |config|
   config.filter_run_excluding :volatile_on_solaris => true if solaris?
   config.filter_run_excluding :volatile_from_verify => false
 
-  # Add jruby filters here
+  config.filter_run_excluding :skip_appveyor => true if ENV["APPVEYOR"]
+  config.filter_run_excluding :appveyor_only => true unless ENV["APPVEYOR"]
+  config.filter_run_excluding :skip_travis => true if ENV["TRAVIS"]
+
   config.filter_run_excluding :windows_only => true unless windows?
   config.filter_run_excluding :not_supported_on_mac_osx_106 => true if mac_osx_106?
-  config.filter_run_excluding :not_supported_on_mac_osx=> true if mac_osx?
-  config.filter_run_excluding :mac_osx_only=> true if !mac_osx?
+  config.filter_run_excluding :not_supported_on_mac_osx => true if mac_osx?
+  config.filter_run_excluding :mac_osx_only => true if !mac_osx?
   config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3?
   config.filter_run_excluding :not_supported_on_solaris => true if solaris?
+  config.filter_run_excluding :not_supported_on_gce => true if gce?
+  config.filter_run_excluding :not_supported_on_nano => true if windows_nano_server?
   config.filter_run_excluding :win2k3_only => true unless windows_win2k3?
   config.filter_run_excluding :windows_2008r2_or_later => true unless windows_2008r2_or_later?
   config.filter_run_excluding :windows64_only => true unless windows64?
   config.filter_run_excluding :windows32_only => true unless windows32?
+  config.filter_run_excluding :windows_nano_only => true unless windows_nano_server?
+  config.filter_run_excluding :ruby64_only => true unless ruby_64bit?
+  config.filter_run_excluding :ruby32_only => true unless ruby_32bit?
   config.filter_run_excluding :windows_powershell_dsc_only => true unless windows_powershell_dsc?
   config.filter_run_excluding :windows_powershell_no_dsc_only => true unless ! windows_powershell_dsc?
   config.filter_run_excluding :windows_domain_joined_only => true unless windows_domain_joined?
+  config.filter_run_excluding :windows_not_domain_joined_only => true if windows_domain_joined?
   config.filter_run_excluding :solaris_only => true unless solaris?
   config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem?
   config.filter_run_excluding :unix_only => true unless unix?
   config.filter_run_excluding :aix_only => true unless aix?
+  config.filter_run_excluding :debian_family_only => true unless debian_family?
   config.filter_run_excluding :supports_cloexec => true unless supports_cloexec?
   config.filter_run_excluding :selinux_only => true unless selinux_enabled?
   config.filter_run_excluding :ruby_20_only => true unless ruby_20?
@@ -145,8 +167,10 @@ RSpec.configure do |config|
   config.filter_run_excluding :openssl_lt_101 => true unless openssl_lt_101?
   config.filter_run_excluding :aes_256_gcm_only => true unless aes_256_gcm?
   config.filter_run_excluding :broken => true
+  config.filter_run_excluding :not_wpar => true unless wpar?
+  config.filter_run_excluding :not_supported_under_fips => true if fips?
 
-  running_platform_arch = `uname -m`.strip
+  running_platform_arch = `uname -m`.strip unless windows?
 
   config.filter_run_excluding :arch => lambda {|target_arch|
     running_platform_arch != target_arch
@@ -157,13 +181,17 @@ RSpec.configure do |config|
   config.filter_run_excluding :provider => lambda {|criteria|
     type, target_provider = criteria.first
 
-    platform = TEST_PLATFORM.dup
-    platform_version = TEST_PLATFORM_VERSION.dup
-
-    begin
-      provider_for_running_platform = Chef::Platform.find_provider(platform, platform_version, type)
-      provider_for_running_platform != target_provider
-    rescue ArgumentError # no provider for platform
+    node = TEST_NODE.dup
+    resource_class = Chef::ResourceResolver.resolve(type, node: node)
+    if resource_class
+      resource = resource_class.new("test", Chef::RunContext.new(node, nil, nil))
+      begin
+        provider = resource.provider_for_action(Array(resource_class.default_action).first)
+        provider.class != target_provider
+      rescue Chef::Exceptions::ProviderNotFound # no provider for platform
+        true
+      end
+    else
       true
     end
   }
@@ -171,21 +199,28 @@ RSpec.configure do |config|
   config.run_all_when_everything_filtered = true
 
   config.before(:each) do
+    Chef.reset!
+
     Chef::Config.reset
 
     # By default, treat deprecation warnings as errors in tests.
     Chef::Config.treat_deprecation_warnings_as_errors(true)
 
     # Set environment variable so the setting persists in child processes
-    ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS'] = "1"
+    ENV["CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS"] = "1"
   end
 
+  # raise if anyone commits any test to CI with :focus set on it
+  config.before(:example, :focus) do
+    raise "This example was committed with `:focus` and should not have been"
+  end if ENV["CI"]
+
   config.before(:suite) do
     ARGV.clear
   end
 end
 
-require 'webrick/utils'
+require "webrick/utils"
 
 #    Webrick uses a centralized/synchronized timeout manager. It works by
 #    starting a thread to check for timeouts on an interval. The timeout
@@ -211,4 +246,4 @@ module WEBrick
 end
 
 # Enough stuff needs json serialization that I'm just adding it here for equality asserts
-require 'chef/json_compat'
+require "chef/json_compat"
diff --git a/spec/stress/win32/file_spec.rb b/spec/stress/win32/file_spec.rb
index 6c4b26b..f1c81eb 100644
--- a/spec/stress/win32/file_spec.rb
+++ b/spec/stress/win32/file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/win32/file' if windows?
+require "spec_helper"
+require "chef/win32/file" if windows?
 
-describe 'Chef::ReservedNames::Win32::File', :windows_only do
+describe "Chef::ReservedNames::Win32::File", :windows_only do
   before(:each) do
     @path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "old_home_dir", "my-dot-emacs"))
   end
diff --git a/spec/stress/win32/memory_spec.rb b/spec/stress/win32/memory_spec.rb
index ed3ad30..f5f429f 100644
--- a/spec/stress/win32/memory_spec.rb
+++ b/spec/stress/win32/memory_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-describe 'Chef::ReservedNames::Win32::Memory', :windows_only do
+describe "Chef::ReservedNames::Win32::Memory", :windows_only do
 end
diff --git a/spec/stress/win32/security_spec.rb b/spec/stress/win32/security_spec.rb
index cb520e5..e9da566 100644
--- a/spec/stress/win32/security_spec.rb
+++ b/spec/stress/win32/security_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 if windows?
-  require 'chef/win32/security'
-  require 'tmpdir'
-  require 'fileutils'
+  require "chef/win32/security"
+  require "tmpdir"
+  require "fileutils"
 end
 
-describe 'Chef::ReservedNames::Win32::Security', :windows_only do
+describe "Chef::ReservedNames::Win32::Security", :windows_only do
 
   def monkeyfoo
     File.join(CHEF_SPEC_DATA, "monkeyfoo").gsub("/", "\\")
@@ -60,7 +60,7 @@ describe 'Chef::ReservedNames::Win32::Security', :windows_only do
     expect {
       securable_object.dacl = Chef::ReservedNames::Win32::Security::ACL.create([
         Chef::ReservedNames::Win32::Security::ACE.access_allowed(Chef::ReservedNames::Win32::Security::SID.Everyone, Chef::ReservedNames::Win32::API::Security::GENERIC_READ),
-        Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL)
+        Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL),
       ])
       GC.start
     }.not_to leak_memory(:warmup => 50, :iterations => 100)
diff --git a/spec/support/chef_helpers.rb b/spec/support/chef_helpers.rb
index 851b1dc..aa60737 100644
--- a/spec/support/chef_helpers.rb
+++ b/spec/support/chef_helpers.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 #
 CHEF_SPEC_DATA = File.expand_path(File.dirname(__FILE__) + "/../data/")
 CHEF_SPEC_ASSETS = File.expand_path(File.dirname(__FILE__) + "/../functional/assets/")
-CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, 'test-backup-path')
+CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, "test-backup-path")
 
 Chef::Config[:log_level] = :fatal
 Chef::Config[:persistent_queue] = false
@@ -25,9 +25,8 @@ Chef::Log.init(StringIO.new)
 Chef::Log.level(Chef::Config.log_level)
 Chef::Config.solo(false)
 
-
 def sha256_checksum(path)
-  Digest::SHA256.hexdigest(File.read(path))
+  OpenSSL::Digest::SHA256.hexdigest(File.read(path))
 end
 
 # From Ruby 1.9.2+
@@ -82,12 +81,12 @@ end
 # This is a helper to canonicalize paths that we're using in the file
 # tests.
 def canonicalize_path(path)
-  windows? ? path.gsub('/', '\\') : path
+  windows? ? path.gsub("/", '\\') : path
 end
 
 # Check if a cmd exists on the PATH
 def which(cmd)
-  paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+  paths = ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
   paths.each do |path|
     filename = File.join(path, cmd)
     return filename if File.executable?(filename)
diff --git a/spec/support/key_helpers.rb b/spec/support/key_helpers.rb
new file mode 100644
index 0000000..33b8b32
--- /dev/null
+++ b/spec/support/key_helpers.rb
@@ -0,0 +1,104 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+shared_examples_for "a knife key command" do
+  let(:stderr) { StringIO.new }
+  let(:command) do
+    c = described_class.new([])
+    c.ui.config[:disable_editing] = true
+    allow(c.ui).to receive(:stderr).and_return(stderr)
+    allow(c.ui).to receive(:stdout).and_return(stderr)
+    allow(c).to receive(:show_usage)
+    c
+  end
+
+  context "before apply_params! is called" do
+    context "when apply_params! is called with invalid args (missing actor)" do
+      let(:params) { [] }
+      it "shows the usage" do
+        expect(command).to receive(:show_usage)
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+
+      it "outputs the proper error" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+        expect(stderr.string).to include(command.actor_missing_error)
+      end
+
+      it "exits 1" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+    end
+  end # before apply_params! is called
+
+  context "after apply_params! is called with valid args" do
+    before do
+      command.apply_params!(params)
+    end
+
+    it "properly defines the actor" do
+      expect(command.actor).to eq("charmander")
+    end
+  end # after apply_params! is called with valid args
+
+  context "when the command is run" do
+    before do
+      allow(command).to receive(:service_object).and_return(service_object)
+      allow(command).to receive(:name_args).and_return(["charmander"])
+    end
+
+    context "when the command is successful" do
+      before do
+        expect(service_object).to receive(:run)
+      end
+    end
+  end
+end # a knife key command
+
+shared_examples_for "a knife key command with a keyname as the second arg" do
+  let(:stderr) { StringIO.new }
+  let(:command) do
+    c = described_class.new([])
+    c.ui.config[:disable_editing] = true
+    allow(c.ui).to receive(:stderr).and_return(stderr)
+    allow(c.ui).to receive(:stdout).and_return(stderr)
+    allow(c).to receive(:show_usage)
+    c
+  end
+
+  context "before apply_params! is called" do
+    context "when apply_params! is called with invalid args (missing keyname)" do
+      let(:params) { ["charmander"] }
+      it "shows the usage" do
+        expect(command).to receive(:show_usage)
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+
+      it "outputs the proper error" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+        expect(stderr.string).to include(command.keyname_missing_error)
+      end
+
+      it "exits 1" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+    end
+  end # before apply_params! is called
+end
diff --git a/spec/support/lib/chef/provider/easy.rb b/spec/support/lib/chef/provider/easy.rb
index a4d285a..54f1bff 100644
--- a/spec/support/lib/chef/provider/easy.rb
+++ b/spec/support/lib/chef/provider/easy.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/lib/chef/provider/openldap_includer.rb b/spec/support/lib/chef/provider/openldap_includer.rb
new file mode 100644
index 0000000..302d600
--- /dev/null
+++ b/spec/support/lib/chef/provider/openldap_includer.rb
@@ -0,0 +1,29 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  class Provider
+    class OpenldapIncluder < Chef::Provider::LWRPBase
+      provides :openldap_includer
+
+      def action_run
+        include_recipe "openldap::default"
+      end
+    end
+  end
+end
diff --git a/spec/support/lib/chef/provider/snakeoil.rb b/spec/support/lib/chef/provider/snakeoil.rb
index 485d373..a42f889 100644
--- a/spec/support/lib/chef/provider/snakeoil.rb
+++ b/spec/support/lib/chef/provider/snakeoil.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/lib/chef/resource/cat.rb b/spec/support/lib/chef/resource/cat.rb
index ecca50c..94190e1 100644
--- a/spec/support/lib/chef/resource/cat.rb
+++ b/spec/support/lib/chef/resource/cat.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,13 +22,12 @@ class Chef
 
       attr_accessor :action
 
-      def initialize(name, run_context=nil)
-        @resource_name = :cat
+      def initialize(name, run_context = nil)
         super
         @action = "sell"
       end
 
-      def pretty_kitty(arg=nil)
+      def pretty_kitty(arg = nil)
         if arg == true or arg == false
           @pretty_kitty = arg
         end
diff --git a/spec/support/lib/chef/resource/one_two_three_four.rb b/spec/support/lib/chef/resource/one_two_three_four.rb
index 296d2cd..d46d20d 100644
--- a/spec/support/lib/chef/resource/one_two_three_four.rb
+++ b/spec/support/lib/chef/resource/one_two_three_four.rb
@@ -1,6 +1,6 @@
 #
 # Author:: John Hampton (<john at cleanoffer.com>)
-# Copyright:: Copyright (c) 2009 CleanOffer, Inc.
+# Copyright:: Copyright 2009-2016, CleanOffer, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,18 +19,14 @@
 class Chef
   class Resource
     class OneTwoThreeFour < Chef::Resource
-      attr_reader :i_can_count
 
-      def initialize(name, run_context)
-        @resource_name = :one_two_three_four
-        super
-      end
+      attr_reader :i_can_count
 
       def i_can_count(tf)
         @i_can_count = tf
       end
 
-      def something(arg=nil)
+      def something(arg = nil)
         if arg == true or arg == false
           @something = arg
         end
diff --git a/spec/support/lib/chef/resource/openldap_includer.rb b/spec/support/lib/chef/resource/openldap_includer.rb
new file mode 100644
index 0000000..5a7651b
--- /dev/null
+++ b/spec/support/lib/chef/resource/openldap_includer.rb
@@ -0,0 +1,26 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class Chef
+  class Resource
+    class OpenldapIncluder < Chef::Resource::LWRPBase
+      allowed_actions :run
+      default_action :run
+    end
+  end
+end
diff --git a/spec/support/lib/chef/resource/with_state.rb b/spec/support/lib/chef/resource/with_state.rb
index 226de0a..f256bf4 100644
--- a/spec/support/lib/chef/resource/with_state.rb
+++ b/spec/support/lib/chef/resource/with_state.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,13 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
 
 class Chef
   class Resource
     class WithState < Chef::Resource
       attr_accessor :state
-
-      def initialize(name, run_context=nil)
-        @resource_name = :with_state
-        super
-      end
-
-      def state
-        @state
-      end
     end
   end
 end
diff --git a/spec/support/lib/chef/resource/zen_follower.rb b/spec/support/lib/chef/resource/zen_follower.rb
index ddc289e..84fc71c 100644
--- a/spec/support/lib/chef/resource/zen_follower.rb
+++ b/spec/support/lib/chef/resource/zen_follower.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
 
 class Chef
   class Resource
@@ -24,12 +24,7 @@ class Chef
 
       provides :follower, platform: "zen"
 
-      def initialize(name, run_context=nil)
-        @resource_name = :zen_follower
-        super
-      end
-
-      def master(arg=nil)
+      def master(arg = nil)
         if !arg.nil?
           @master = arg
         end
diff --git a/spec/support/lib/chef/resource/zen_master.rb b/spec/support/lib/chef/resource/zen_master.rb
index d47d174..f5137c1 100644
--- a/spec/support/lib/chef/resource/zen_master.rb
+++ b/spec/support/lib/chef/resource/zen_master.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,21 @@
 # limitations under the License.
 #
 
-require 'chef/knife'
-require 'chef/json_compat'
+require "chef/knife"
+require "chef/json_compat"
 
 class Chef
   class Resource
     class ZenMaster < Chef::Resource
-      attr_reader :peace
+      allowed_actions :win, :score
 
-      def initialize(name, run_context=nil)
-        @resource_name = :zen_master
-        super
-        allowed_actions << :win << :score
-      end
+      attr_reader :peace
 
       def peace(tf)
         @peace = tf
       end
 
-      def something(arg=nil)
+      def something(arg = nil)
         if !arg.nil?
           @something = arg
         end
diff --git a/spec/support/lib/library_load_order.rb b/spec/support/lib/library_load_order.rb
index c47a2f2..6b4c54f 100644
--- a/spec/support/lib/library_load_order.rb
+++ b/spec/support/lib/library_load_order.rb
@@ -18,5 +18,3 @@ module LibraryLoadOrder
     load_order << file
   end
 end
-
-
diff --git a/spec/support/matchers/leak.rb b/spec/support/matchers/leak.rb
index 01d1e53..f50a1bf 100644
--- a/spec/support/matchers/leak.rb
+++ b/spec/support/matchers/leak.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ module Matchers
   module LeakBase
     include RSpec::Matchers
 
-    def initialize(opts={}, &block)
+    def initialize(opts = {}, &block)
       @warmup = opts[:warmup] || 5
       @iterations = opts[:iterations] || 100
       @variance = opts[:variance] || 5000
@@ -35,6 +35,7 @@ module Matchers
     end
 
     private
+
     def match(measure, given_proc)
       profiler.start
 
@@ -60,10 +61,10 @@ module Matchers
     def profiler
       @profiler ||= begin
         if Chef::Platform.windows?
-          require File.join(File.dirname(__FILE__), '..', 'platforms', 'prof', 'win32')
+          require File.join(File.dirname(__FILE__), "..", "platforms", "prof", "win32")
           RSpec::Prof::Win32::Profiler.new
         else
-          require File.join(File.dirname(__FILE__), '..', 'prof', 'gc')
+          require File.join(File.dirname(__FILE__), "..", "prof", "gc")
           RSpec::Prof::GC::Profiler.new
         end
       end
@@ -90,6 +91,7 @@ module Matchers
   def leak_memory(opts, &block)
     Matchers::LeakMemory.new(opts, &block)
   end
+
   def leak_handles(opts, &block)
     Matchers::LeakHandles.new(opts, &block)
   end
diff --git a/spec/support/mock/constant.rb b/spec/support/mock/constant.rb
index c706ad2..a2abc19 100644
--- a/spec/support/mock/constant.rb
+++ b/spec/support/mock/constant.rb
@@ -9,7 +9,7 @@ def mock_constants(constants, &block)
   constants.each do |constant, val|
     source_object, const_name = parse_constant(constant)
     saved_constants[constant] = source_object.const_get(const_name)
-    with_warnings(nil) {source_object.const_set(const_name, val) }
+    with_warnings(nil) { source_object.const_set(const_name, val) }
   end
 
   begin
@@ -23,7 +23,7 @@ def mock_constants(constants, &block)
 end
 
 def parse_constant(constant)
-  source, _, constant_name = constant.to_s.rpartition('::')
+  source, _, constant_name = constant.to_s.rpartition("::")
   [constantize(source), constant_name]
 end
 
@@ -41,7 +41,7 @@ end
 
 # File activesupport/lib/active_support/inflector/methods.rb, line 209
 def constantize(camel_cased_word)
-  names = camel_cased_word.split('::')
+  names = camel_cased_word.split("::")
   names.shift if names.empty? || names.first.empty?
 
   constant = Object
diff --git a/spec/support/mock/platform.rb b/spec/support/mock/platform.rb
index ab2c19b..ef94678 100644
--- a/spec/support/mock/platform.rb
+++ b/spec/support/mock/platform.rb
@@ -6,8 +6,8 @@
 # testing code that mixes in platform specific modules like +Chef::Mixin::Securable+
 # or +Chef::FileAccessControl+
 def platform_mock(platform = :unix, &block)
-  allow(Chef::Platform).to receive(:windows?).and_return(platform == :windows ? true : false)
-  ENV['SYSTEMDRIVE'] = (platform == :windows ? 'C:' : nil)
+  allow(ChefConfig).to receive(:windows?).and_return(platform == :windows ? true : false)
+  ENV["SYSTEMDRIVE"] = (platform == :windows ? "C:" : nil)
 
   if platform == :windows
     Chef::Config.set_defaults_for_windows
@@ -16,10 +16,10 @@ def platform_mock(platform = :unix, &block)
   end
 
   if block_given?
-    mock_constants({"RUBY_PLATFORM" => (platform == :windows ? 'i386-mingw32' : 'x86_64-darwin11.2.0'),
-                    "File::PATH_SEPARATOR" => (platform == :windows ? ";" : ":"),
-                    "File::ALT_SEPARATOR" => (platform == :windows ? "\\" : nil) }) do
-yield
+    mock_constants({ "RUBY_PLATFORM" => (platform == :windows ? "i386-mingw32" : "x86_64-darwin11.2.0"),
+                     "File::PATH_SEPARATOR" => (platform == :windows ? ";" : ":"),
+                     "File::ALT_SEPARATOR" => (platform == :windows ? "\\" : nil) }) do
+      yield
     end
   end
 end
diff --git a/spec/support/pedant/Gemfile b/spec/support/pedant/Gemfile
deleted file mode 100644
index d4224cd..0000000
--- a/spec/support/pedant/Gemfile
+++ /dev/null
@@ -1,3 +0,0 @@
-source "https://rubygems.org"
-
-gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => "server-cli-option"
diff --git a/spec/support/pedant/pedant_config.rb b/spec/support/pedant/pedant_config.rb
deleted file mode 100644
index 3f8219f..0000000
--- a/spec/support/pedant/pedant_config.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright: Copyright (c) 2012 Opscode, Inc.
-# License: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This annotated Pedant configuration file details the various
-# configuration settings available to you.  It is separate from the
-# actual Pedant::Config class because not all settings have sane
-# defaults, and not all settings are appropriate in all settings.
-
-################################################################################
-# You MUST specify the address of the server the API requests will be
-# sent to.  Only specify protocol, hostname, and port.
-# NOTE this is assigned in run_pedant.rb, because it's possible 8889 will not be the port chosen.
-#chef_server 'http://127.0.0.1:8889'
-
-# If you are doing development testing, you can specify the address of
-# the Solr server.  The presence of this parameter will enable tests
-# to force commits to Solr, greatly decreasing the amount of time
-# needed for testing the search endpoint.  This is only an
-# optimization for development!  If you are testing a "live" Chef
-# Server, or otherwise do not have access to the Solr server from your
-# testing location, you should not specify a value for this parameter.
-# The tests will still run, albeit slower, as they will now need to
-# poll for a period to ensure they are querying committed results.
-#search_server "http://localhost:8983"
-
-# Related to the 'search_server' parameter, this specifies the maximum
-# amount of time (in seconds) that search endpoint requests should be
-# retried before giving up.  If not explicitly set, it will default to
-# 65 seconds; only set it if you know that your Solr commit interval
-# differs significantly from this.
-maximum_search_time 0
-
-# OSC sends erchef a host header with a port, so this option needs
-# # to be enabled for Pedant tests to work correctly
-explicit_port_url true
-
-# We're starting to break tests up into groups based on different
-# criteria.  The proper API tests (the results of which are viewable
-# to OPC customers) should be the only ones run by Pedant embedded in
-# OPC installs.  There are other specs that help us keep track of API
-# cruft that we want to come back and fix later; these shouldn't be
-# viewable to customers, but we should be able to run them in
-# development and CI environments.  If this parameter is missing or
-# explicitly `false` only the customer-friendly tests will be run.
-#
-# This is mainly here for documentation purposes, since the
-# command-line `opscode-pedant` utility ultimately determines this
-# value.
-include_internal false
-
-# Test users.  The five users specified below are required; their
-# names (:user, :non_org_user, etc.) are indicative of their role
-# within the tests.  All users must have a ':name' key.  If they have
-# a ':create_me' key, Pedant will create these users for you.  If you
-# are using pre-existing users, you must supply a ':key_file' key,
-# which should be the fully-qualified path /on the machine Pedant is
-# running on/ to a private key for that user.
-key = 'spec/support/pedant/stickywicket.pem'
-superuser_name 'admin'
-superuser_key key
-webui_key key
-
-# When we updated Chef to RSpec 3 there were gem conflicts with chef-pedant.
-# We removed chef as a chef-pedant gem dependency in pedant.gemfile, but this
-# caused chef-pedant to fail because it could not query for the chef version
-# on the box pedant is running on. X-Chef-Version isn't needed in server
-# requests for these tests, so we've disabled it.
-ingore_x_chef_version true
-
-# Set the platform_class
-platform_class Pedant::OpenSourcePlatform
-
-requestors({
-  :clients => {
-    # The the admin user, for the purposes of getting things rolling
-    :admin => {
-      :name => "pedant_admin_client",
-      :create_me => true,
-      :create_knife => true,
-      :admin => true
-    },
-    :non_admin => {
-      :name => 'pedant_client',
-      :create_me => true,
-      :create_knife => true
-    },
-    :bad => {
-      :name => 'bad_client',
-      :bogus => true
-    }
-  },
-  :users => {
-    :admin => {
-      :name => "admin",
-      :key_file => key,
-      :create_me => false,
-      :create_knife => false,
-      :admin => true
-     },
-    :non_admin => {
-      :name => "pedant_non_admin_user",
-      :create_me => true,
-      :create_knife => true,
-      :admin => false
-    },
-    # A user for Knife tests.  A knife.rb and key files will be set up
-    # for this user
-    :knife_user => {
-      :name => "knifey",
-      :create_me => true,
-      :create_knife => true
-    }
-  }
-})
-
-self[:tags] = [:validation, :authentication, :authorization]
-verify_error_messages false
diff --git a/spec/support/pedant/run_pedant.rb b/spec/support/pedant/run_pedant.rb
deleted file mode 100644
index aac2c2d..0000000
--- a/spec/support/pedant/run_pedant.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env ruby
-require 'bundler'
-require 'bundler/setup'
-require 'chef_zero/server'
-require 'rspec/core'
-require 'chef/chef_fs/chef_fs_data_store'
-require 'chef/chef_fs/config'
-require 'tmpdir'
-require 'fileutils'
-require 'chef/version'
-require 'chef/mixin/shell_out'
-
-def start_server(chef_repo_path)
-  Dir.mkdir(chef_repo_path) if !File.exists?(chef_repo_path)
-
-  # 11.6 and below had a bug where it couldn't create the repo children automatically
-  if Chef::VERSION.to_f < 11.8
-    %w(clients cookbooks data_bags environments nodes roles users).each do |child|
-      Dir.mkdir("#{chef_repo_path}/#{child}") if !File.exists?("#{chef_repo_path}/#{child}")
-    end
-  end
-
-  # Start the new server
-  Chef::Config.repo_mode = 'everything'
-  Chef::Config.chef_repo_path = chef_repo_path
-  Chef::Config.versioned_cookbooks = true
-  chef_fs = Chef::ChefFS::Config.new.local_fs
-  data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
-  server = ChefZero::Server.new(:port => 8889.upto(9999), :data_store => data_store)#, :log_level => :debug)
-  server.start_background
-  server
-end
-
-tmpdir = Dir.mktmpdir
-begin
-  # Create chef repository
-  chef_repo_path = "#{tmpdir}/repo"
-
-  # Capture setup data into master_chef_repo_path
-  server = start_server(chef_repo_path)
-  so = nil
-
-  include Chef::Mixin::ShellOut
-
-  Bundler.with_clean_env do
-
-    shell_out("bundle install --gemfile spec/support/pedant/Gemfile", :live_stream => STDOUT)
-
-    pedant_cmd = "chef-pedant " +
-        " --config spec/support/pedant/pedant_config.rb" +
-        " --server '#{server.url}'" +
-        " --skip-knife --skip-validation --skip-authentication" +
-        " --skip-authorization --skip-omnibus"
-    so = shell_out("bundle exec #{pedant_cmd}", :live_stream => STDOUT, :env => {'BUNDLE_GEMFILE' => 'spec/support/pedant/Gemfile'})
-
-  end
-
-ensure
-  server.stop if server && server.running?
-  FileUtils.remove_entry_secure(tmpdir) if tmpdir
-end
-
-exit(so.exitstatus)
diff --git a/spec/support/pedant/stickywicket.pem b/spec/support/pedant/stickywicket.pem
deleted file mode 100644
index ff09e73..0000000
--- a/spec/support/pedant/stickywicket.pem
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEApNCkX2k+lFGDWRVhX4uClaVQrumG9XXvk6X7M2izrIg7RzMP
-Dk4thhZkpx5gr22By7PZQdMEjWC/Zo8MBjtoJ0GV0jw8npefbU1MGKs2dtpYgo0N
-Fq8fX8MdFPu4h2W3g0dMEdhT8icc2H4EjhZmdeUhUn3RIEt2duCgp3YDYnUUZx3j
-N7MHcTIdzD58ikr6zQrZzHOv+OOI86Xk9EpyEEQizOLoQxkICNrhqN7ElQDuvXaX
-BSBrYDRKH2umBMMcXzvsR/SvkmqxoEESSpIlW8zeKAWQ+znNjDC0tmTg7jZmgSP7
-siKrwo4t4ebjcmjpIoi/JKww/nGN3Uhz1ZOZuwIDAQABAoIBAQCaJQD2s0nyEeKU
-uKhfYe155Cl3zbWJcQnmv4AXbr9MiAVY6+oS6Q8ur1bn7kNjDzoruENjiuZhC7E3
-TGZklb8tp+tluyy+7vQOmBKpp8fClSfewekR5CultqhGbb8B8yIVR+NfdUHd4rLZ
-z9KWyWB+txPZQQ8L80gSmrfmpzs3IuT7oPvmtBU1Wq9QapC4n/rUohHUpUV1du4G
-0wCIF4zQTg6cbYW2YXozwVQvw+P7P3RVEqZt+aZlbVcy0fNr6jNao0hi1KFC9OH2
-VjjU+PioreoA/NU3aZPIUzmJpWtsu31yuOZxXmytAkYooCZgiEQNEHnJlNPv0RmC
-6BPMzVoBAoGBAM7yZoSNJpzdP/q1/4+H3zyy7o4I0VTW9u/GqUzhnbjm5poK30X9
-YXh/7WOVV0OoVqdO6ljRKygP3Oggf41ZEbi1C6bbsO57pksBWgx9bD9V35XscZ0J
-F1ERe//kMHwVQy74R8/cIuRwm75haLSBj5/fwGbLeeVDglJkCVqPjtuBAoGBAMvh
-qsAGG5k9u6voTcXlFwS+B5YjULhK4NSxdJ2BnOxzYzxQ3IYQZMlb2xt8yZYx/ZZK
-wjkr9rcAPEQIQZ2A6NUbGq6qCD7sSmg6UAi0CgiqTokQ/Wtag0UDvFMzwerdg/On
-37uxffpxpte8z1jYi/MxRaoTYueuc1UVnqofVIM7AoGBALZJzwPzUY/bVAADUJmd
-lYZiFsAGBF42/E05MOgH1GaK/ZWy/fkouDLsfK67XaK7JZk6ajLSDLG9R1kxRym6
-y2FoGFtiKPfo8xIenrNhx3gCrG/jVjB9UYyXWiKNXifukr9M8/SkdBfFGWsZYqGd
-fmXVMiVaFoVcce8hLxwWWEABAoGBAKcyhKX/HEj6YFqlIoqkydDAylXs1jicZ27l
-rF2yum8KXZpMMdzbutuKsdAD8Ql0K6NB4a+jByuiTMn5/11cJxUEqkgM9sArZQW+
-tH2+r+/VQpyTS0/rpXVGj/2nl2K1kI2T4R36e/aTl6CanWweAf9JK/lC9rxKyxg+
-p6SaFuObAoGACP6TKCkp2oymXlKgdUUgPrnsaz2VAw8jD5QHtx10U4wty0C8gxsk
-MLe00h09iLPyFmvJpD+MgbxV/r6RrZeVdsKdU/5LG52YgiVSTaizyy+ciEfW7xoQ
-CL5EtZd8Cn5OKinBEzzFpELqunlqepIKCIDOcLKz/cjR+3a+E6Zx5Wo=
------END RSA PRIVATE KEY-----
diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb
index da03137..b50c2a0 100644
--- a/spec/support/platform_helpers.rb
+++ b/spec/support/platform_helpers.rb
@@ -1,6 +1,6 @@
-require 'fcntl'
-require 'chef/mixin/shell_out'
-
+require "fcntl"
+require "chef/mixin/shell_out"
+require "ohai/mixin/gce_metadata"
 
 class ShellHelpers
   extend Chef::Mixin::ShellOut
@@ -11,11 +11,11 @@ def ruby_lt_20?
 end
 
 def chef_gte_13?
-  Chef::VERSION.split('.').first.to_i >= 13
+  Chef::VERSION.split(".").first.to_i >= 13
 end
 
 def chef_lt_13?
-  Chef::VERSION.split('.').first.to_i < 13
+  Chef::VERSION.split(".").first.to_i < 13
 end
 
 def ruby_gte_19?
@@ -26,6 +26,14 @@ def ruby_20?
   !!(RUBY_VERSION =~ /^2.0/)
 end
 
+def ruby_64bit?
+  !!(RbConfig::CONFIG["host_cpu"] =~ /x86_64/)
+end
+
+def ruby_32bit?
+  !!(RbConfig::CONFIG["host_cpu"] =~ /i686/)
+end
+
 def windows?
   !!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
 end
@@ -35,39 +43,39 @@ def ohai
   OHAI_SYSTEM
 end
 
-require 'wmi-lite/wmi' if windows?
+require "wmi-lite/wmi" if windows?
 
 def windows_domain_joined?
   return false unless windows?
   wmi = WmiLite::Wmi.new
-  computer_system = wmi.first_of('Win32_ComputerSystem')
-  computer_system['partofdomain']
+  computer_system = wmi.first_of("Win32_ComputerSystem")
+  computer_system["partofdomain"]
 end
 
 def windows_win2k3?
   return false unless windows?
   wmi = WmiLite::Wmi.new
-  host = wmi.first_of('Win32_OperatingSystem')
-  (host['version'] && host['version'].start_with?("5.2"))
+  host = wmi.first_of("Win32_OperatingSystem")
+  (host["version"] && host["version"].start_with?("5.2"))
 end
 
 def windows_2008r2_or_later?
   return false unless windows?
   wmi = WmiLite::Wmi.new
-  host = wmi.first_of('Win32_OperatingSystem')
-  version = host['version']
+  host = wmi.first_of("Win32_OperatingSystem")
+  version = host["version"]
   return false unless version
-  components = version.split('.').map do | component |
+  components = version.split(".").map do |component|
     component.to_i
   end
-  components.length >=2 && components[0] >= 6 && components[1] >= 1
+  components.length >= 2 && components[0] >= 6 && components[1] >= 1
 end
 
 def windows_powershell_dsc?
   return false unless windows?
   supports_dsc = false
   begin
-    wmi = WmiLite::Wmi.new('root/microsoft/windows/desiredstateconfiguration')
+    wmi = WmiLite::Wmi.new("root/microsoft/windows/desiredstateconfiguration")
     lcm = wmi.query("SELECT * FROM meta_class WHERE __this ISA 'MSFT_DSCLocalConfigurationManager'")
     supports_dsc = !! lcm
   rescue WmiLite::WmiException
@@ -75,6 +83,11 @@ def windows_powershell_dsc?
   supports_dsc
 end
 
+def windows_nano_server?
+  require "chef/platform/query_helpers"
+  Chef::Platform.windows_nano_server?
+end
+
 def mac_osx_106?
   if File.exists? "/usr/bin/sw_vers"
     result = ShellHelpers.shell_out("/usr/bin/sw_vers")
@@ -101,10 +114,9 @@ def mac_osx?
   false
 end
 
-
 # detects if the hardware is 64-bit (evaluates to true in "WOW64" mode in a 32-bit app on a 64-bit system)
 def windows64?
-  windows? && ( ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64' || ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64' )
+  windows? && ( ENV["PROCESSOR_ARCHITECTURE"] == "AMD64" || ENV["PROCESSOR_ARCHITEW6432"] == "AMD64" )
 end
 
 # detects if the hardware is 32-bit
@@ -130,22 +142,30 @@ def freebsd?
   !!(RUBY_PLATFORM =~ /freebsd/)
 end
 
+def debian_family?
+  !!(ohai[:platform_family] == "debian")
+end
+
 def aix?
   !!(RUBY_PLATFORM =~ /aix/)
 end
 
+def wpar?
+  !((ohai[:virtualization] || {})[:wpar_no].nil?)
+end
+
 def supports_cloexec?
-  Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
+  Fcntl.const_defined?("F_SETFD") && Fcntl.const_defined?("FD_CLOEXEC")
 end
 
-DEV_NULL = windows? ? 'NUL' : '/dev/null'
+DEV_NULL = windows? ? "NUL" : "/dev/null"
 
 def selinux_enabled?
   # This code is currently copied from lib/chef/util/selinux to make
   # specs independent of product.
   selinuxenabled_path = which("selinuxenabled")
   if selinuxenabled_path
-    cmd = Mixlib::ShellOut.new(selinuxenabled_path, :returns => [0,1])
+    cmd = Mixlib::ShellOut.new(selinuxenabled_path, :returns => [0, 1])
     cmd_result = cmd.run_command
     case cmd_result.exitstatus
     when 1
@@ -182,3 +202,17 @@ end
 def aes_256_gcm?
   OpenSSL::Cipher.ciphers.include?("aes-256-gcm")
 end
+
+def fips?
+  ENV["CHEF_FIPS"] == "1"
+end
+
+class GCEDetector
+  extend Ohai::Mixin::GCEMetadata
+end
+
+def gce?
+  GCEDetector.can_metadata_connect?(Ohai::Mixin::GCEMetadata::GCE_METADATA_ADDR, 80)
+rescue SocketError
+  false
+end
diff --git a/spec/support/platforms/prof/gc.rb b/spec/support/platforms/prof/gc.rb
index 6ca50df..2e1b45c 100644
--- a/spec/support/platforms/prof/gc.rb
+++ b/spec/support/platforms/prof/gc.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,4 +51,3 @@ module RSpec
     end
   end
 end
-
diff --git a/spec/support/platforms/prof/win32.rb b/spec/support/platforms/prof/win32.rb
index ab256ff..1cfbecc 100644
--- a/spec/support/platforms/prof/win32.rb
+++ b/spec/support/platforms/prof/win32.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/win32/process'
+require "chef/win32/process"
 
 module RSpec
   module Prof
@@ -43,4 +43,3 @@ module RSpec
     end
   end
 end
-
diff --git a/spec/support/platforms/win32/spec_service.rb b/spec/support/platforms/win32/spec_service.rb
index 3e1f6c3..c196e13 100644
--- a/spec/support/platforms/win32/spec_service.rb
+++ b/spec/support/platforms/win32/spec_service.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Serdar Sutay (<serdar at lambda.local>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'win32/daemon'
+require "win32/daemon"
 
 class SpecService < ::Win32::Daemon
   def service_init
@@ -26,7 +26,7 @@ class SpecService < ::Win32::Daemon
   def service_main(*startup_parameters)
     while running? do
       if !File.exists?(@test_service_file)
-        File.open(@test_service_file, 'wb') do |f|
+        File.open(@test_service_file, "wb") do |f|
           f.write("This file is created by SpecService")
         end
       end
diff --git a/spec/support/shared/context/client.rb b/spec/support/shared/context/client.rb
new file mode 100644
index 0000000..d8676ef
--- /dev/null
+++ b/spec/support/shared/context/client.rb
@@ -0,0 +1,285 @@
+
+require "spec_helper"
+
+# Stubs a basic client object
+shared_context "client" do
+  let(:fqdn)             { "hostname.example.org" }
+  let(:hostname)         { "hostname" }
+  let(:machinename)      { "machinename.example.org" }
+  let(:platform)         { "example-platform" }
+  let(:platform_version) { "example-platform-1.0" }
+
+  let(:ohai_data) do
+    {
+      :fqdn =>             fqdn,
+      :hostname =>         hostname,
+      :machinename =>      machinename,
+      :platform =>         platform,
+      :platform_version => platform_version,
+    }
+  end
+
+  let(:ohai_system) do
+    ohai = instance_double("Ohai::System", :all_plugins => true, :data => ohai_data)
+    allow(ohai).to receive(:[]) do |k|
+      ohai_data[k]
+    end
+    ohai
+  end
+
+  let(:node) do
+    Chef::Node.new.tap do |n|
+      n.name(fqdn)
+      n.chef_environment("_default")
+    end
+  end
+
+  let(:json_attribs) { nil }
+  let(:client_opts) { {} }
+
+  let(:client) do
+    Chef::Config[:event_loggers] = []
+    Chef::Client.new(json_attribs, client_opts).tap do |c|
+      c.node = node
+    end
+  end
+
+  before do
+    Chef::Log.logger = Logger.new(StringIO.new)
+
+    # Node/Ohai data
+    #Chef::Config[:node_name] = fqdn
+    allow(Ohai::System).to receive(:new).and_return(ohai_system)
+  end
+end
+
+# Stubs a client for a client run.
+# Requires a client object be defined in the scope of this included context.
+# e.g.:
+#   describe "some functionality" do
+#     include_context "client"
+#     include_context "a client run"
+#     ...
+#   end
+shared_context "a client run" do
+  let(:stdout) { StringIO.new }
+  let(:stderr) { StringIO.new }
+
+  let(:api_client_exists?) { false }
+  let(:enable_fork)        { false }
+
+  let(:http_cookbook_sync) { double("Chef::ServerAPI (cookbook sync)") }
+  let(:http_node_load)     { double("Chef::ServerAPI (node)") }
+  let(:http_node_save)     { double("Chef::ServerAPI (node save)") }
+  let(:reporting_rest_client) { double("Chef::ServerAPI (reporting client)") }
+
+  let(:runner)       { instance_double("Chef::Runner") }
+  let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => false) }
+
+  def stub_for_register
+    # --Client.register
+    #   Make sure Client#register thinks the client key doesn't
+    #   exist, so it tries to register and create one.
+    allow(File).to receive(:exists?).and_call_original
+    expect(File).to receive(:exists?).
+      with(Chef::Config[:client_key]).
+      exactly(:once).
+      and_return(api_client_exists?)
+
+    unless api_client_exists?
+      #   Client.register will register with the validation client name.
+      expect_any_instance_of(Chef::ApiClient::Registration).to receive(:run)
+    end
+  end
+
+  def stub_for_node_load
+    #   Client.register will then turn around create another
+    #   Chef::ServerAPI object, this time with the client key it got from the
+    #   previous step.
+    expect(Chef::ServerAPI).to receive(:new).
+      with(Chef::Config[:chef_server_url], client_name: fqdn,
+                                           signing_key_filename: Chef::Config[:client_key]).
+      exactly(:once).
+      and_return(http_node_load)
+
+    # --Client#build_node
+    #   looks up the node, which we will return, then later saves it.
+    expect(Chef::Node).to receive(:find_or_create).with(fqdn).and_return(node)
+
+    # --ResourceReporter#node_load_completed
+    #   gets a run id from the server for storing resource history
+    #   (has its own tests, so stubbing it here.)
+    expect_any_instance_of(Chef::ResourceReporter).to receive(:node_load_completed)
+  end
+
+  def stub_rest_clean
+    allow(client).to receive(:rest_clean).and_return(reporting_rest_client)
+  end
+
+  def stub_for_sync_cookbooks
+    # --Client#setup_run_context
+    # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
+    #
+    expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
+    expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+    expect(http_cookbook_sync).to receive(:post).
+      with("environments/_default/cookbook_versions", { :run_list => [] }).
+      and_return({})
+  end
+
+  def stub_for_converge
+    # define me
+  end
+
+  def stub_for_audit
+    # define me
+  end
+
+  def stub_for_node_save
+    # define me
+  end
+
+  def stub_for_run
+    # define me
+  end
+
+  before do
+    Chef::Config[:client_fork] = enable_fork
+    Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef"
+    Chef::Config[:why_run] = false
+    Chef::Config[:audit_mode] = :enabled
+
+    stub_const("Chef::Client::STDOUT_FD", stdout)
+    stub_const("Chef::Client::STDERR_FD", stderr)
+
+    stub_rest_clean
+    stub_for_register
+    stub_for_node_load
+    stub_for_sync_cookbooks
+    stub_for_converge
+    stub_for_audit
+    stub_for_node_save
+
+    expect_any_instance_of(Chef::RunLock).to receive(:acquire)
+    expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
+    expect_any_instance_of(Chef::RunLock).to receive(:release)
+
+    # Post conditions: check that node has been filled in correctly
+    expect(client).to receive(:run_started)
+
+    stub_for_run
+  end
+end
+
+shared_context "converge completed" do
+  def stub_for_converge
+    # --Client#converge
+    expect(Chef::Runner).to receive(:new).and_return(runner)
+    expect(runner).to receive(:converge).and_return(true)
+  end
+
+  def stub_for_node_save
+    allow(node).to receive(:data_for_save).and_return(node.for_json)
+
+    # --Client#save_updated_node
+    expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url], client_name: fqdn,
+                                                                                  signing_key_filename: Chef::Config[:client_key], validate_utf8: false).and_return(http_node_save)
+    expect(http_node_save).to receive(:put).with("nodes/#{fqdn}", node.for_json).and_return(true)
+  end
+end
+
+shared_context "converge failed" do
+  let(:converge_error) do
+    err = Chef::Exceptions::UnsupportedAction.new("Action unsupported")
+    err.set_backtrace([ "/path/recipe.rb:15", "/path/recipe.rb:12" ])
+    err
+  end
+
+  def stub_for_converge
+    expect(Chef::Runner).to receive(:new).and_return(runner)
+    expect(runner).to receive(:converge).and_raise(converge_error)
+  end
+
+  def stub_for_node_save
+    expect(client).to_not receive(:save_updated_node)
+  end
+end
+
+shared_context "audit phase completed" do
+  def stub_for_audit
+    # -- Client#run_audits
+    expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
+    expect(audit_runner).to receive(:run).and_return(true)
+    expect(client.events).to receive(:audit_phase_complete)
+  end
+end
+
+shared_context "audit phase failed with error" do
+  let(:audit_error) do
+    err = RuntimeError.new("Unexpected audit error")
+    err.set_backtrace([ "/path/recipe.rb:57", "/path/recipe.rb:55" ])
+    err
+  end
+
+  def stub_for_audit
+    expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
+    expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
+    expect(audit_runner).to receive(:run).and_raise(audit_error)
+    expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
+  end
+end
+
+shared_context "audit phase completed with failed controls" do
+  let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => true,
+                                                              :num_failed => 1, :num_total => 3) }
+
+  let(:audit_error) do
+    err = Chef::Exceptions::AuditsFailed.new(audit_runner.num_failed, audit_runner.num_total)
+    err.set_backtrace([ "/path/recipe.rb:108", "/path/recipe.rb:103" ])
+    err
+  end
+
+  def stub_for_audit
+    expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
+    expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
+    expect(audit_runner).to receive(:run)
+    expect(Chef::Exceptions::AuditsFailed).to receive(:new).with(
+      audit_runner.num_failed, audit_runner.num_total
+    ).and_return(audit_error)
+    expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
+  end
+end
+
+shared_context "run completed" do
+  def stub_for_run
+    expect(client).to receive(:run_completed_successfully)
+
+    # --ResourceReporter#run_completed
+    #   updates the server with the resource history
+    #   (has its own tests, so stubbing it here.)
+    expect_any_instance_of(Chef::ResourceReporter).to receive(:run_completed)
+    # --AuditReporter#run_completed
+    #   posts the audit data to server.
+    #   (has its own tests, so stubbing it here.)
+    expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_completed)
+  end
+end
+
+shared_context "run failed" do
+  def stub_for_run
+    expect(client).to receive(:run_failed)
+
+    # --ResourceReporter#run_completed
+    #   updates the server with the resource history
+    #   (has its own tests, so stubbing it here.)
+    expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
+    # --AuditReporter#run_completed
+    #   posts the audit data to server.
+    #   (has its own tests, so stubbing it here.)
+    expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
+  end
+
+  before do
+    expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
+  end
+end
diff --git a/spec/support/shared/context/config.rb b/spec/support/shared/context/config.rb
index 1412356..bb4ff7e 100644
--- a/spec/support/shared/context/config.rb
+++ b/spec/support/shared/context/config.rb
@@ -5,15 +5,15 @@
 #
 
 # Required chef files here:
-require 'chef/config'
+require "chef/config"
 
 # Required spec files here:
-require 'spec_helper'
+require "spec_helper"
 
 # Basic config. Nothing fancy.
 shared_context "default config options" do
   before do
-    Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
+    Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef"
   end
 
   # Don't need to have an after block to reset the config...
diff --git a/spec/support/shared/context/win32.rb b/spec/support/shared/context/win32.rb
new file mode 100644
index 0000000..98f7f90
--- /dev/null
+++ b/spec/support/shared/context/win32.rb
@@ -0,0 +1,34 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+RSpec.shared_context "Win32" do
+  before(:all) do
+    @original_win32 = if defined?(Win32)
+                        win32 = Object.send(:const_get, "Win32")
+                        Object.send(:remove_const, "Win32")
+                        win32
+                      else
+                        nil
+                      end
+    Win32 = Module.new
+  end
+
+  after(:all) do
+    Object.send(:remove_const, "Win32") if defined?(Win32)
+    Object.send(:const_set, "Win32", @original_win32) if @original_win32
+  end
+end
diff --git a/spec/support/shared/examples/client.rb b/spec/support/shared/examples/client.rb
new file mode 100644
index 0000000..3c13cd7
--- /dev/null
+++ b/spec/support/shared/examples/client.rb
@@ -0,0 +1,53 @@
+
+require "spec_helper"
+require "spec/support/shared/context/client"
+
+# requires platform and platform_version be defined
+shared_examples "a completed run" do
+  include_context "run completed"
+
+  it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges, and runs audits" do
+    # This is what we're testing.
+    expect(client.run).to be true
+
+    # fork is stubbed, so we can see the outcome of the run
+    expect(node.automatic_attrs[:platform]).to eq(platform)
+    expect(node.automatic_attrs[:platform_version]).to eq(platform_version)
+  end
+end
+
+shared_examples "a completed run with audit failure" do
+  include_context "run completed"
+
+  before do
+    expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
+  end
+
+  it "converges, runs audits, saves the node and raises the error in a wrapping error" do
+    expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+      expect(error.wrapped_errors.size).to eq(run_errors.size)
+      run_errors.each do |run_error|
+        expect(error.wrapped_errors).to include(run_error)
+        expect(error.backtrace).to include(*run_error.backtrace)
+      end
+    end
+
+    # fork is stubbed, so we can see the outcome of the run
+    expect(node.automatic_attrs[:platform]).to eq(platform)
+    expect(node.automatic_attrs[:platform_version]).to eq(platform_version)
+  end
+end
+
+shared_examples "a failed run" do
+  include_context "run failed"
+
+  it "skips node save and raises the error in a wrapping error" do
+    expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+      expect(error.wrapped_errors.size).to eq(run_errors.size)
+      run_errors.each do |run_error|
+        expect(error.wrapped_errors).to include(run_error)
+        expect(error.backtrace).to include(*run_error.backtrace)
+      end
+    end
+  end
+end
diff --git a/spec/support/shared/functional/diff_disabled.rb b/spec/support/shared/functional/diff_disabled.rb
index 7ee9808..c40b1e6 100644
--- a/spec/support/shared/functional/diff_disabled.rb
+++ b/spec/support/shared/functional/diff_disabled.rb
@@ -1,5 +1,5 @@
 
-shared_context "diff disabled"  do
+shared_context "diff disabled" do
   before do
     Chef::Config[:diff_disabled] = true
   end
diff --git a/spec/support/shared/functional/directory_resource.rb b/spec/support/shared/functional/directory_resource.rb
index 39bdc31..084cd43 100644
--- a/spec/support/shared/functional/directory_resource.rb
+++ b/spec/support/shared/functional/directory_resource.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ shared_examples_for "a directory resource" do
 
   include_context "diff disabled"
 
-  let(:expect_updated?) {true}
+  let(:expect_updated?) { true }
 
   context "when the target directory does not exist" do
     before do
@@ -48,7 +48,7 @@ shared_examples_for "a directory resource" do
           expect(File).not_to exist(path)
 
           resource.recursive(true)
-          @recursive_path = File.join(path, 'red-headed-stepchild')
+          @recursive_path = File.join(path, "red-headed-stepchild")
           resource.path(@recursive_path)
           resource.run_action(:create)
         end
@@ -68,14 +68,14 @@ shared_examples_for "a directory resource" do
     def allowed_acl(sid, expected_perms)
       [
        ACE.access_allowed(sid, expected_perms[:specific]),
-       ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
+       ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
       ]
     end
 
     def denied_acl(sid, expected_perms)
       [
        ACE.access_denied(sid, expected_perms[:specific]),
-       ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
+       ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
       ]
     end
 
@@ -133,7 +133,7 @@ shared_examples_for "a directory resource" do
 
       context "with the recursive option" do
         before do
-          FileUtils.mkdir(File.join(path, 'red-headed-stepchild'))
+          FileUtils.mkdir(File.join(path, "red-headed-stepchild"))
           resource.recursive(true)
           resource.run_action(:delete)
         end
@@ -152,7 +152,7 @@ shared_context Chef::Resource::Directory do
   # deployment strategies more completely.
   let(:test_file_dir) do
     if windows?
-      File.join(ENV['systemdrive'], "test-dir")
+      File.join(ENV["systemdrive"], "test-dir")
     else
       File.join(CHEF_SPEC_DATA, "test-dir")
     end
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index 4f8e2f5..5f34f1e 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,7 +44,6 @@ shared_context "deploying via destdir" do
   end
 end
 
-
 shared_examples_for "a file with the wrong content" do
   before do
     # Assert starting state is as expected
@@ -103,7 +102,7 @@ shared_examples_for "a file with the wrong content" do
         end
 
         it "raises an exception" do
-          expect{ resource.run_action(:create) }.to raise_error(Chef::Exceptions::ChecksumMismatch)
+          expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::ChecksumMismatch)
         end
       end
     end
@@ -144,7 +143,7 @@ shared_examples_for "a file with the wrong content" do
   end
 
   context "when diff is enabled" do
-    describe 'sensitive attribute' do
+    describe "sensitive attribute" do
       context "should be insensitive by default" do
         it { expect(resource.sensitive).to(be_falsey) }
       end
@@ -165,7 +164,7 @@ shared_examples_for "a file with the wrong content" do
           end
 
           it "should suppress the diff" do
-            expect(resource.diff).to(include('suppressed sensitive resource'))
+            expect(resource.diff).to(include("suppressed sensitive resource"))
             expect(reporter_messages[1]).to eq("suppressed sensitive resource")
           end
 
@@ -308,14 +307,14 @@ shared_examples_for "a file resource" do
 
   describe "when setting atomic_update" do
     it "booleans should work" do
-      expect {resource.atomic_update(true)}.not_to raise_error
-      expect {resource.atomic_update(false)}.not_to raise_error
+      expect { resource.atomic_update(true) }.not_to raise_error
+      expect { resource.atomic_update(false) }.not_to raise_error
     end
 
     it "anything else should raise an error" do
-      expect {resource.atomic_update(:copy)}.to raise_error(ArgumentError)
-      expect {resource.atomic_update(:move)}.to raise_error(ArgumentError)
-      expect {resource.atomic_update(958)}.to raise_error(ArgumentError)
+      expect { resource.atomic_update(:copy) }.to raise_error(ArgumentError)
+      expect { resource.atomic_update(:move) }.to raise_error(ArgumentError)
+      expect { resource.atomic_update(958) }.to raise_error(ArgumentError)
     end
   end
 
@@ -351,13 +350,13 @@ shared_examples_for "file resource not pointing to a real file" do
 
   describe "when force_unlink is set to false" do
     it ":create raises an error" do
-      expect {resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
+      expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
     end
   end
 
   describe "when force_unlink is not set (default)" do
     it ":create raises an error" do
-      expect {resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
+      expect { resource.run_action(:create) }.to raise_error(Chef::Exceptions::FileTypeMismatch)
     end
   end
 end
@@ -405,7 +404,6 @@ shared_examples_for "a configured file resource" do
       File.join(CHEF_SPEC_DATA, "file-test-target")
     }
 
-
     describe "when configured not to manage symlink's target" do
       before(:each) do
         # configure not to manage symlink source
@@ -574,7 +572,6 @@ shared_examples_for "a configured file resource" do
             File.open(path, "wb") { |f| f.write(expected_content) }
           end
 
-
           include_context "setup broken permissions"
 
           include_examples "a securable resource with existing target"
@@ -592,10 +589,6 @@ shared_examples_for "a configured file resource" do
             File.open(path, "wb") { |f| f.write(wrong_content) }
           end
 
-          it "updates the source file content" do
-            skip
-          end
-
           it "marks the resource as updated" do
             resource.run_action(:create)
             expect(resource).to be_updated_by_last_action
@@ -725,7 +718,7 @@ shared_examples_for "a configured file resource" do
     it_behaves_like "file resource not pointing to a real file"
   end
 
-  context "when the target file is a blockdev",:unix_only, :requires_root, :not_supported_on_solaris do
+  context "when the target file is a blockdev", :unix_only, :requires_root, :not_supported_on_solaris do
     include Chef::Mixin::ShellOut
     let(:path) do
       File.join(CHEF_SPEC_DATA, "testdev")
@@ -743,7 +736,7 @@ shared_examples_for "a configured file resource" do
     it_behaves_like "file resource not pointing to a real file"
   end
 
-  context "when the target file is a chardev",:unix_only, :requires_root, :not_supported_on_solaris do
+  context "when the target file is a chardev", :unix_only, :requires_root, :not_supported_on_solaris do
     include Chef::Mixin::ShellOut
     let(:path) do
       File.join(CHEF_SPEC_DATA, "testdev")
@@ -761,7 +754,7 @@ shared_examples_for "a configured file resource" do
     it_behaves_like "file resource not pointing to a real file"
   end
 
-  context "when the target file is a pipe",:unix_only do
+  context "when the target file is a pipe", :unix_only do
     include Chef::Mixin::ShellOut
     let(:path) do
       File.join(CHEF_SPEC_DATA, "testpipe")
@@ -779,8 +772,8 @@ shared_examples_for "a configured file resource" do
     it_behaves_like "file resource not pointing to a real file"
   end
 
-  context "when the target file is a socket",:unix_only do
-    require 'socket'
+  context "when the target file is a socket", :unix_only do
+    require "socket"
 
     # It turns out that the path to a socket can have at most ~104
     # bytes. Therefore we are creating our sockets in tmpdir so that
@@ -1022,16 +1015,16 @@ shared_examples_for "a configured file resource" do
 
 end
 
-shared_context Chef::Resource::File  do
+shared_context Chef::Resource::File do
   if windows?
-    require 'chef/win32/file'
+    require "chef/win32/file"
   end
 
   # We create the files in a different directory than tmp to exercise
   # different file deployment strategies more completely.
   let(:test_file_dir) do
     if windows?
-      File.join(ENV['systemdrive'], "test-dir")
+      File.join(ENV["systemdrive"], "test-dir")
     else
       File.join(CHEF_SPEC_DATA, "test-dir")
     end
diff --git a/spec/support/shared/functional/http.rb b/spec/support/shared/functional/http.rb
index 963fbf1..8e6b5bf 100644
--- a/spec/support/shared/functional/http.rb
+++ b/spec/support/shared/functional/http.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,11 +22,11 @@
 
 module ChefHTTPShared
   def nyan_uncompressed_filename
-    File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png')
+    File.join(CHEF_SPEC_DATA, "remote_file", "nyan_cat.png")
   end
 
   def nyan_compressed_filename
-    File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz')
+    File.join(CHEF_SPEC_DATA, "remote_file", "nyan_cat.png.gz")
   end
 
   def binread(file)
@@ -37,7 +37,7 @@ module ChefHTTPShared
     content
   end
 
-  def start_tiny_server(server_opts={})
+  def start_tiny_server(server_opts = {})
     nyan_uncompressed_size = File::Stat.new(nyan_uncompressed_filename).size
     nyan_compressed_size   = File::Stat.new(nyan_compressed_filename).size
 
@@ -60,7 +60,7 @@ module ChefHTTPShared
 
     # this ends in .gz, we do not uncompress it and drop it on the filesystem as a .gz file (the internet often lies)
     # (expected_content should be compressed)
-    @api.get("/nyan_cat.png.gz", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+    @api.get("/nyan_cat.png.gz", 200, nil, { "Content-Type" => "application/gzip", "Content-Encoding" => "gzip" } ) {
       File.open(nyan_compressed_filename, "rb") do |f|
         f.read
       end
@@ -68,7 +68,7 @@ module ChefHTTPShared
 
     # this is an uncompressed file that was compressed by some mod_gzip-ish webserver thingy, so we will expand it
     # (expected_content should be uncompressed)
-    @api.get("/nyan_cat_compressed.png", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) {
+    @api.get("/nyan_cat_compressed.png", 200, nil, { "Content-Type" => "application/gzip", "Content-Encoding" => "gzip" } ) {
       File.open(nyan_compressed_filename, "rb") do |f|
         f.read
       end
@@ -81,7 +81,7 @@ module ChefHTTPShared
     # (expected_content should be uncompressed)
     @api.get("/nyan_cat_content_length.png", 200, nil,
       {
-        'Content-Length'   => nyan_uncompressed_size.to_s,
+        "Content-Length"   => nyan_uncompressed_size.to_s
       }
     ) {
       File.open(nyan_uncompressed_filename, "rb") do |f|
@@ -92,9 +92,9 @@ module ChefHTTPShared
     # (expected_content should be uncompressed)
     @api.get("/nyan_cat_content_length_compressed.png", 200, nil,
       {
-        'Content-Length'   => nyan_compressed_size.to_s,
-        'Content-Type'     => 'application/gzip',
-        'Content-Encoding' => 'gzip'
+        "Content-Length"   => nyan_compressed_size.to_s,
+        "Content-Type"     => "application/gzip",
+        "Content-Encoding" => "gzip",
       }
     ) {
       File.open(nyan_compressed_filename, "rb") do |f|
@@ -109,7 +109,7 @@ module ChefHTTPShared
     # (expected_content should be uncompressed)
     @api.get("/nyan_cat_truncated.png", 200, nil,
       {
-        'Content-Length'   => (nyan_uncompressed_size + 1).to_s,
+        "Content-Length"   => (nyan_uncompressed_size + 1).to_s
       }
     ) {
       File.open(nyan_uncompressed_filename, "rb") do |f|
@@ -120,9 +120,9 @@ module ChefHTTPShared
     # (expected_content should be uncompressed)
     @api.get("/nyan_cat_truncated_compressed.png", 200, nil,
       {
-        'Content-Length'   => (nyan_compressed_size + 1).to_s,
-        'Content-Type'     => 'application/gzip',
-        'Content-Encoding' => 'gzip'
+        "Content-Length"   => (nyan_compressed_size + 1).to_s,
+        "Content-Type"     => "application/gzip",
+        "Content-Encoding" => "gzip",
       }
     ) {
       File.open(nyan_compressed_filename, "rb") do |f|
@@ -137,8 +137,8 @@ module ChefHTTPShared
     # (expected_content should be uncompressed)
     @api.get("/nyan_cat_transfer_encoding.png", 200, nil,
       {
-        'Content-Length'    => (nyan_uncompressed_size + 1).to_s,
-        'Transfer-Encoding' => 'anything',
+        "Content-Length"    => (nyan_uncompressed_size + 1).to_s,
+        "Transfer-Encoding" => "anything",
       }
     ) {
       File.open(nyan_uncompressed_filename, "rb") do |f|
@@ -149,20 +149,19 @@ module ChefHTTPShared
     #
     # 403 with a Content-Length
     #
-    @api.get('/forbidden', 403, 'Forbidden',
+    @api.get("/forbidden", 403, "Forbidden",
       {
-        'Content-Length' => 'Forbidden'.bytesize.to_s
+        "Content-Length" => "Forbidden".bytesize.to_s
       }
     )
 
-    @api.post('/posty', 200, 'Hi!')
+    @api.post("/posty", 200, "Hi!")
 
     #
     # 400 with an error
     #
-    @api.get('/bad_request', 400, '{ "error": [ "Your request is just terrible." ] }')
-    @api.post('/bad_request', 400, '{ "error": [ "Your request is just terrible." ] }')
-
+    @api.get("/bad_request", 400, '{ "error": [ "Your request is just terrible." ] }')
+    @api.post("/bad_request", 400, '{ "error": [ "Your request is just terrible." ] }')
   end
 
   def stop_tiny_server
@@ -175,14 +174,14 @@ end
 shared_examples_for "downloading all the things" do
 
   describe "when downloading a simple uncompressed file" do
-    let(:source) { 'http://localhost:9000/nyan_cat.png' }
+    let(:source) { "http://localhost:9000/nyan_cat.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "downloads requests correctly"
   end
 
   describe "when downloading a compressed file that should be left compressed" do
-    let(:source) { 'http://localhost:9000/nyan_cat.png.gz' }
+    let(:source) { "http://localhost:9000/nyan_cat.png.gz" }
     let(:expected_content) { binread(nyan_compressed_filename) }
 
     # its the callers responsibility to disable_gzip when downloading a .gz url
@@ -192,57 +191,57 @@ shared_examples_for "downloading all the things" do
   end
 
   describe "when downloading a file that has been compressed by the webserver" do
-    let(:source) { 'http://localhost:9000/nyan_cat_compressed.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_compressed.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "downloads requests correctly"
   end
 
   describe "when downloading an uncompressed file with a correct content_length" do
-    let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_content_length.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "downloads requests correctly"
   end
 
   describe "when downloading a file that has been compressed by the webserver with a correct content_length" do
-    let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "downloads requests correctly"
   end
 
   describe "when downloading an uncompressed file that is truncated" do
-    let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_truncated.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "validates content length and throws an exception"
   end
 
   describe "when downloading a file that has been compressed by the webserver that is truncated" do
-    let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_truncated_compressed.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "validates content length and throws an exception"
   end
 
   describe "when downloading a file that has transfer encoding set with a bad content length that should be ignored" do
-    let(:source) { 'http://localhost:9000/nyan_cat_transfer_encoding.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_transfer_encoding.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
 
     it_behaves_like "downloads requests correctly"
   end
 
   describe "when downloading an endpoint that 403s" do
-    let(:source) { 'http://localhost:9000/forbidden' }
+    let(:source) { "http://localhost:9000/forbidden" }
 
     it_behaves_like "an endpoint that 403s"
   end
 
   describe "when downloading an endpoint that 403s" do
-    let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' }
+    let(:source) { "http://localhost:9000/nyan_cat_content_length_compressed.png" }
     let(:expected_content) { binread(nyan_uncompressed_filename) }
-    let(:source2) { 'http://localhost:9000/forbidden' }
+    let(:source2) { "http://localhost:9000/forbidden" }
 
     it_behaves_like "a 403 after a successful request when reusing the request object"
   end
diff --git a/spec/support/shared/functional/knife.rb b/spec/support/shared/functional/knife.rb
index e96de7c..694d0de 100644
--- a/spec/support/shared/functional/knife.rb
+++ b/spec/support/shared/functional/knife.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Author:: Ho-Sheng Hsiao (<hosh at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Ho-Sheng Hsiao (<hosh at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/support/shared/functional/securable_resource.rb b/spec/support/shared/functional/securable_resource.rb
index e016bb6..dd8a021 100644
--- a/spec/support/shared/functional/securable_resource.rb
+++ b/spec/support/shared/functional/securable_resource.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Author:: Mark Mzyk (<mmzyk at opscode.com>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Author:: Mark Mzyk (<mmzyk at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'etc'
-require 'functional/resource/base'
+require "etc"
+require "functional/resource/base"
 
 shared_context "setup correct permissions" do
   if windows?
@@ -38,9 +38,9 @@ shared_context "setup correct permissions" do
   # Root only context.
   before :each, :unix_only, :requires_root do
     if ohai[:platform] == "aix"
-      File.chown(Etc.getpwnam('guest').uid, 1337, path)
+      File.chown(Etc.getpwnam("guest").uid, 1337, path)
     else
-      File.chown(Etc.getpwnam('nobody').uid, 1337, path)
+      File.chown(Etc.getpwnam("nobody").uid, 1337, path)
     end
   end
 
@@ -111,28 +111,28 @@ shared_context "use Windows permissions", :windows_only do
   let(:expected_read_execute_perms) do
     {
       :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE,
-      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE
+      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE,
     }
   end
 
   let(:expected_write_perms) do
     {
       :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
-      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
+      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE,
     }
   end
 
   let(:expected_modify_perms) do
     {
       :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
-      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE
+      :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
     }
   end
 
   let(:expected_full_control_perms) do
     {
       :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_ALL,
-      :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS
+      :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS,
     }
   end
 
@@ -155,17 +155,14 @@ shared_examples_for "a securable resource with existing target" do
 
   context "on Unix", :unix_only do
     if ohai[:platform] == "aix"
-      let(:expected_user_name) { 'guest' }
+      let(:expected_user_name) { "guest" }
     else
-      let(:expected_user_name) { 'nobody' }
+      let(:expected_user_name) { "nobody" }
     end
     let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
     let(:desired_gid) { 1337 }
     let(:expected_gid) { 1337 }
 
-    skip "should set an owner (Rerun specs under root)", :requires_unprivileged_user => true
-    skip "should set a group (Rerun specs under root)",  :requires_unprivileged_user => true
-
     describe "when setting the owner", :requires_root do
       before do
         resource.owner expected_user_name
@@ -200,16 +197,11 @@ shared_examples_for "a securable resource with existing target" do
 
     describe "when setting the permissions from octal given as a String" do
       before do
-        @mode_string = '776'
+        @mode_string = "776"
         resource.mode @mode_string
         resource.run_action(:create)
       end
 
-      it "should set permissions as specified" do
-        pending("Linux does not support lchmod")
-        expect{ File.lstat(path).mode & 007777 }.to eq(@mode_string.oct & 007777)
-      end
-
       it "is marked as updated only if changes are made" do
         expect(resource.updated_by_last_action?).to eq(expect_updated?)
       end
@@ -222,15 +214,28 @@ shared_examples_for "a securable resource with existing target" do
         resource.run_action(:create)
       end
 
-      it "should set permissions in numeric form as a ruby-interpreted octal" do
-        pending('Linux does not support lchmod')
-        expect{ File.lstat(path).mode & 007777 }.to eq(@mode_integer & 007777)
-      end
-
       it "is marked as updated only if changes are made" do
         expect(resource.updated_by_last_action?).to eq(expect_updated?)
       end
     end
+
+    describe "when setting the suid bit", :requires_root do
+      before do
+        @suid_mode = 04776
+        resource.mode @suid_mode
+        resource.run_action(:create)
+      end
+
+      it "should set the suid bit" do
+        expect(File.lstat(path).mode & 007777).to eq(@suid_mode & 007777)
+      end
+
+      it "should retain the suid bit when updating the user" do
+        resource.user 1338
+        resource.run_action(:create)
+        expect(File.lstat(path).mode & 007777).to eq(@suid_mode & 007777)
+      end
+    end
   end
 
   context "on Windows", :windows_only do
@@ -253,7 +258,7 @@ shared_examples_for "a securable resource with existing target" do
 
     describe "when setting group" do
       before do
-        resource.group('Administrators')
+        resource.group("Administrators")
         resource.run_action(:create)
       end
 
@@ -268,8 +273,8 @@ shared_examples_for "a securable resource with existing target" do
 
     describe "when setting rights and deny_rights" do
       before do
-        resource.deny_rights(:modify, 'Guest')
-        resource.rights(:read, 'Guest')
+        resource.deny_rights(:modify, "Guest")
+        resource.rights(:read, "Guest")
         resource.run_action(:create)
       end
 
@@ -288,21 +293,17 @@ shared_examples_for "a securable resource without existing target" do
 
   include_context "diff disabled"
 
-  context "on Unix", :unix_only do
-    skip "if we need any securable resource tests on Unix without existing target resource."
-  end
-
   context "on Windows", :windows_only do
     include_context "use Windows permissions"
 
-    it "sets owner to Administrators on create if owner is not specified" do
+    it "leaves owner as system default on create if owner is not specified" do
       expect(File.exist?(path)).to eq(false)
       resource.run_action(:create)
-      expect(descriptor.owner).to eq(SID.Administrators)
+      expect(descriptor.owner).to eq(SID.default_security_object_owner)
     end
 
     it "sets owner when owner is specified" do
-      resource.owner 'Guest'
+      resource.owner "Guest"
       resource.run_action(:create)
       expect(descriptor.owner).to eq(SID.Guest)
     end
@@ -318,26 +319,28 @@ shared_examples_for "a securable resource without existing target" do
     end
 
     it "leaves owner alone if owner is not specified and resource already exists" do
-      # Set owner to Guest so it's not the same as the current user (which is the default on create)
-      resource.owner 'Guest'
+      arbitrary_non_default_owner = SID.Guest
+      expect(arbitrary_non_default_owner).not_to eq(SID.default_security_object_owner)
+
+      resource.owner "Guest" # Change to arbitrary_non_default_owner once issue #1508 is fixed
       resource.run_action(:create)
-      expect(descriptor.owner).to eq(SID.Guest)
+      expect(descriptor.owner).to eq(arbitrary_non_default_owner)
 
       new_resource = create_resource
       expect(new_resource.owner).to eq(nil)
       new_resource.run_action(:create)
-      expect(descriptor.owner).to eq(SID.Guest)
+      expect(descriptor.owner).to eq(arbitrary_non_default_owner)
     end
 
-    it "sets group to None on create if group is not specified" do
+    it "leaves group as system default on create if group is not specified" do
       expect(resource.group).to eq(nil)
       expect(File.exist?(path)).to eq(false)
       resource.run_action(:create)
-      expect(descriptor.group).to eq(SID.None)
+      expect(descriptor.group).to eq(SID.default_security_object_group)
     end
 
     it "sets group when group is specified" do
-      resource.group 'Everyone'
+      resource.group "Everyone"
       resource.run_action(:create)
       expect(descriptor.group).to eq(SID.Everyone)
     end
@@ -346,67 +349,62 @@ shared_examples_for "a securable resource without existing target" do
       expect { resource.group 'Lance "The Nose" Glindenberry III' }.to raise_error(Chef::Exceptions::ValidationFailed)
     end
 
-    it "sets group when group is specified with a \\" do
-      pending("Need to find a group containing a backslash that is on most peoples' machines")
-      resource.group "#{ENV['COMPUTERNAME']}\\Administrators"
-      resource.run_action(:create)
-      expect{ descriptor.group }.to eq(SID.Everyone)
-    end
-
     it "leaves group alone if group is not specified and resource already exists" do
-      # Set group to Everyone so it's not the default (None)
-      resource.group 'Everyone'
+      arbitrary_non_default_group = SID.Everyone
+      expect(arbitrary_non_default_group).not_to eq(SID.default_security_object_group)
+
+      resource.group "Everyone" # Change to arbitrary_non_default_group once issue #1508 is fixed
       resource.run_action(:create)
-      expect(descriptor.group).to eq(SID.Everyone)
+      expect(descriptor.group).to eq(arbitrary_non_default_group)
 
       new_resource = create_resource
       expect(new_resource.group).to eq(nil)
       new_resource.run_action(:create)
-      expect(descriptor.group).to eq(SID.Everyone)
+      expect(descriptor.group).to eq(arbitrary_non_default_group)
     end
 
     describe "with rights and deny_rights attributes" do
 
       it "correctly sets :read rights" do
-        resource.rights(:read, 'Guest')
+        resource.rights(:read, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
       end
 
       it "correctly sets :read_execute rights" do
-        resource.rights(:read_execute, 'Guest')
+        resource.rights(:read_execute, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
       end
 
       it "correctly sets :write rights" do
-        resource.rights(:write, 'Guest')
+        resource.rights(:write, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms))
       end
 
       it "correctly sets :modify rights" do
-        resource.rights(:modify, 'Guest')
+        resource.rights(:modify, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
       end
 
       it "correctly sets :full_control rights" do
-        resource.rights(:full_control, 'Guest')
+        resource.rights(:full_control, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
       end
 
       it "correctly sets deny_rights" do
         # deny is an ACE with full rights, but is a deny type ace, not an allow type
-        resource.deny_rights(:full_control, 'Guest')
+        resource.deny_rights(:full_control, "Guest")
         resource.run_action(:create)
         expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
       end
 
       it "Sets multiple rights" do
-        resource.rights(:read, 'Everyone')
-        resource.rights(:modify, 'Guest')
+        resource.rights(:read, "Everyone")
+        resource.rights(:modify, "Guest")
         resource.run_action(:create)
 
         expect(explicit_aces).to eq(
@@ -416,8 +414,8 @@ shared_examples_for "a securable resource without existing target" do
       end
 
       it "Sets deny_rights ahead of rights" do
-        resource.rights(:read, 'Everyone')
-        resource.deny_rights(:modify, 'Guest')
+        resource.rights(:read, "Everyone")
+        resource.deny_rights(:modify, "Guest")
         resource.run_action(:create)
 
         expect(explicit_aces).to eq(
@@ -427,8 +425,8 @@ shared_examples_for "a securable resource without existing target" do
       end
 
       it "Sets deny_rights ahead of rights when specified in reverse order" do
-        resource.deny_rights(:modify, 'Guest')
-        resource.rights(:read, 'Everyone')
+        resource.deny_rights(:modify, "Guest")
+        resource.rights(:read, "Everyone")
         resource.run_action(:create)
 
         expect(explicit_aces).to eq(
@@ -447,9 +445,9 @@ shared_examples_for "a securable resource without existing target" do
       it "respects mode in string form as an octal number" do
         #on windows, mode cannot modify owner and/or group permissons
         #unless the owner and/or group as appropriate is specified
-        resource.mode '400'
-        resource.owner 'Guest'
-        resource.group 'Everyone'
+        resource.mode "400"
+        resource.owner "Guest"
+        resource.group "Everyone"
         resource.run_action(:create)
 
         expect(explicit_aces).to eq([ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ) ])
@@ -457,7 +455,7 @@ shared_examples_for "a securable resource without existing target" do
 
       it "respects mode in numeric form as a ruby-interpreted octal" do
         resource.mode 0700
-        resource.owner 'Guest'
+        resource.owner "Guest"
         resource.run_action(:create)
 
         expect(explicit_aces).to eq([ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE) ])
@@ -465,31 +463,31 @@ shared_examples_for "a securable resource without existing target" do
 
       it "respects the owner, group and everyone bits of mode" do
         resource.mode 0754
-        resource.owner 'Guest'
-        resource.group 'Administrators'
+        resource.owner "Guest"
+        resource.group "Administrators"
         resource.run_action(:create)
 
         expect(explicit_aces).to eq([
           ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE),
           ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_EXECUTE),
-          ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ)
+          ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ),
         ])
       end
 
       it "respects the individual read, write and execute bits of mode" do
         resource.mode 0421
-        resource.owner 'Guest'
-        resource.group 'Administrators'
+        resource.owner "Guest"
+        resource.group "Administrators"
         resource.run_action(:create)
 
         expect(explicit_aces).to eq([
           ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ),
           ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_WRITE | Security::DELETE),
-          ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE)
+          ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE),
         ])
       end
 
-      it 'warns when mode tries to set owner bits but owner is not specified' do
+      it "warns when mode tries to set owner bits but owner is not specified" do
         @warn = []
         allow(Chef::Log).to receive(:warn) { |msg| @warn << msg }
 
@@ -499,7 +497,7 @@ shared_examples_for "a securable resource without existing target" do
         expect(@warn.include?("Mode 400 includes bits for the owner, but owner is not specified")).to be_truthy
       end
 
-      it 'warns when mode tries to set group bits but group is not specified' do
+      it "warns when mode tries to set group bits but group is not specified" do
         @warn = []
         allow(Chef::Log).to receive(:warn) { |msg| @warn << msg }
 
@@ -513,11 +511,11 @@ shared_examples_for "a securable resource without existing target" do
     it "does not inherit aces if inherits is set to false" do
       # We need at least one ACE if we're creating a securable without
       # inheritance
-      resource.rights(:full_control, 'Administrators')
+      resource.rights(:full_control, "Administrators")
       resource.inherits(false)
       resource.run_action(:create)
 
-      descriptor.dacl.each do | ace |
+      descriptor.dacl.each do |ace|
         expect(ace.inherited?).to eq(false)
       end
     end
diff --git a/spec/support/shared/functional/securable_resource_with_reporting.rb b/spec/support/shared/functional/securable_resource_with_reporting.rb
index 37fc538..0bec297 100644
--- a/spec/support/shared/functional/securable_resource_with_reporting.rb
+++ b/spec/support/shared/functional/securable_resource_with_reporting.rb
@@ -1,5 +1,5 @@
 
-require 'functional/resource/base'
+require "functional/resource/base"
 
 ALL_EXPANDED_PERMISSIONS = ["generic read",
                             "generic write",
@@ -21,7 +21,6 @@ ALL_EXPANDED_PERMISSIONS = ["generic read",
                             "read attributes",
                             "write attributes"]
 
-
 shared_examples_for "a securable resource with reporting" do
 
   include_context "diff disabled"
@@ -76,9 +75,9 @@ shared_examples_for "a securable resource with reporting" do
         # TODO/bug: duplicated from the "securable resource" tests
 
         if ohai[:platform] == "aix"
-          let(:expected_user_name) { 'guest' }
+          let(:expected_user_name) { "guest" }
         else
-          let(:expected_user_name) { 'nobody' }
+          let(:expected_user_name) { "nobody" }
         end
 
         before do
@@ -96,9 +95,9 @@ shared_examples_for "a securable resource with reporting" do
 
         # TODO: duplicated from "securable resource"
         if ohai[:platform] == "aix"
-          let(:expected_user_name) { 'guest' }
+          let(:expected_user_name) { "guest" }
         else
-          let(:expected_user_name) { 'nobody' }
+          let(:expected_user_name) { "nobody" }
         end
         let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
         let(:desired_gid) { 1337 }
@@ -273,37 +272,35 @@ shared_examples_for "a securable resource with reporting" do
       # Windows reporting data should look like this (+/- ish):
       # { "owner" => "bob", "checksum" => "ffff", "access control" => { "bob" => { "permissions" => ["perm1", "perm2", ...], "flags" => [] }}}
 
-
       before do
         resource.action(:create)
       end
 
       it "has empty values for file metadata in 'current_resource'" do
-        pending "windows reporting not yet fully supported"
+        skip "windows reporting not yet fully supported"
         expect(current_resource.owner).to be_nil
         expect(current_resource.expanded_rights).to be_nil
       end
 
       context "and no security metadata is specified in new_resource" do
         before do
-          pending "windows reporting not yet fully supported"
+          skip "windows reporting not yet fully supported"
         end
 
         it "sets the metadata values on the new_resource as strings after creating" do
           resource.run_action(:create)
           # TODO: most stable way to specify?
           expect(resource.owner).to eq(etc.getpwuid(process.uid).name)
-          expect(resource.state[:expanded_rights]).to eq({ "CURRENTUSER" => { "permissions" => ALL_EXPANDED_PERMISSIONS, "flags" => [] }})
+          expect(resource.state[:expanded_rights]).to eq({ "CURRENTUSER" => { "permissions" => ALL_EXPANDED_PERMISSIONS, "flags" => [] } })
           expect(resource.state[:expanded_deny_rights]).to eq({})
           expect(resource.state[:inherits]).to be_truthy
         end
       end
 
-
-      context "and owner is specified with a string (username) in new_resource"  do
+      context "and owner is specified with a string (username) in new_resource" do
 
         # TODO/bug: duplicated from the "securable resource" tests
-        let(:expected_user_name) { 'Guest' }
+        let(:expected_user_name) { "Guest" }
 
         before do
           resource.owner(expected_user_name)
@@ -322,7 +319,7 @@ shared_examples_for "a securable resource with reporting" do
         let(:expected_user_name) { 'domain\user' }
 
         before do
-          pending "windows reporting not yet fully supported"
+          skip "windows reporting not yet fully supported"
           resource.owner(expected_user_name)
           resource.run_action(:create)
         end
@@ -336,7 +333,7 @@ shared_examples_for "a securable resource with reporting" do
 
     context "when the target file exists" do
       before do
-        pending "windows reporting not yet fully supported"
+        skip "windows reporting not yet fully supported"
         FileUtils.touch(resource.path)
         resource.action(:create)
       end
@@ -392,7 +389,6 @@ shared_examples_for "a securable resource with reporting" do
         end
       end
 
-
     end
   end
 end
diff --git a/spec/support/shared/functional/win32_service.rb b/spec/support/shared/functional/win32_service.rb
index 7dd1920..0f9072b 100644
--- a/spec/support/shared/functional/win32_service.rb
+++ b/spec/support/shared/functional/win32_service.rb
@@ -1,5 +1,5 @@
 
-require 'chef/application/windows_service_manager'
+require "chef/application/windows_service_manager"
 
 shared_context "using Win32::Service" do
   # Some helper methods.
@@ -35,10 +35,8 @@ shared_context "using Win32::Service" do
     if File.exists?(test_service_file)
       File.delete(test_service_file)
     end
-
   end
 
-
   # Definition for the test-service
 
   let(:test_service) {
@@ -46,7 +44,8 @@ shared_context "using Win32::Service" do
       :service_name => "spec-service",
       :service_display_name => "Spec Test Service",
       :service_description => "Service for testing Chef::Application::WindowsServiceManager.",
-      :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../platforms/win32/spec_service.rb'))
+      :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), "../../platforms/win32/spec_service.rb")),
+      :delayed_start => true,
     }
   }
 
diff --git a/spec/support/shared/functional/windows_script.rb b/spec/support/shared/functional/windows_script.rb
index 35b86dc..67a5330 100644
--- a/spec/support/shared/functional/windows_script.rb
+++ b/spec/support/shared/functional/windows_script.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,15 @@
 # Shared context used by both Powershell and Batch script provider
 # tests.
 
+require "chef/platform/query_helpers"
+
 shared_context Chef::Resource::WindowsScript do
   before(:all) do
-
-    ohai_reader = Ohai::System.new
-    ohai_reader.all_plugins("platform")
+    @ohai_reader = Ohai::System.new
+    @ohai_reader.all_plugins(["platform", "kernel"])
 
     new_node = Chef::Node.new
-    new_node.consume_external_attrs(ohai_reader.data,{})
+    new_node.consume_external_attrs(@ohai_reader.data, {})
 
     events = Chef::EventDispatch::Dispatcher.new
 
@@ -51,16 +52,15 @@ shared_context Chef::Resource::WindowsScript do
 
   shared_examples_for "a script resource with architecture attribute" do
     context "with the given architecture attribute value" do
-      let(:resource_architecture) { architecture }
       let(:expected_architecture) do
-        if architecture
-          expected_architecture = architecture
+        if resource_architecture
+          expected_architecture = resource_architecture
         else
-          expected_architecture = :i386
+          expected_architecture = @ohai_reader.data["kernel"]["machine"].to_sym
         end
       end
       let(:expected_architecture_output) do
-        expected_architecture == :i386 ? 'X86' : 'AMD64'
+        expected_architecture == :i386 ? "X86" : "AMD64"
       end
       let(:guard_script_suffix) do
         "guard"
@@ -77,16 +77,16 @@ shared_context Chef::Resource::WindowsScript do
 
       before(:each) do
         resource.code resource_command
-        (resource.architecture architecture) if architecture
+        (resource.architecture resource_architecture) if resource_architecture
         resource.returns(0)
       end
 
-      it "should create a process with the expected architecture" do
+      it "creates a process with the expected architecture" do
         resource.run_action(:run)
         expect(get_process_architecture).to eq(expected_architecture_output.downcase)
       end
 
-      it "should execute guards with the same architecture as the resource" do
+      it "executes guards with the same architecture as the resource" do
         resource.only_if resource_guard_command
         resource.run_action(:run)
         expect(get_process_architecture).to eq(expected_architecture_output.downcase)
@@ -94,18 +94,32 @@ shared_context Chef::Resource::WindowsScript do
         expect(get_guard_process_architecture).to eq(get_process_architecture)
       end
 
-      let (:architecture) { :x86_64 }
-      it "should execute a 64-bit guard if the guard's architecture is specified as 64-bit", :windows64_only do
-        resource.only_if resource_guard_command, :architecture => :x86_64
-        resource.run_action(:run)
-        expect(get_guard_process_architecture).to eq('amd64')
+      context "when the guard's architecture is specified as 64-bit" do
+        let (:guard_architecture) { :x86_64 }
+        it "executes a 64-bit guard", :windows64_only do
+          resource.only_if resource_guard_command, :architecture => guard_architecture
+          resource.run_action(:run)
+          expect(get_guard_process_architecture).to eq("amd64")
+        end
       end
 
-      let (:architecture) { :i386 }
-      it "should execute a 32-bit guard if the guard's architecture is specified as 32-bit" do
-        resource.only_if resource_guard_command, :architecture => :i386
-        resource.run_action(:run)
-        expect(get_guard_process_architecture).to eq('x86')
+      context "when the guard's architecture is specified as 32-bit", :not_supported_on_nano do
+        let (:guard_architecture) { :i386 }
+        it "executes a 32-bit guard" do
+          resource.only_if resource_guard_command, :architecture => guard_architecture
+          resource.run_action(:run)
+          expect(get_guard_process_architecture).to eq("x86")
+        end
+      end
+
+      context "when the guard's architecture is specified as 32-bit", :windows_nano_only do
+        let (:guard_architecture) { :i386 }
+        it "raises an error" do
+          resource.only_if resource_guard_command, :architecture => guard_architecture
+          expect { resource.run_action(:run) }.to raise_error(
+            Chef::Exceptions::Win32ArchitectureIncorrect,
+            /cannot execute script with requested architecture 'i386' on Windows Nano Server/)
+        end
       end
     end
   end
@@ -114,7 +128,28 @@ shared_context Chef::Resource::WindowsScript do
 
     describe "when the run action is invoked on Windows" do
       it "executes the script code" do
-        resource.code("@whoami > #{script_output_path}")
+        resource.code("whoami > \"#{script_output_path}\"")
+        resource.returns(0)
+        resource.run_action(:run)
+      end
+    end
+
+    context "when $env:TMP has a space" do
+      before(:each) do
+        @dir = Dir.mktmpdir("Jerry Smith")
+        @original_env = ENV.to_hash.dup
+        ENV.delete("TMP")
+        ENV["TMP"] = @dir
+      end
+
+      after(:each) do
+        FileUtils.remove_entry_secure(@dir)
+        ENV.clear
+        ENV.update(@original_env)
+      end
+
+      it "executes the script code" do
+        resource.code("whoami > \"#{script_output_path}\"")
         resource.returns(0)
         resource.run_action(:run)
       end
@@ -122,6 +157,8 @@ shared_context Chef::Resource::WindowsScript do
 
     context "when evaluating guards" do
       it "has a guard_interpreter attribute set to the short name of the resource" do
+        pending "powershell.exe always exits with 0 on nano" if Chef::Platform.windows_nano_server?
+
         expect(resource.guard_interpreter).to eq(resource.resource_name)
         resource.not_if "findstr.exe /thiscommandhasnonzeroexitstatus"
         expect(Chef::Resource).to receive(:resource_for_node).and_call_original
@@ -131,22 +168,22 @@ shared_context Chef::Resource::WindowsScript do
     end
 
     context "when the architecture attribute is not set" do
-      let(:architecture) { nil }
+      let(:resource_architecture) { nil }
       it_behaves_like "a script resource with architecture attribute"
     end
 
-    context "when the architecture attribute is :i386" do
-      let(:architecture) { :i386 }
+    context "when the architecture attribute is :i386", :not_supported_on_nano do
+      let(:resource_architecture) { :i386 }
       it_behaves_like "a script resource with architecture attribute"
     end
 
     context "when the architecture attribute is :x86_64" do
-      let(:architecture) { :x86_64 }
+      let(:resource_architecture) { :x86_64 }
       it_behaves_like "a script resource with architecture attribute"
     end
   end
 
-  def get_windows_script_output(suffix = '')
+  def get_windows_script_output(suffix = "")
     File.read("#{script_output_path}#{suffix}")
   end
 
@@ -158,7 +195,7 @@ shared_context Chef::Resource::WindowsScript do
     get_process_architecture(guard_script_suffix)
   end
 
-  def get_process_architecture(suffix = '')
+  def get_process_architecture(suffix = "")
     get_windows_script_output(suffix).strip.downcase
   end
 
diff --git a/spec/support/shared/integration/app_server_support.rb b/spec/support/shared/integration/app_server_support.rb
index a0d5e7f..c504c7c 100644
--- a/spec/support/shared/integration/app_server_support.rb
+++ b/spec/support/shared/integration/app_server_support.rb
@@ -1,7 +1,7 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh at opscode.com>)
-# Copyright:: Copyright (c) 2012, 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh at chef.io>)
+# Copyright:: Copyright 2012-2016, 2013-2015 Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'rack'
-require 'stringio'
+require "rack"
+require "stringio"
 
 module AppServerSupport
   def start_app_server(app, port)
@@ -27,12 +27,12 @@ module AppServerSupport
       Rack::Handler::WEBrick.run(app,
         :Port => 9018,
         :AccessLog => [],
-        :Logger => WEBrick::Log::new(StringIO.new, 7)
+        :Logger => WEBrick::Log::new(StringIO.new, 7),
       ) do |found_server|
         server = found_server
       end
     end
-    Timeout::timeout(5) do
+    Timeout::timeout(30) do
       until server && server.status == :Running
         sleep(0.01)
       end
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index e6942c6..29f2eef 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -1,7 +1,7 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Author:: Ho-Sheng Hsiao (<hosh at opscode.com>)
-# Copyright:: Copyright (c) 2012, 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Author:: Ho-Sheng Hsiao (<hosh at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,30 @@
 # limitations under the License.
 #
 
-require 'tmpdir'
-require 'fileutils'
-require 'chef/config'
-require 'chef/json_compat'
-require 'chef/server_api'
-require 'chef_zero/rspec'
-require 'support/shared/integration/knife_support'
-require 'support/shared/integration/app_server_support'
-require 'spec_helper'
+require "tmpdir"
+require "fileutils"
+require "chef/config"
+require "chef/json_compat"
+require "chef/server_api"
+require "support/shared/integration/knife_support"
+require "support/shared/integration/app_server_support"
+require "cheffish/rspec/chef_run_support"
+require "spec_helper"
+
+module Cheffish
+  class BasicChefClient
+    def_delegators :@run_context, :before_notifications
+  end
+end
 
 module IntegrationSupport
   include ChefZero::RSpec
 
+  def self.included(includer_class)
+    includer_class.extend(Cheffish::RSpec::ChefRunSupport)
+    includer_class.extend(ClassMethods)
+  end
+
   module ClassMethods
     include ChefZero::RSpec
 
@@ -49,10 +60,6 @@ module IntegrationSupport
     end
   end
 
-  def self.included(includer_class)
-    includer_class.extend(ClassMethods)
-  end
-
   def api
     Chef::ServerAPI.new
   end
@@ -68,8 +75,8 @@ module IntegrationSupport
   def file(relative_path, contents)
     filename = path_to(relative_path)
     dir = File.dirname(filename)
-    FileUtils.mkdir_p(dir) unless dir == '.'
-    File.open(filename, 'w') do |file|
+    FileUtils.mkdir_p(dir) unless dir == "."
+    File.open(filename, "w") do |file|
       raw = case contents
             when Hash, Array
               Chef::JSONCompat.to_json_pretty(contents)
@@ -83,7 +90,7 @@ module IntegrationSupport
   def symlink(relative_path, relative_dest)
     filename = path_to(relative_path)
     dir = File.dirname(filename)
-    FileUtils.mkdir_p(dir) unless dir == '.'
+    FileUtils.mkdir_p(dir) unless dir == "."
     dest_filename = path_to(relative_dest)
     File.symlink(dest_filename, filename)
   end
@@ -92,7 +99,7 @@ module IntegrationSupport
     File.expand_path(relative_path, (@parent_path || @repository_dir))
   end
 
-  def cb_metadata(name, version, extra_text="")
+  def cb_metadata(name, version, extra_text = "")
     "name #{name.inspect}; version #{version.inspect}#{extra_text}"
   end
 
@@ -104,9 +111,9 @@ module IntegrationSupport
   RSpec.shared_context "with a chef repo" do
     before :each do
       raise "Can only create one directory per test" if @repository_dir
-      @repository_dir = Dir.mktmpdir('chef_repo')
+      @repository_dir = Dir.mktmpdir("chef_repo")
       Chef::Config.chef_repo_path = @repository_dir
-      %w(client cookbook data_bag environment node role user).each do |object_name|
+      %w{client cookbook data_bag environment node role user}.each do |object_name|
         Chef::Config.delete("#{object_name}_path".to_sym)
       end
     end
@@ -114,14 +121,14 @@ module IntegrationSupport
     after :each do
       if @repository_dir
         begin
-          %w(client cookbook data_bag environment node role user).each do |object_name|
+          %w{client cookbook data_bag environment node role user}.each do |object_name|
             Chef::Config.delete("#{object_name}_path".to_sym)
           end
           Chef::Config.delete(:chef_repo_path)
           # TODO: "force" actually means "silence all exceptions". this
           # silences a weird permissions error on Windows that we should track
           # down, but for now there's no reason for it to blow up our CI.
-          FileUtils.remove_entry_secure(@repository_dir, force=Chef::Platform.windows?)
+          FileUtils.remove_entry_secure(@repository_dir, force = Chef::Platform.windows?)
         ensure
           @repository_dir = nil
         end
@@ -133,7 +140,7 @@ module IntegrationSupport
 
   # Versioned cookbooks
 
-  RSpec.shared_context 'with versioned cookbooks', :versioned_cookbooks => true do
+  RSpec.shared_context "with versioned cookbooks", :versioned_cookbooks => true do
     before(:each) { Chef::Config[:versioned_cookbooks] = true }
     after(:each)  { Chef::Config.delete(:versioned_cookbooks) }
   end
diff --git a/spec/support/shared/integration/knife_support.rb b/spec/support/shared/integration/knife_support.rb
index 30293be..fe9c6f7 100644
--- a/spec/support/shared/integration/knife_support.rb
+++ b/spec/support/shared/integration/knife_support.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,14 +15,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'chef/config'
-require 'chef/knife'
-require 'chef/application/knife'
-require 'logger'
-require 'chef/log'
+require "chef/config"
+require "chef/knife"
+require "chef/application/knife"
+require "logger"
+require "chef/log"
 
 module KnifeSupport
-  DEBUG = ENV['DEBUG']
+  DEBUG = ENV["DEBUG"]
   def knife(*args, &block)
     # Allow knife('role from file roles/blah.json') rather than requiring the
     # arguments to be split like knife('role', 'from', 'file', 'roles/blah.json')
@@ -37,10 +37,10 @@ module KnifeSupport
     Chef::Config[:concurrency] = 1
 
     # Work on machines where we can't access /var
-    checksums_cache_dir = Dir.mktmpdir('checksums') do |checksums_cache_dir|
+    checksums_cache_dir = Dir.mktmpdir("checksums") do |checksums_cache_dir|
       Chef::Config[:cache_options] = {
         :path => checksums_cache_dir,
-        :skip_expires => true
+        :skip_expires => true,
       }
 
       # This is Chef::Knife.run without load_commands--we'll load stuff
@@ -146,11 +146,11 @@ module KnifeSupport
     private
 
     def should_result_in(expected)
-      expected[:stdout] = '' if !expected[:stdout]
-      expected[:stderr] = '' if !expected[:stderr]
+      expected[:stdout] = "" if !expected[:stdout]
+      expected[:stderr] = "" if !expected[:stderr]
       expected[:exit_code] = 0 if !expected[:exit_code]
       # TODO make this go away
-      stderr_actual = @stderr.sub(/^WARNING: No knife configuration file found\n/, '')
+      stderr_actual = @stderr.sub(/^WARNING: No knife configuration file found\n/, "")
 
       if expected[:stderr].is_a?(Regexp)
         expect(stderr_actual).to match(expected[:stderr])
diff --git a/spec/support/shared/matchers/exit_with_code.rb b/spec/support/shared/matchers/exit_with_code.rb
index 32ebf8d..c5458ee 100644
--- a/spec/support/shared/matchers/exit_with_code.rb
+++ b/spec/support/shared/matchers/exit_with_code.rb
@@ -1,4 +1,4 @@
-require 'rspec/expectations'
+require "rspec/expectations"
 
 # Lifted from http://stackoverflow.com/questions/1480537/how-can-i-validate-exits-and-aborts-in-rspec
 RSpec::Matchers.define :exit_with_code do |exp_code|
@@ -14,7 +14,7 @@ RSpec::Matchers.define :exit_with_code do |exp_code|
 
   failure_message do |block|
     "expected block to call exit(#{exp_code}) but exit" +
-        (actual.nil? ? " not called" : "(#{actual}) was called")
+      (actual.nil? ? " not called" : "(#{actual}) was called")
   end
 
   failure_message_when_negated do |block|
diff --git a/spec/support/shared/matchers/match_environment_variable.rb b/spec/support/shared/matchers/match_environment_variable.rb
index c8c905f..393775e 100644
--- a/spec/support/shared/matchers/match_environment_variable.rb
+++ b/spec/support/shared/matchers/match_environment_variable.rb
@@ -1,6 +1,6 @@
 
-require 'rspec/expectations'
-require 'spec/support/platform_helpers'
+require "rspec/expectations"
+require "spec/support/platform_helpers"
 
 RSpec::Matchers.define :match_environment_variable do |varname|
   match do |actual|
diff --git a/spec/support/shared/shared_examples.rb b/spec/support/shared/shared_examples.rb
index b20c65f..550fa2e 100644
--- a/spec/support/shared/shared_examples.rb
+++ b/spec/support/shared/shared_examples.rb
@@ -1,7 +1,7 @@
 # For storing any examples shared between multiple tests
 
 # Any object which defines a .to_json should import this test
-shared_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+shared_examples "to_json equivalent to Chef::JSONCompat.to_json" do
 
   let(:jsonable) {
     raise "You must define the subject when including this test"
diff --git a/spec/support/shared/unit/api_error_inspector.rb b/spec/support/shared/unit/api_error_inspector.rb
index 29faa07..45bfcc6 100644
--- a/spec/support/shared/unit/api_error_inspector.rb
+++ b/spec/support/shared/unit/api_error_inspector.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
 # limitations under the License.
 #
 
-
-
 # == API Error Inspector Examples
 # These tests are work in progress. They exercise the code enough to ensure it
 # runs without error, but don't make assertions about the output. This is
@@ -34,7 +32,7 @@ shared_examples_for "an api error inspector" do
       :validation_key => "/etc/chef/testorg-validator.pem",
       :chef_server_url => "https://chef-api.example.com",
       :node_name => "testnode-name",
-      :client_key => "/etc/chef/client.pem"
+      :client_key => "/etc/chef/client.pem",
     }
     @description = Chef::Formatters::ErrorDescription.new("Error registering the node:")
     @outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR)
diff --git a/spec/support/shared/unit/api_versioning.rb b/spec/support/shared/unit/api_versioning.rb
new file mode 100644
index 0000000..b61469a
--- /dev/null
+++ b/spec/support/shared/unit/api_versioning.rb
@@ -0,0 +1,77 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/exceptions"
+
+shared_examples_for "version handling" do
+  let(:response_406) { OpenStruct.new(:code => "406") }
+  let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
+
+  before do
+    allow(rest_v1).to receive(http_verb).and_raise(exception_406)
+  end
+
+  context "when the server does not support the min or max server API version that Chef::UserV1 supports" do
+    before do
+      allow(object).to receive(:server_client_api_version_intersection).and_return([])
+    end
+
+    it "raises the original exception" do
+      expect { object.send(method) }.to raise_error(exception_406)
+    end
+  end # when the server does not support the min or max server API version that Chef::UserV1 supports
+end # version handling
+
+shared_examples_for "user and client reregister" do
+  let(:response_406) { OpenStruct.new(:code => "406") }
+  let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
+  let(:generic_exception) { Exception.new }
+  let(:min_version) { "2" }
+  let(:max_version) { "5" }
+  let(:return_hash_406) {
+    {
+      "min_version" => min_version,
+      "max_version" => max_version,
+      "request_version" => "30",
+    }
+  }
+
+  context "when V0 is not supported by the server" do
+    context "when the exception is 406 and returns x-ops-server-api-version header" do
+      before do
+        allow(rest_v0).to receive(:put).and_raise(exception_406)
+        allow(response_406).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash_406))
+      end
+
+      it "raises an error about only V0 being supported" do
+        expect(object).to receive(:reregister_only_v0_supported_error_msg).with(max_version, min_version)
+        expect { object.reregister }.to raise_error(Chef::Exceptions::OnlyApiVersion0SupportedForAction)
+      end
+
+    end
+    context "when the exception is not versioning related" do
+      before do
+        allow(rest_v0).to receive(:put).and_raise(generic_exception)
+      end
+
+      it "raises the original error" do
+        expect { object.reregister }.to raise_error(generic_exception)
+      end
+    end
+  end
+end
diff --git a/spec/support/shared/unit/execute_resource.rb b/spec/support/shared/unit/execute_resource.rb
index e969a2e..27c60ef 100644
--- a/spec/support/shared/unit/execute_resource.rb
+++ b/spec/support/shared/unit/execute_resource.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 shared_examples_for "an execute resource" do
 
@@ -111,6 +111,11 @@ shared_examples_for "an execute resource" do
     expect(@resource.creates).to eql("something")
   end
 
+  it "should accept a boolean for live streaming" do
+    @resource.live_stream true
+    expect(@resource.live_stream).to be true
+  end
+
   describe "when it has cwd, environment, group, path, return value, and a user" do
     before do
       @resource.command("grep")
diff --git a/spec/support/shared/unit/file_system_support.rb b/spec/support/shared/unit/file_system_support.rb
index 358f0c4..32bdb14 100644
--- a/spec/support/shared/unit/file_system_support.rb
+++ b/spec/support/shared/unit/file_system_support.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,32 @@
 # limitations under the License.
 #
 
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_system/memory_root'
-require 'chef/chef_fs/file_system/memory_dir'
-require 'chef/chef_fs/file_system/memory_file'
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_system/memory/memory_root"
+require "chef/chef_fs/file_system/memory/memory_dir"
+require "chef/chef_fs/file_system/memory/memory_file"
 
 module FileSystemSupport
   def memory_fs(pretty_name, value, cannot_be_in_regex = nil)
     if !value.is_a?(Hash)
       raise "memory_fs() must take a Hash"
     end
-    dir = Chef::ChefFS::FileSystem::MemoryRoot.new(pretty_name, cannot_be_in_regex)
+    dir = Chef::ChefFS::FileSystem::Memory::MemoryRoot.new(pretty_name, cannot_be_in_regex)
     value.each do |key, child|
       dir.add_child(memory_fs_value(child, key.to_s, dir))
     end
     dir
   end
 
-  def memory_fs_value(value, name = '', parent = nil)
+  def memory_fs_value(value, name = "", parent = nil)
     if value.is_a?(Hash)
-      dir = Chef::ChefFS::FileSystem::MemoryDir.new(name, parent)
+      dir = Chef::ChefFS::FileSystem::Memory::MemoryDir.new(name, parent)
       value.each do |key, child|
         dir.add_child(memory_fs_value(child, key.to_s, dir))
       end
       dir
     else
-      Chef::ChefFS::FileSystem::MemoryFile.new(name, parent, value || "#{name}\n")
+      Chef::ChefFS::FileSystem::Memory::MemoryFile.new(name, parent, value || "#{name}\n")
     end
   end
 
@@ -54,9 +54,9 @@ module FileSystemSupport
   end
 
   def no_blocking_calls_allowed
-    [ Chef::ChefFS::FileSystem::MemoryFile, Chef::ChefFS::FileSystem::MemoryDir ].each do |c|
+    [ Chef::ChefFS::FileSystem::Memory::MemoryFile, Chef::ChefFS::FileSystem::Memory::MemoryDir ].each do |c|
       [ :children, :exists?, :read ].each do |m|
-        allow_any_instance_of(c).to receive(m).and_raise("#{m.to_s} should not be called")
+        allow_any_instance_of(c).to receive(m).and_raise("#{m} should not be called")
       end
     end
   end
@@ -67,4 +67,3 @@ module FileSystemSupport
     expect(result_paths).to match_array(expected_paths)
   end
 end
-
diff --git a/spec/support/shared/unit/knife_shared.rb b/spec/support/shared/unit/knife_shared.rb
new file mode 100644
index 0000000..0af05ff
--- /dev/null
+++ b/spec/support/shared/unit/knife_shared.rb
@@ -0,0 +1,39 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+shared_examples_for "mandatory field missing" do
+  context "when field is nil" do
+    before do
+      knife.name_args = name_args
+    end
+
+    it "exits 1" do
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "prints the usage" do
+      expect(knife).to receive(:show_usage)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "prints a relevant error message" do
+      expect { knife.run }.to raise_error(SystemExit)
+      expect(stderr.string).to match /You must specify a #{fieldname}/
+    end
+  end
+end
diff --git a/spec/support/shared/unit/mock_shellout.rb b/spec/support/shared/unit/mock_shellout.rb
new file mode 100644
index 0000000..dac51be
--- /dev/null
+++ b/spec/support/shared/unit/mock_shellout.rb
@@ -0,0 +1,49 @@
+#
+# Author:: John Keiser <jkeiser at chef.io>
+# Copyright:: Copyright 2015-2016, John Keiser.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Mocks shellout results. Examples:
+#   mock_shellout_command("systemctl --all", exitstatus: 1)
+#
+class MockShellout
+  module RSpec
+    def mock_shellout_command(command, **result)
+      allow(::Mixlib::ShellOut).to receive(:new).with(command, anything).and_return MockShellout.new(result)
+    end
+  end
+
+  def initialize(**properties)
+    @properties = {
+      stdout: "",
+      stderr: "",
+      exitstatus: 0,
+    }.merge(properties)
+  end
+
+  def method_missing(name, *args)
+    @properties[name.to_sym]
+  end
+
+  def error?
+    exitstatus != 0
+  end
+
+  def error!
+    raise Mixlib::ShellOut::ShellCommandFailed, "Expected process to exit with 0, but received #{exitstatus}" if error?
+  end
+end
diff --git a/spec/support/shared/unit/platform_introspector.rb b/spec/support/shared/unit/platform_introspector.rb
index 9f42c98..2e6f74f 100644
--- a/spec/support/shared/unit/platform_introspector.rb
+++ b/spec/support/shared/unit/platform_introspector.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010, 2012 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,28 +17,28 @@
 # limitations under the License.
 #
 
-
 shared_examples_for "a platform introspector" do
   before(:each) do
     @platform_hash = {}
     %w{openbsd freebsd}.each do |x|
       @platform_hash[x] = {
         "default" => x,
-        "1.2.3" => "#{x}-1.2.3"
+        "1.2.3" => "#{x}-1.2.3",
       }
     end
-    @platform_hash["debian"] = {["5", "6"] => "debian-5/6", "default" => "debian"}
+    @platform_hash["debian"] = { ["5", "6"] => "debian-5/6", "default" => "debian" }
     @platform_hash["default"] = "default"
     # The following @platform_hash keys are used for testing version constraints
-    @platform_hash['exact_match'] = { '1.2.3' => 'exact', '>= 1.0' => 'not exact'}
-    @platform_hash['multiple_matches'] = { '~> 2.3.4' => 'matched ~> 2.3.4', '>= 2.3' => 'matched >=2.3' }
-    @platform_hash['successful_matches'] = { '< 3.0' => 'matched < 3.0', '>= 3.0' => 'matched >= 3.0' }
+    @platform_hash["exact_match"] = { "1.2.3" => "exact", ">= 1.0" => "not exact" }
+    @platform_hash["multiple_matches"] = { "~> 2.3.4" => "matched ~> 2.3.4", ">= 2.3" => "matched >=2.3" }
+    @platform_hash["invalid_cookbook_version"] = { ">= 21" => "Matches a single number" }
+    @platform_hash["successful_matches"] = { "< 3.0" => "matched < 3.0", ">= 3.0" => "matched >= 3.0" }
 
     @platform_family_hash = {
       "debian" => "debian value",
       [:rhel, :fedora] => "redhatty value",
       "suse" => "suse value",
-      :default => "default value"
+      :default => "default value",
     }
   end
 
@@ -83,22 +83,28 @@ shared_examples_for "a platform introspector" do
     expect(platform_introspector.value_for_platform(@platform_hash)).to eq("openbsd")
   end
 
-  it 'returns the exact match' do
-    node.automatic_attrs[:platform] = 'exact_match'
-    node.automatic_attrs[:platform_version] = '1.2.3'
-    expect(platform_introspector.value_for_platform(@platform_hash)).to eq('exact')
+  it "returns the exact match" do
+    node.automatic_attrs[:platform] = "exact_match"
+    node.automatic_attrs[:platform_version] = "1.2.3"
+    expect(platform_introspector.value_for_platform(@platform_hash)).to eq("exact")
   end
 
-  it 'raises RuntimeError' do
-    node.automatic_attrs[:platform] = 'multiple_matches'
-    node.automatic_attrs[:platform_version] = '2.3.4'
-    expect {platform_introspector.value_for_platform(@platform_hash)}.to raise_error(RuntimeError)
+  it "raises RuntimeError" do
+    node.automatic_attrs[:platform] = "multiple_matches"
+    node.automatic_attrs[:platform_version] = "2.3.4"
+    expect { platform_introspector.value_for_platform(@platform_hash) }.to raise_error(RuntimeError)
   end
 
-  it 'should return the value for that match' do
-    node.automatic_attrs[:platform] = 'successful_matches'
-    node.automatic_attrs[:platform_version] = '2.9'
-    expect(platform_introspector.value_for_platform(@platform_hash)).to eq('matched < 3.0')
+  it "should not require .0 to match >= 21.0" do
+    node.automatic_attrs[:platform] = "invalid_cookbook_version"
+    node.automatic_attrs[:platform_version] = "21"
+    expect(platform_introspector.value_for_platform(@platform_hash)).to eq("Matches a single number")
+  end
+
+  it "should return the value for that match" do
+    node.automatic_attrs[:platform] = "successful_matches"
+    node.automatic_attrs[:platform_version] = "2.9"
+    expect(platform_introspector.value_for_platform(@platform_hash)).to eq("matched < 3.0")
   end
 
   describe "when platform versions is an array" do
@@ -118,17 +124,17 @@ shared_examples_for "a platform introspector" do
   describe "when checking platform?" do
 
     it "returns true if the node is a provided platform and platforms are provided as symbols" do
-      node.automatic_attrs[:platform] = 'ubuntu'
+      node.automatic_attrs[:platform] = "ubuntu"
       expect(platform_introspector.platform?([:redhat, :ubuntu])).to eq(true)
     end
 
     it "returns true if the node is a provided platform and platforms are provided as strings" do
-      node.automatic_attrs[:platform] = 'ubuntu'
+      node.automatic_attrs[:platform] = "ubuntu"
       expect(platform_introspector.platform?(["redhat", "ubuntu"])).to eq(true)
     end
 
     it "returns false if the node is not of the provided platforms" do
-      node.automatic_attrs[:platform] = 'ubuntu'
+      node.automatic_attrs[:platform] = "ubuntu"
       expect(platform_introspector.platform?(:splatlinux)).to eq(false)
     end
   end
@@ -136,17 +142,17 @@ shared_examples_for "a platform introspector" do
   describe "when checking platform_family?" do
 
     it "returns true if the node is in a provided platform family and families are provided as symbols" do
-      node.automatic_attrs[:platform_family] = 'debian'
+      node.automatic_attrs[:platform_family] = "debian"
       expect(platform_introspector.platform_family?([:rhel, :debian])).to eq(true)
     end
 
     it "returns true if the node is a provided platform and platforms are provided as strings" do
-      node.automatic_attrs[:platform_family] = 'rhel'
+      node.automatic_attrs[:platform_family] = "rhel"
       expect(platform_introspector.platform_family?(["rhel", "debian"])).to eq(true)
     end
 
     it "returns false if the node is not of the provided platforms" do
-      node.automatic_attrs[:platform_family] = 'suse'
+      node.automatic_attrs[:platform_family] = "suse"
       expect(platform_introspector.platform_family?(:splatlinux)).to eq(false)
     end
 
@@ -164,21 +170,20 @@ shared_examples_for "a platform introspector" do
         "centos" => { "default" => [ :restart, :reload, :status ] },
         "redhat" => { "default" => [ :restart, :reload, :status ] },
         "fedora" => { "default" => [ :restart, :reload, :status ] },
-        "default" => { "default" => [:restart, :reload ] }}
+        "default" => { "default" => [:restart, :reload ] } }
     end
 
     it "returns the correct default for a given platform" do
       node.automatic_attrs[:platform] = "debian"
-      node.automatic_attrs[:platform_version] = '9000'
+      node.automatic_attrs[:platform_version] = "9000"
       expect(platform_introspector.value_for_platform(@platform_hash)).to eq([ :restart, :reload, :status ])
     end
 
     it "returns the correct platform+version specific value " do
       node.automatic_attrs[:platform] = "debian"
-      node.automatic_attrs[:platform_version] = '4.0'
+      node.automatic_attrs[:platform_version] = "4.0"
       expect(platform_introspector.value_for_platform(@platform_hash)).to eq([:restart, :reload])
     end
   end
 
 end
-
diff --git a/spec/support/shared/unit/provider/file.rb b/spec/support/shared/unit/provider/file.rb
index 86f32c9..5e5fc05 100644
--- a/spec/support/shared/unit/provider/file.rb
+++ b/spec/support/shared/unit/provider/file.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 if windows?
-  require 'chef/win32/file'
+  require "chef/win32/file"
 end
 
 # Filesystem stubs
@@ -37,7 +37,7 @@ end
 
 # forwards-vs-reverse slashes on windows sucks
 def windows_path
-  windows? ? normalized_path.gsub(/\\/, '/') : normalized_path
+  windows? ? normalized_path.gsub(/\\/, "/") : normalized_path
 end
 
 # this is all getting a bit stupid, CHEF-4802 cut to remove all this
@@ -117,7 +117,7 @@ class BasicTempfile < ::File
   end
 
   def self.new(basename)
-    super(make_tmp_path(basename), File::RDWR|File::CREAT|File::EXCL, 0600)
+    super(make_tmp_path(basename), File::RDWR | File::CREAT | File::EXCL, 0600)
   end
 
   def unlink
@@ -255,7 +255,7 @@ shared_examples_for Chef::Provider::File do
     context "examining file security metadata on Unix with a file that exists" do
       before do
         # fake that we're on unix even if we're on windows
-        allow(Chef::Platform).to receive(:windows?).and_return(false)
+        allow(ChefConfig).to receive(:windows?).and_return(false)
         # mock up the filesystem to behave like unix
         setup_normal_file
         stat_struct = double("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000)
@@ -331,7 +331,7 @@ shared_examples_for Chef::Provider::File do
     context "examining file security metadata on Unix with a file that does not exist" do
       before do
         # fake that we're on unix even if we're on windows
-        allow(Chef::Platform).to receive(:windows?).and_return(false)
+        allow(ChefConfig).to receive(:windows?).and_return(false)
         setup_missing_file
       end
 
@@ -380,7 +380,7 @@ shared_examples_for Chef::Provider::File do
 
     before do
       # fake that we're on unix even if we're on windows
-      allow(Chef::Platform).to receive(:windows?).and_return(false)
+      allow(ChefConfig).to receive(:windows?).and_return(false)
       # mock up the filesystem to behave like unix
       setup_normal_file
       stat_struct = double("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000)
@@ -419,12 +419,12 @@ shared_examples_for Chef::Provider::File do
       [:create, :create_if_missing, :touch].each do |action|
         context "action #{action}" do
           it "raises EnclosingDirectoryDoesNotExist" do
-            expect {provider.run_action(action)}.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+            expect { provider.run_action(action) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
           end
 
           it "does not raise an exception in why-run mode" do
             Chef::Config[:why_run] = true
-            expect {provider.run_action(action)}.not_to raise_error
+            expect { provider.run_action(action) }.not_to raise_error
             Chef::Config[:why_run] = false
           end
         end
@@ -435,19 +435,19 @@ shared_examples_for Chef::Provider::File do
       before { setup_unwritable_file }
 
       it "action delete raises InsufficientPermissions" do
-        expect {provider.run_action(:delete)}.to raise_error(Chef::Exceptions::InsufficientPermissions)
+        expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
       end
 
       it "action delete also raises InsufficientPermissions in why-run mode" do
         Chef::Config[:why_run] = true
-        expect {provider.run_action(:delete)}.to raise_error(Chef::Exceptions::InsufficientPermissions)
+        expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
         Chef::Config[:why_run] = false
       end
     end
   end
 
   context "action create" do
-    it "should create the file, update its contents and then set the acls on the file"  do
+    it "should create the file, update its contents and then set the acls on the file" do
       setup_missing_file
       expect(provider).to receive(:do_create_file)
       expect(provider).to receive(:do_contents_changes)
@@ -460,28 +460,23 @@ shared_examples_for Chef::Provider::File do
       before { setup_normal_file }
 
       let(:tempfile) {
-        t = double('Tempfile', :path => "/tmp/foo-bar-baz", :closed? => true)
+        t = double("Tempfile", :path => "/tmp/foo-bar-baz", :closed? => true)
         allow(content).to receive(:tempfile).and_return(t)
         t
       }
 
-      let(:verification) { double("Verification") }
-
       context "with user-supplied verifications" do
         it "calls #verify on each verification with tempfile path" do
-          allow(Chef::Resource::File::Verification).to receive(:new).and_return(verification)
-          provider.new_resource.verify "true"
-          provider.new_resource.verify "true"
-          expect(verification).to receive(:verify).with(tempfile.path).twice.and_return(true)
+          provider.new_resource.verify windows? ? "REM" : "true"
+          provider.new_resource.verify windows? ? "REM" : "true"
           provider.send(:do_validate_content)
         end
 
         it "raises an exception if any verification fails" do
-          provider.new_resource.verify "true"
-          provider.new_resource.verify "false"
-          allow(verification).to receive(:verify).with("true").and_return(true)
-          allow(verification).to receive(:verify).with("false").and_return(false)
-          expect{provider.send(:do_validate_content)}.to raise_error(Chef::Exceptions::ValidationFailed)
+          allow(File).to receive(:directory?).with("C:\\Windows\\system32/cmd.exe").and_return(false)
+          provider.new_resource.verify windows? ? "REM" : "true"
+          provider.new_resource.verify windows? ? "cmd.exe /c exit 1" : "false"
+          expect { provider.send(:do_validate_content) }.to raise_error(Chef::Exceptions::ValidationFailed)
         end
       end
     end
@@ -512,7 +507,7 @@ shared_examples_for Chef::Provider::File do
         before do
           setup_normal_file
           provider.load_current_resource
-          tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz")
+          tempfile = double("Tempfile", :path => "/tmp/foo-bar-baz")
           allow(content).to receive(:tempfile).and_return(tempfile)
           expect(File).to receive(:exists?).with("/tmp/foo-bar-baz").and_return(true)
           expect(tempfile).to receive(:close).once
@@ -525,34 +520,57 @@ shared_examples_for Chef::Provider::File do
           let(:diff_for_reporting) { "+++\n---\n+foo\n-bar\n" }
           before do
             allow(provider).to receive(:contents_changed?).and_return(true)
-            diff = double('Diff', :for_output => ['+++','---','+foo','-bar'],
+            diff = double("Diff", :for_output => ["+++", "---", "+foo", "-bar"],
                                   :for_reporting => diff_for_reporting )
             allow(diff).to receive(:diff).with(resource_path, tempfile_path).and_return(true)
             expect(provider).to receive(:diff).at_least(:once).and_return(diff)
-            expect(provider).to receive(:managing_content?).at_least(:once).and_return(true)
             expect(provider).to receive(:checksum).with(tempfile_path).and_return(tempfile_sha256)
-            expect(provider).to receive(:checksum).with(resource_path).and_return(tempfile_sha256)
+            allow(provider).to receive(:managing_content?).and_return(true)
+            allow(provider).to receive(:checksum).with(resource_path).and_return(tempfile_sha256)
+            expect(resource).not_to receive(:checksum).with(tempfile_sha256) # do not mutate the new resource
             expect(provider.deployment_strategy).to receive(:deploy).with(tempfile_path, normalized_path)
           end
           context "when the file was created" do
             before { expect(provider).to receive(:needs_creating?).at_least(:once).and_return(true) }
-            it "does not backup the file and does not produce a diff for reporting" do
+            it "does not backup the file" do
               expect(provider).not_to receive(:do_backup)
               provider.send(:do_contents_changes)
+            end
+
+            it "does not produce a diff for reporting" do
+              provider.send(:do_contents_changes)
               expect(resource.diff).to be_nil
             end
+
+            it "renders the final checksum correctly for reporting" do
+              provider.send(:do_contents_changes)
+              expect(resource.state_for_resource_reporter[:checksum]).to eql(tempfile_sha256)
+            end
           end
           context "when the file was not created" do
-            before { expect(provider).to receive(:needs_creating?).at_least(:once).and_return(false) }
-            it "backs up the file and produces a diff for reporting" do
+            before do
+              allow(provider).to receive(:do_backup) # stub do_backup
+              expect(provider).to receive(:needs_creating?).at_least(:once).and_return(false)
+            end
+
+            it "backs up the file" do
               expect(provider).to receive(:do_backup)
               provider.send(:do_contents_changes)
+            end
+
+            it "produces a diff for reporting" do
+              provider.send(:do_contents_changes)
               expect(resource.diff).to eq(diff_for_reporting)
             end
+
+            it "renders the final checksum correctly for reporting" do
+              provider.send(:do_contents_changes)
+              expect(resource.state_for_resource_reporter[:checksum]).to eql(tempfile_sha256)
+            end
           end
         end
 
-        it "does nothing when the contents have not changed"  do
+        it "does nothing when the contents have not changed" do
           allow(provider).to receive(:contents_changed?).and_return(false)
           expect(provider).not_to receive(:diff)
           provider.send(:do_contents_changes)
@@ -562,20 +580,20 @@ shared_examples_for Chef::Provider::File do
       it "does nothing when there is no content to deploy (tempfile returned from contents is nil)" do
         expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(nil)
         expect(provider).not_to receive(:diff)
-        expect{ provider.send(:do_contents_changes) }.not_to raise_error
+        expect { provider.send(:do_contents_changes) }.not_to raise_error
       end
 
       it "raises an exception when the content object returns a tempfile with a nil path" do
-        tempfile = double('Tempfile', :path => nil)
+        tempfile = double("Tempfile", :path => nil)
         expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
-        expect{ provider.send(:do_contents_changes) }.to raise_error
+        expect { provider.send(:do_contents_changes) }.to raise_error
       end
 
       it "raises an exception when the content object returns a tempfile that does not exist" do
-        tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz")
+        tempfile = double("Tempfile", :path => "/tmp/foo-bar-baz")
         expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
         expect(File).to receive(:exists?).with("/tmp/foo-bar-baz").and_return(false)
-        expect{ provider.send(:do_contents_changes) }.to raise_error
+        expect { provider.send(:do_contents_changes) }.to raise_error
       end
     end
 
diff --git a/spec/support/shared/unit/provider/useradd_based_user_provider.rb b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
index fc7c79e..6694aa3 100644
--- a/spec/support/shared/unit/provider/useradd_based_user_provider.rb
+++ b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010, 2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 #
 # License:: Apache License, Version 2.0
 #
@@ -46,7 +46,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     @current_resource.manage_home false
     @current_resource.force false
     @current_resource.non_unique false
-    @current_resource.supports({:manage_home => false, :non_unique => false})
+    @current_resource.supports({ :manage_home => false, :non_unique => false })
   end
 
   describe "when setting option" do
@@ -60,14 +60,14 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
 
       it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do
         allow(@new_resource).to receive(attribute).and_return("hola")
-        expect(provider.universal_options).to eql([option, 'hola'])
+        expect(provider.universal_options).to eql([option, "hola"])
       end
 
       it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do
-        allow(@new_resource).to receive(:supports).and_return({:manage_home => false,
-                                                    :non_unique => false})
+        allow(@new_resource).to receive(:supports).and_return({ :manage_home => false,
+                                                                :non_unique => false })
         allow(@new_resource).to receive(attribute).and_return("hola")
-        expect(provider.universal_options).to eql([option, 'hola'])
+        expect(provider.universal_options).to eql([option, "hola"])
       end
 
       it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
@@ -75,15 +75,15 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
         allow(@new_resource).to receive(:non_unique).and_return(false)
         allow(@new_resource).to receive(:non_unique).and_return(false)
         allow(@new_resource).to receive(attribute).and_return("hola")
-        expect(provider.universal_options).to eql([option, 'hola'])
+        expect(provider.universal_options).to eql([option, "hola"])
       end
     end
 
     it "should combine all the possible options" do
       combined_opts = []
-      supported_useradd_options.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+      supported_useradd_options.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
         allow(@new_resource).to receive(attribute).and_return("hola")
-        combined_opts << option << 'hola'
+        combined_opts << option << "hola"
       end
       expect(provider.universal_options).to eql(combined_opts)
     end
@@ -103,12 +103,12 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     describe "when the resource has a different home directory and supports home directory management" do
       before do
         allow(@new_resource).to receive(:home).and_return("/wowaweea")
-        allow(@new_resource).to receive(:supports).and_return({:manage_home => true,
-                                                   :non_unique => false})
+        allow(@new_resource).to receive(:supports).and_return({ :manage_home => true,
+                                                                :non_unique => false })
       end
 
       it "should set -m -d /homedir" do
-        expect(provider.universal_options).to eq(%w[-d /wowaweea -m])
+        expect(provider.universal_options).to eq(%w{-d /wowaweea -m})
         expect(provider.useradd_options).to eq([])
       end
     end
@@ -121,15 +121,15 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
       end
 
       it "should set -m -d /homedir" do
-        expect(provider.universal_options).to eql(%w[-d /wowaweea -m])
+        expect(provider.universal_options).to eql(%w{-d /wowaweea -m})
         expect(provider.useradd_options).to eq([])
       end
     end
 
     describe "when the resource supports non_unique ids" do
       before do
-        allow(@new_resource).to receive(:supports).and_return({:manage_home => false,
-                                                  :non_unique => true})
+        allow(@new_resource).to receive(:supports).and_return({ :manage_home => false,
+                                                                :non_unique => true })
       end
 
       it "should set -m -o" do
@@ -156,17 +156,17 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
       provider.current_resource = @current_resource
       provider.new_resource.manage_home true
       provider.new_resource.home "/Users/mud"
-      provider.new_resource.gid '23'
+      provider.new_resource.gid "23"
     end
 
     it "runs useradd with the computed command options" do
       command = ["useradd",
-                  "-c",  'Adam Jacob',
-                  "-g", '23' ]
-      command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
-      command.concat([ "-s", '/usr/bin/zsh',
-                       "-u", '1000',
-                       "-d", '/Users/mud',
+                  "-c", "Adam Jacob",
+                  "-g", "23" ]
+      command.concat(["-p", "abracadabra"]) if supported_useradd_options.key?("password")
+      command.concat([ "-s", "/usr/bin/zsh",
+                       "-u", "1000",
+                       "-d", "/Users/mud",
                        "-m",
                        "adam" ])
       expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -183,11 +183,11 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
 
       it "should not include -m or -d in the command options" do
         command = ["useradd",
-                    "-c", 'Adam Jacob',
-                    "-g", '23']
-        command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
-        command.concat([ "-s", '/usr/bin/zsh',
-                         "-u", '1000',
+                    "-c", "Adam Jacob",
+                    "-g", "23"]
+        command.concat(["-p", "abracadabra"]) if supported_useradd_options.key?("password")
+        command.concat([ "-s", "/usr/bin/zsh",
+                         "-u", "1000",
                          "-r",
                          "adam" ])
         expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -202,15 +202,15 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     before(:each) do
       provider.new_resource.manage_home true
       provider.new_resource.home "/Users/mud"
-      provider.new_resource.gid '23'
+      provider.new_resource.gid "23"
     end
 
     # CHEF-3423, -m must come before the username
     # CHEF-4305, -d must come before -m to support CentOS/RHEL 5
     it "runs usermod with the computed command options" do
       command = ["usermod",
-                  "-g", '23',
-                  "-d", '/Users/mud',
+                  "-g", "23",
+                  "-d", "/Users/mud",
                   "-m",
                   "adam" ]
       expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -220,8 +220,8 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     it "does not set the -r option to usermod" do
       @new_resource.system(true)
       command = ["usermod",
-                  "-g", '23',
-                  "-d", '/Users/mud',
+                  "-g", "23",
+                  "-d", "/Users/mud",
                   "-m",
                   "adam" ]
       expect(provider).to receive(:shell_out!).with(*command).and_return(true)
@@ -231,7 +231,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     it "CHEF-3429: does not set -m if we aren't changing the home directory" do
       expect(provider).to receive(:updating_home?).and_return(false)
       command = ["usermod",
-                  "-g", '23',
+                  "-g", "23",
                   "adam" ]
       expect(provider).to receive(:shell_out!).with(*command).and_return(true)
       provider.manage_user
@@ -247,14 +247,14 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
 
     it "should run userdel with the new resources user name and -r if manage_home is true" do
       @new_resource.supports({ :manage_home => true,
-                               :non_unique => false})
+                               :non_unique => false })
       expect(provider).to receive(:shell_out!).with("userdel", "-r", @new_resource.username).and_return(true)
       provider.remove_user
     end
 
     it "should run userdel with the new resources user name if non_unique is true" do
       @new_resource.supports({ :manage_home => false,
-                               :non_unique => true})
+                               :non_unique => true })
       expect(provider).to receive(:shell_out!).with("userdel", @new_resource.username).and_return(true)
       provider.remove_user
     end
@@ -285,7 +285,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
 
     it "should return false if status begins with P" do
       expect(provider).to receive(:shell_out!).
-        with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+        with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
         and_return(passwd_s_status)
       expect(provider.check_lock).to eql(false)
     end
@@ -293,7 +293,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     it "should return false if status begins with N" do
       @stdout = "root N"
       expect(provider).to receive(:shell_out!).
-        with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+        with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
         and_return(passwd_s_status)
       expect(provider.check_lock).to eql(false)
     end
@@ -301,26 +301,26 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     it "should return true if status begins with L" do
       @stdout = "root L"
       expect(provider).to receive(:shell_out!).
-        with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+        with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
         and_return(passwd_s_status)
       expect(provider.check_lock).to eql(true)
     end
 
     it "should raise a Chef::Exceptions::User if passwd -S fails on anything other than redhat/centos" do
-      @node.automatic_attrs[:platform] = 'ubuntu'
+      @node.automatic_attrs[:platform] = "ubuntu"
       expect(provider).to receive(:shell_out!).
-        with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+        with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
         and_return(passwd_s_status)
       expect(passwd_s_status).to receive(:exitstatus).and_return(1)
       expect { provider.check_lock }.to raise_error(Chef::Exceptions::User)
     end
 
-    ['redhat', 'centos'].each do |os|
+    ["redhat", "centos"].each do |os|
       it "should not raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is version 0.73-1" do
         @node.automatic_attrs[:platform] = os
         expect(passwd_s_status).to receive(:exitstatus).and_return(1)
         expect(provider).to receive(:shell_out!).
-          with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+          with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
           and_return(passwd_s_status)
         rpm_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-1\n", :stderr => "")
         expect(provider).to receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
@@ -331,7 +331,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
         @node.automatic_attrs[:platform] = os
         expect(passwd_s_status).to receive(:exitstatus).and_return(1)
         expect(provider).to receive(:shell_out!).
-          with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+          with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
           and_return(passwd_s_status)
         rpm_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-2\n", :stderr => "")
         expect(provider).to receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
@@ -349,7 +349,7 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
       before do
         passwd_status = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "", :stderr => "passwd: user 'chef-test' does not exist\n")
         expect(provider).to receive(:shell_out!).
-          with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+          with("passwd", "-S", @new_resource.username, { :returns => [0, 1] }).
           and_return(passwd_status)
         Chef::Config[:why_run] = true
       end
@@ -384,25 +384,25 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
        "action" => "should return false if home matches",
        "current_resource_home" => [ "/home/laurent" ],
        "new_resource_home" => [ "/home/laurent" ],
-       "expected_result" => false
+       "expected_result" => false,
      },
      {
        "action" => "should return true if home doesn't match",
        "current_resource_home" => [ "/home/laurent" ],
        "new_resource_home" => [ "/something/else" ],
-       "expected_result" => true
+       "expected_result" => true,
      },
      {
        "action" => "should return false if home only differs by trailing slash",
        "current_resource_home" => [ "/home/laurent" ],
        "new_resource_home" => [ "/home/laurent/", "/home/laurent" ],
-       "expected_result" => false
+       "expected_result" => false,
      },
      {
        "action" => "should return false if home is an equivalent path",
        "current_resource_home" => [ "/home/laurent" ],
        "new_resource_home" => [ "/home/./laurent", "/home/laurent" ],
-       "expected_result" => false
+       "expected_result" => false,
      },
     ].each do |home_check|
       it home_check["action"] do
@@ -431,4 +431,3 @@ shared_examples_for "a useradd-based user provider" do |supported_useradd_option
     end
   end
 end
-
diff --git a/spec/support/shared/unit/resource/static_provider_resolution.rb b/spec/support/shared/unit/resource/static_provider_resolution.rb
index 2bc4c70..4ae5d45 100644
--- a/spec/support/shared/unit/resource/static_provider_resolution.rb
+++ b/spec/support/shared/unit/resource/static_provider_resolution.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
 # limitations under the License.
 #
 
-
-
 #
 # This is for typical "static" provider resolution which maps resources onto
 # providers based only on the node data.  Its not really 'static' because it
@@ -25,7 +23,7 @@
 # a static mapping for the node (unlike the service resource which is
 # complicated).
 #
-def static_provider_resolution(opts={})
+def static_provider_resolution(opts = {})
   action           = opts[:action]
   provider_class   = opts[:provider]
   resource_class   = opts[:resource]
@@ -63,4 +61,3 @@ def static_provider_resolution(opts={})
     end
   end
 end
-
diff --git a/spec/support/shared/unit/script_resource.rb b/spec/support/shared/unit/script_resource.rb
index 18ee946..a80ab81 100644
--- a/spec/support/shared/unit/script_resource.rb
+++ b/spec/support/shared/unit/script_resource.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 shared_examples_for "a script resource" do
 
@@ -49,18 +49,18 @@ shared_examples_for "a script resource" do
   end
 
   it "should raise an exception if users set command on the resource", :chef_gte_13_only do
-    expect { script_resource.command('foo') }.to raise_error(Chef::Exceptions::Script)
+    expect { script_resource.command("foo") }.to raise_error(Chef::Exceptions::Script)
   end
 
   it "should not raise an exception if users set command on the resource", :chef_lt_13_only do
-    expect { script_resource.command('foo') }.not_to raise_error
+    expect { script_resource.command("foo") }.not_to raise_error
   end
 
   describe "when executing guards" do
     let(:resource) {
       resource = script_resource
       resource.run_context = run_context
-      resource.code 'echo hi'
+      resource.code "echo hi"
       resource
     }
     let(:node) {
@@ -74,7 +74,7 @@ shared_examples_for "a script resource" do
 
     it "inherits exactly the :cwd, :environment, :group, :path, :user, and :umask attributes from a parent resource class" do
       inherited_difference = Chef::Resource::Script.guard_inherited_attributes -
-        [:cwd, :environment, :group, :path, :user, :umask ]
+                             [:cwd, :environment, :group, :path, :user, :umask ]
 
       expect(inherited_difference).to eq([])
     end
@@ -83,7 +83,7 @@ shared_examples_for "a script resource" do
       expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate_block)
       expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).not_to receive(:evaluate_action)
       expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:evaluate).and_return(true)
-      resource.only_if 'echo hi'
+      resource.only_if "echo hi"
       expect(resource.should_skip?(:run)).to eq(nil)
     end
 
@@ -91,7 +91,7 @@ shared_examples_for "a script resource" do
       expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).not_to receive(:evaluate)
       expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
       resource.guard_interpreter :script
-      resource.only_if 'echo hi'
+      resource.only_if "echo hi"
       expect(resource.should_skip?(:run)).to eq(nil)
     end
   end
diff --git a/spec/support/shared/unit/user_and_client_shared.rb b/spec/support/shared/unit/user_and_client_shared.rb
new file mode 100644
index 0000000..e386294
--- /dev/null
+++ b/spec/support/shared/unit/user_and_client_shared.rb
@@ -0,0 +1,114 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+shared_examples_for "user or client create" do
+
+  context "when server API V1 is valid on the Chef Server receiving the request" do
+
+    it "creates a new object via the API" do
+      expect(rest_v1).to receive(:post).with(url, payload).and_return({})
+      object.create
+    end
+
+    it "creates a new object via the API with a public_key when it exists" do
+      object.public_key "some_public_key"
+      expect(rest_v1).to receive(:post).with(url, payload.merge({ :public_key => "some_public_key" })).and_return({})
+      object.create
+    end
+
+    context "raise error when create_key and public_key are both set" do
+
+      before do
+        object.public_key "key"
+        object.create_key true
+      end
+
+      it "rasies the proper error" do
+        expect { object.create }.to raise_error(error)
+      end
+    end
+
+    context "when create_key == true" do
+      before do
+        object.create_key true
+      end
+
+      it "creates a new object via the API with create_key" do
+        expect(rest_v1).to receive(:post).with(url, payload.merge({ :create_key => true })).and_return({})
+        object.create
+      end
+    end
+
+    context "when chef_key is returned by the server" do
+      let(:chef_key) {
+        {
+          "chef_key" => {
+            "public_key" => "some_public_key"
+          }
+        }
+      }
+
+      it "puts the public key into the objectr returned by create" do
+        expect(rest_v1).to receive(:post).with(url, payload).and_return(payload.merge(chef_key))
+        new_object = object.create
+        expect(new_object.public_key).to eq("some_public_key")
+      end
+
+      context "when private_key is returned in chef_key" do
+        let(:chef_key) {
+          {
+            "chef_key" => {
+              "public_key" => "some_public_key",
+              "private_key" => "some_private_key",
+            }
+          }
+        }
+
+        it "puts the private key into the object returned by create" do
+          expect(rest_v1).to receive(:post).with(url, payload).and_return(payload.merge(chef_key))
+          new_object = object.create
+          expect(new_object.private_key).to eq("some_private_key")
+        end
+      end
+    end # when chef_key is returned by the server
+
+  end # when server API V1 is valid on the Chef Server receiving the request
+
+  context "when server API V1 is not valid on the Chef Server receiving the request" do
+
+    context "when the server supports API V0" do
+      before do
+        allow(object).to receive(:server_client_api_version_intersection).and_return([0])
+        allow(rest_v1).to receive(:post).and_raise(exception_406)
+      end
+
+      it "creates a new object via the API" do
+        expect(rest_v0).to receive(:post).with(url, payload).and_return({})
+        object.create
+      end
+
+      it "creates a new object via the API with a public_key when it exists" do
+        object.public_key "some_public_key"
+        expect(rest_v0).to receive(:post).with(url, payload.merge({ :public_key => "some_public_key" })).and_return({})
+        object.create
+      end
+
+    end # when the server supports API V0
+  end # when server API V1 is not valid on the Chef Server receiving the request
+
+end # user or client create
diff --git a/spec/support/shared/unit/windows_script_resource.rb b/spec/support/shared/unit/windows_script_resource.rb
index a2fc884..2dc0229 100644
--- a/spec/support/shared/unit/windows_script_resource.rb
+++ b/spec/support/shared/unit/windows_script_resource.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'support/shared/unit/execute_resource'
-require 'support/shared/unit/script_resource'
+require "support/shared/unit/execute_resource"
+require "support/shared/unit/script_resource"
 
 shared_examples_for "a Windows script resource" do
   before(:each) do
@@ -51,7 +51,7 @@ shared_examples_for "a Windows script resource" do
     it "should use a resource to evaluate the guard when guard_interpreter is not specified" do
       expect_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
       expect_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).not_to receive(:evaluate)
-      @resource.only_if 'echo hi'
+      @resource.only_if "echo hi"
       expect(@resource.should_skip?(:run)).to eq(nil)
     end
 
@@ -78,4 +78,3 @@ shared_examples_for "a Windows script resource" do
   end
 
 end
-
diff --git a/spec/tiny_server.rb b/spec/tiny_server.rb
index a2cfe16..a3711e4 100644
--- a/spec/tiny_server.rb
+++ b/spec/tiny_server.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'rubygems'
-require 'webrick'
-require 'webrick/https'
-require 'rack'
+require "rubygems"
+require "webrick"
+require "webrick/https"
+require "rack"
 #require 'thin'
-require 'singleton'
-require 'open-uri'
-require 'chef/config'
+require "singleton"
+require "open-uri"
+require "chef/config"
 
 module TinyServer
 
@@ -31,7 +31,7 @@ module TinyServer
 
     attr_writer :app
 
-    def self.setup(options=nil, &block)
+    def self.setup(options = nil, &block)
       tiny_app = new(options)
       app_code = Rack::Builder.new(&block).to_app
       tiny_app.app = app_code
@@ -48,15 +48,15 @@ module TinyServer
     # 5 == debug, 3 == warning
     LOGGER = WEBrick::Log.new(STDOUT, 3)
     DEFAULT_OPTIONS = {
-      :server => 'webrick',
+      :server => "webrick",
       :Port => 9000,
-      :Host => 'localhost',
+      :Host => "localhost",
       :environment => :none,
       :Logger => LOGGER,
       :AccessLog => [] # Remove this option to enable the access log when debugging.
     }
 
-    def initialize(options=nil)
+    def initialize(options = nil)
       @options = options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS
       @creator = caller.first
     end
@@ -66,9 +66,11 @@ module TinyServer
         @server = Server.setup(@options) do
           run API.instance
         end
+        @old_handler = trap(:INT, "EXIT")
         @server.start
       end
       block_until_started
+      trap(:INT, @old_handler)
     end
 
     def url
@@ -92,9 +94,11 @@ module TinyServer
       true
     rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET => e
       sleep 0.1
+      true
       # If the host has ":::1 localhost" in its hosts file and if IPv6
       # is not enabled we can get NetworkUnreachable exception...
-    rescue Errno::ENETUNREACH => e
+    rescue Errno::ENETUNREACH, Net::ReadTimeout, IO::EAGAINWaitReadable,
+        Errno::EHOSTUNREACH => e
       sleep 0.1
       false
     end
@@ -124,22 +128,22 @@ module TinyServer
     end
 
     def clear
-      @routes = {GET => [], PUT => [], POST => [], DELETE => []}
+      @routes = { GET => [], PUT => [], POST => [], DELETE => [] }
     end
 
-    def get(path, response_code, data=nil, headers=nil, &block)
+    def get(path, response_code, data = nil, headers = nil, &block)
       @routes[GET] << Route.new(path, Response.new(response_code, data, headers, &block))
     end
 
-    def put(path, response_code, data=nil, headers=nil, &block)
+    def put(path, response_code, data = nil, headers = nil, &block)
       @routes[PUT] << Route.new(path, Response.new(response_code, data, headers, &block))
     end
 
-    def post(path, response_code, data=nil, headers=nil, &block)
+    def post(path, response_code, data = nil, headers = nil, &block)
       @routes[POST] << Route.new(path, Response.new(response_code, data, headers, &block))
     end
 
-    def delete(path, response_code, data=nil, headers=nil, &block)
+    def delete(path, response_code, data = nil, headers = nil, &block)
       @routes[DELETE] << Route.new(path, Response.new(response_code, data, headers, &block))
     end
 
@@ -147,11 +151,11 @@ module TinyServer
       if response = response_for_request(env)
         response.call
       else
-        debug_info = {:message => "no data matches the request for #{env['REQUEST_URI']}",
-                      :available_routes => @routes, :request => env}
+        debug_info = { :message => "no data matches the request for #{env['REQUEST_URI']}",
+                       :available_routes => @routes, :request => env }
         # Uncomment me for glorious debugging
         # pp :not_found => debug_info
-        [404, {'Content-Type' => 'application/json'}, [ Chef::JSONCompat.to_json(debug_info) ]]
+        [404, { "Content-Type" => "application/json" }, [ Chef::JSONCompat.to_json(debug_info) ]]
       end
     end
 
@@ -181,9 +185,9 @@ module TinyServer
   end
 
   class Response
-    HEADERS = {'Content-Type' => 'application/json'}
+    HEADERS = { "Content-Type" => "application/json" }
 
-    def initialize(response_code=200, data=nil, headers=nil, &block)
+    def initialize(response_code = 200, data = nil, headers = nil, &block)
       @response_code, @data = response_code, data
       @response_headers = headers ? HEADERS.merge(headers) : HEADERS
       @block = block_given? ? block : nil
@@ -195,7 +199,7 @@ module TinyServer
     end
 
     def to_s
-      "#{@response_code} => #{(@data|| @block)}"
+      "#{@response_code} => #{(@data || @block)}"
     end
 
   end
diff --git a/spec/unit/api_client/registration_spec.rb b/spec/unit/api_client/registration_spec.rb
index d6230af..750223a 100644
--- a/spec/unit/api_client/registration_spec.rb
+++ b/spec/unit/api_client/registration_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
 
-require 'chef/api_client/registration'
+require "chef/api_client/registration"
 
 describe Chef::ApiClient::Registration do
 
@@ -32,10 +32,10 @@ describe Chef::ApiClient::Registration do
   subject(:registration) { Chef::ApiClient::Registration.new(client_name, key_location) }
 
   let(:private_key_data) do
-    File.open(Chef::Config[:validation_key], "r") {|f| f.read.chomp }
+    File.open(Chef::Config[:validation_key], "r") { |f| f.read.chomp }
   end
 
-  let(:http_mock) { double("Chef::REST mock") }
+  let(:http_mock) { double("Chef::ServerAPI mock") }
 
   let(:expected_post_data) do
     { :name => client_name, :admin => false, :public_key => generated_public_key.to_pem }
@@ -46,8 +46,10 @@ describe Chef::ApiClient::Registration do
   end
 
   let(:server_v10_response) do
-    {"uri" => "https://chef.local/clients/#{client_name}",
-     "private_key" => "--begin rsa key etc--"}
+    {
+      "uri" => "https://chef.local/clients/#{client_name}",
+      "private_key" => "--begin rsa key etc--",
+    }
   end
 
   # Server v11 includes `json_class` on all replies
@@ -61,30 +63,31 @@ describe Chef::ApiClient::Registration do
   let(:response_409) { Net::HTTPConflict.new("1.1", "409", "Conflict") }
   let(:exception_409) { Net::HTTPServerException.new("409 conflict", response_409) }
 
-  let(:generated_private_key_pem) { IO.read(File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)) }
+  let(:generated_private_key_pem) { IO.read(File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)) }
   let(:generated_private_key) { OpenSSL::PKey::RSA.new(generated_private_key_pem) }
   let(:generated_public_key) { generated_private_key.public_key }
 
-
   let(:create_with_pkey_response) do
     {
       "uri" => "",
-      "public_key" => generated_public_key.to_pem
+      "chef_key" => {
+        "public_key" => generated_public_key.to_pem
+      },
     }
   end
 
   let(:update_with_pkey_response) do
-    {"name"=>client_name,
-     "admin"=>false,
-     "public_key"=> generated_public_key,
-     "validator"=>false,
-     "private_key"=>false,
-     "clientname"=>client_name}
+    { "name" => client_name,
+      "admin" => false,
+      "public_key" => generated_public_key,
+      "validator" => false,
+      "private_key" => false,
+      "clientname" => client_name }
   end
 
   before do
     Chef::Config[:validation_client_name] = "test-validator"
-    Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+    Chef::Config[:validation_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
     allow(OpenSSL::PKey::RSA).to receive(:generate).with(2048).and_return(generated_private_key)
   end
 
@@ -93,9 +96,10 @@ describe Chef::ApiClient::Registration do
   end
 
   it "has an HTTP client configured with validator credentials" do
-    expect(registration.http_api).to be_a_kind_of(Chef::REST)
-    expect(registration.http_api.client_name).to eq("test-validator")
-    expect(registration.http_api.signing_key).to eq(private_key_data)
+    expect(registration.http_api).to be_a_kind_of(Chef::ServerAPI)
+    expect(registration.http_api.options[:client_name]).to eq("test-validator")
+    auth = registration.http_api.middlewares.select { |klass| klass.kind_of? Chef::HTTP::Authenticator }.first
+    expect(auth.client_name).to eq("test-validator")
   end
 
   describe "when creating/updating the client on the server" do
@@ -107,8 +111,8 @@ describe Chef::ApiClient::Registration do
       expect(http_mock).to receive(:post).
         with("clients", expected_post_data).
         and_return(create_with_pkey_response)
-      expect(registration.create_or_update).to eq(create_with_pkey_response)
-      expect(registration.private_key).to eq(generated_private_key_pem)
+      expect(registration.run.public_key).to eq(create_with_pkey_response["chef_key"]["public_key"])
+      expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
     end
 
     it "puts a locally generated public key to the server to update a client" do
@@ -118,8 +122,8 @@ describe Chef::ApiClient::Registration do
       expect(http_mock).to receive(:put).
         with("clients/#{client_name}", expected_put_data).
         and_return(update_with_pkey_response)
-      expect(registration.create_or_update).to eq(update_with_pkey_response)
-      expect(registration.private_key).to eq(generated_private_key_pem)
+      expect(registration.run.public_key).to eq(update_with_pkey_response["public_key"].to_pem)
+      expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
     end
 
     it "writes the generated private key to disk" do
@@ -127,7 +131,7 @@ describe Chef::ApiClient::Registration do
         with("clients", expected_post_data).
         and_return(create_with_pkey_response)
       registration.run
-      expect(IO.read(key_location)).to eq(generated_private_key_pem)
+      expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
     end
 
     context "and the client already exists on a Chef 11 server" do
@@ -136,8 +140,8 @@ describe Chef::ApiClient::Registration do
         expect(http_mock).to receive(:put).
           with("clients/#{client_name}", expected_put_data).
           and_return(update_with_pkey_response)
-        expect(registration.create_or_update).to eq(update_with_pkey_response)
-        expect(registration.private_key).to eq(generated_private_key_pem)
+        expect(registration.run.public_key).to eq(update_with_pkey_response["public_key"].to_pem)
+        expect(OpenSSL::PKey::RSA.new(registration.private_key).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
       end
     end
 
@@ -160,7 +164,7 @@ describe Chef::ApiClient::Registration do
         expect(http_mock).to receive(:post).
           with("clients", expected_post_data).
           and_return(server_v10_response)
-        expect(registration.create_or_update).to eq(server_v10_response)
+        expect(registration.run.private_key).to eq(server_v10_response["private_key"])
         expect(registration.private_key).to eq("--begin rsa key etc--")
       end
 
@@ -170,7 +174,7 @@ describe Chef::ApiClient::Registration do
           expect(http_mock).to receive(:put).
             with("clients/#{client_name}", expected_put_data).
             and_return(server_v11_response)
-          expect(registration.create_or_update).to eq(server_v11_response)
+          expect(registration.run).to eq(server_v11_response)
           expect(registration.private_key).to eq("--begin rsa key etc--")
         end
       end
@@ -182,7 +186,7 @@ describe Chef::ApiClient::Registration do
           expect(http_mock).to receive(:put).
             with("clients/#{client_name}", expected_put_data).
             and_return(server_v10_response)
-          expect(registration.create_or_update).to eq(server_v10_response)
+          expect(registration.run.private_key).to eq(server_v10_response["private_key"])
           expect(registration.private_key).to eq("--begin rsa key etc--")
         end
       end
@@ -191,7 +195,7 @@ describe Chef::ApiClient::Registration do
 
   describe "when writing the private key to disk" do
     before do
-      allow(registration).to receive(:private_key).and_return('--begin rsa key etc--')
+      allow(registration).to receive(:private_key).and_return("--begin rsa key etc--")
     end
 
     # Permission read via File.stat is busted on windows, though creating the
@@ -210,9 +214,9 @@ describe Chef::ApiClient::Registration do
       expect(IO.read(key_location)).to eq("--begin rsa key etc--")
     end
 
-    context 'when the client key location is a symlink' do
-      it 'does not follow the symlink', :unix_only do
-        expected_flags = (File::CREAT|File::TRUNC|File::RDWR)
+    context "when the client key location is a symlink" do
+      it "does not follow the symlink", :unix_only do
+        expected_flags = (File::CREAT | File::TRUNC | File::RDWR)
 
         if defined?(File::NOFOLLOW)
           expected_flags |= File::NOFOLLOW
@@ -221,13 +225,13 @@ describe Chef::ApiClient::Registration do
         expect(registration.file_flags).to eq(expected_flags)
       end
 
-      context 'with follow_client_key_symlink set to true' do
+      context "with follow_client_key_symlink set to true" do
         before do
           Chef::Config[:follow_client_key_symlink] = true
         end
 
-        it 'follows the symlink', :unix_only do
-          expect(registration.file_flags).to eq(File::CREAT|File::TRUNC|File::RDWR)
+        it "follows the symlink", :unix_only do
+          expect(registration.file_flags).to eq(File::CREAT | File::TRUNC | File::RDWR)
         end
       end
     end
@@ -242,7 +246,7 @@ describe Chef::ApiClient::Registration do
     it "creates the client on the server and writes the key" do
       expect(http_mock).to receive(:post).ordered.and_return(server_v10_response)
       registration.run
-      expect(IO.read(key_location)).to eq(generated_private_key_pem)
+      expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
     end
 
     it "retries up to 5 times" do
@@ -257,7 +261,7 @@ describe Chef::ApiClient::Registration do
 
       expect(http_mock).to receive(:post).ordered.and_return(server_v10_response)
       registration.run
-      expect(IO.read(key_location)).to eq(generated_private_key_pem)
+      expect(OpenSSL::PKey::RSA.new(IO.read(key_location)).to_s).to eq(OpenSSL::PKey::RSA.new(generated_private_key_pem).to_s)
     end
 
     it "gives up retrying after the max attempts" do
@@ -266,7 +270,7 @@ describe Chef::ApiClient::Registration do
 
       expect(http_mock).to receive(:post).exactly(6).times.and_raise(exception_500)
 
-      expect {registration.run}.to raise_error(Net::HTTPFatalError)
+      expect { registration.run }.to raise_error(Net::HTTPFatalError)
     end
 
   end
diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb
index 7668e31..a8ac4f7 100644
--- a/spec/unit/api_client_spec.rb
+++ b/spec/unit/api_client_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/api_client'
-require 'tempfile'
+require "chef/api_client"
+require "tempfile"
 
+# DEPRECATION NOTE
+#
+# This code will be removed in Chef 13 in favor of the code in Chef::ApiClientV1,
+# which will be moved to this namespace. New development should occur in
+# Chef::ApiClientV1 until the time before Chef 13.
 describe Chef::ApiClient do
   before(:each) do
     @client = Chef::ApiClient.new
@@ -77,7 +82,6 @@ describe Chef::ApiClient do
     expect { @client.public_key Hash.new }.to raise_error(ArgumentError)
   end
 
-
   it "has a private key attribute" do
     @client.private_key("super private")
     expect(@client.private_key).to eq("super private")
@@ -123,10 +127,6 @@ describe Chef::ApiClient do
     it "does not include the private key if not present" do
       expect(@json).not_to include("private_key")
     end
-
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
-      let(:jsonable) { @client }
-    end
   end
 
   describe "when deserializing from JSON (string) using ApiClient#from_json" do
@@ -175,12 +175,12 @@ describe Chef::ApiClient do
         "private_key" => "monkeypants",
         "admin" => true,
         "validator" => true,
-        "json_class" => "Chef::ApiClient"
+        "json_class" => "Chef::ApiClient",
       }
     end
 
     let(:client) do
-      Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(client_hash))
+      Chef::ApiClient.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(client_hash)))
     end
 
     it "should deserialize to a Chef::ApiClient object" do
@@ -220,12 +220,12 @@ describe Chef::ApiClient do
       "private_key" => "monkeypants",
       "admin" => true,
       "validator" => true,
-      "json_class" => "Chef::ApiClient"
+      "json_class" => "Chef::ApiClient",
       }
-      @http_client = double("Chef::REST mock")
-      allow(Chef::REST).to receive(:new).and_return(@http_client)
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
       expect(@http_client).to receive(:get).with("clients/black").and_return(client)
-      @client = Chef::ApiClient.load(client['name'])
+      @client = Chef::ApiClient.load(client["name"])
     end
 
     it "should deserialize to a Chef::ApiClient object" do
@@ -257,7 +257,7 @@ describe Chef::ApiClient do
   describe "with correctly configured API credentials" do
     before do
       Chef::Config[:node_name] = "silent-bob"
-      Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
+      Chef::Config[:client_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
     end
 
     after do
@@ -266,21 +266,15 @@ describe Chef::ApiClient do
     end
 
     let :private_key_data do
-      File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp }
+      File.open(Chef::Config[:client_key], "r") { |f| f.read.chomp }
     end
 
-    it "has an HTTP client configured with default credentials" do
-      expect(@client.http_api).to be_a_kind_of(Chef::REST)
-      expect(@client.http_api.client_name).to eq("silent-bob")
-      expect(@client.http_api.signing_key.to_s).to eq(private_key_data)
-    end
   end
 
-
   describe "when requesting a new key" do
     before do
-      @http_client = double("Chef::REST mock")
-      allow(Chef::REST).to receive(:new).and_return(@http_client)
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
     end
 
     context "and the client does not exist on the server" do
@@ -303,7 +297,6 @@ describe Chef::ApiClient do
         expect(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
       end
 
-
       context "and the client exists on a Chef 11-like server" do
         before do
           @api_client_with_key = Chef::ApiClient.new
@@ -326,7 +319,7 @@ describe Chef::ApiClient do
 
       context "and the client exists on a Chef 10-like server" do
         before do
-          @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"}
+          @api_client_with_key = { "name" => "lost-my-key", "private_key" => "the new private key" }
           expect(@http_client).to receive(:put).
             with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true).
             and_return(@api_client_with_key)
diff --git a/spec/unit/api_client_v1_spec.rb b/spec/unit/api_client_v1_spec.rb
new file mode 100644
index 0000000..8c90d5a
--- /dev/null
+++ b/spec/unit/api_client_v1_spec.rb
@@ -0,0 +1,455 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+require "chef/api_client_v1"
+require "tempfile"
+
+describe Chef::ApiClientV1 do
+  before(:each) do
+    @client = Chef::ApiClientV1.new
+  end
+
+  it "has a name attribute" do
+    @client.name("ops_master")
+    expect(@client.name).to eq("ops_master")
+  end
+
+  it "does not allow spaces in the name" do
+    expect { @client.name "ops master" }.to raise_error(ArgumentError)
+  end
+
+  it "only allows string values for the name" do
+    expect { @client.name Hash.new }.to raise_error(ArgumentError)
+  end
+
+  it "has an admin flag attribute" do
+    @client.admin(true)
+    expect(@client.admin).to be_truthy
+  end
+
+  it "defaults to non-admin" do
+    expect(@client.admin).to be_falsey
+  end
+
+  it "allows only boolean values for the admin flag" do
+    expect { @client.admin(false) }.not_to raise_error
+    expect { @client.admin(Hash.new) }.to raise_error(ArgumentError)
+  end
+
+  it "has an create_key flag attribute" do
+    @client.create_key(true)
+    expect(@client.create_key).to be_truthy
+  end
+
+  it "create_key defaults to false" do
+    expect(@client.create_key).to be_falsey
+  end
+
+  it "allows only boolean values for the create_key flag" do
+    expect { @client.create_key(false) }.not_to raise_error
+    expect { @client.create_key(Hash.new) }.to raise_error(ArgumentError)
+  end
+
+  it "has a 'validator' flag attribute" do
+    @client.validator(true)
+    expect(@client.validator).to be_truthy
+  end
+
+  it "defaults to non-validator" do
+    expect(@client.validator).to be_falsey
+  end
+
+  it "allows only boolean values for the 'validator' flag" do
+    expect { @client.validator(false) }.not_to raise_error
+    expect { @client.validator(Hash.new) }.to raise_error(ArgumentError)
+  end
+
+  it "has a public key attribute" do
+    @client.public_key("super public")
+    expect(@client.public_key).to eq("super public")
+  end
+
+  it "accepts only String values for the public key" do
+    expect { @client.public_key "" }.not_to raise_error
+    expect { @client.public_key Hash.new }.to raise_error(ArgumentError)
+  end
+
+  it "has a private key attribute" do
+    @client.private_key("super private")
+    expect(@client.private_key).to eq("super private")
+  end
+
+  it "accepts only String values for the private key" do
+    expect { @client.private_key "" }.not_to raise_error
+    expect { @client.private_key Hash.new }.to raise_error(ArgumentError)
+  end
+
+  describe "when serializing to JSON" do
+    before(:each) do
+      @client.name("black")
+      @client.public_key("crowes")
+      @json = @client.to_json
+    end
+
+    it "serializes as a JSON object" do
+      expect(@json).to match(/^\{.+\}$/)
+    end
+
+    it "includes the name value" do
+      expect(@json).to include(%q{"name":"black"})
+    end
+
+    it "includes the public key value" do
+      expect(@json).to include(%{"public_key":"crowes"})
+    end
+
+    it "includes the 'admin' flag" do
+      expect(@json).to include(%q{"admin":false})
+    end
+
+    it "includes the 'validator' flag" do
+      expect(@json).to include(%q{"validator":false})
+    end
+
+    it "includes the 'create_key' flag when present" do
+      @client.create_key(true)
+      @json = @client.to_json
+      expect(@json).to include(%q{"create_key":true})
+    end
+
+    it "includes the private key when present" do
+      @client.private_key("monkeypants")
+      expect(@client.to_json).to include(%q{"private_key":"monkeypants"})
+    end
+
+    it "does not include the private key if not present" do
+      expect(@json).not_to include("private_key")
+    end
+
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
+      let(:jsonable) { @client }
+    end
+  end
+
+  describe "when deserializing from JSON (string) using ApiClient#from_json" do
+    let(:client_string) do
+      "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}"
+    end
+
+    let(:client) do
+      Chef::ApiClientV1.from_json(client_string)
+    end
+
+    it "does not require a 'json_class' string" do
+      expect(Chef::JSONCompat.parse(client_string)["json_class"]).to eq(nil)
+    end
+
+    it "should deserialize to a Chef::ApiClientV1 object" do
+      expect(client).to be_a_kind_of(Chef::ApiClientV1)
+    end
+
+    it "preserves the name" do
+      expect(client.name).to eq("black")
+    end
+
+    it "preserves the public key" do
+      expect(client.public_key).to eq("crowes")
+    end
+
+    it "preserves the admin status" do
+      expect(client.admin).to be_truthy
+    end
+
+    it "preserves the create_key status" do
+      expect(client.create_key).to be_truthy
+    end
+
+    it "preserves the 'validator' status" do
+      expect(client.validator).to be_truthy
+    end
+
+    it "includes the private key if present" do
+      expect(client.private_key).to eq("monkeypants")
+    end
+  end
+
+  describe "when deserializing from JSON (hash) using ApiClientV1#from_json" do
+    let(:client_hash) do
+      {
+        "name" => "black",
+        "public_key" => "crowes",
+        "private_key" => "monkeypants",
+        "admin" => true,
+        "validator" => true,
+        "create_key" => true,
+      }
+    end
+
+    let(:client) do
+      Chef::ApiClientV1.from_json(Chef::JSONCompat.to_json(client_hash))
+    end
+
+    it "should deserialize to a Chef::ApiClientV1 object" do
+      expect(client).to be_a_kind_of(Chef::ApiClientV1)
+    end
+
+    it "preserves the name" do
+      expect(client.name).to eq("black")
+    end
+
+    it "preserves the public key" do
+      expect(client.public_key).to eq("crowes")
+    end
+
+    it "preserves the admin status" do
+      expect(client.admin).to be_truthy
+    end
+
+    it "preserves the create_key status" do
+      expect(client.create_key).to be_truthy
+    end
+
+    it "preserves the 'validator' status" do
+      expect(client.validator).to be_truthy
+    end
+
+    it "includes the private key if present" do
+      expect(client.private_key).to eq("monkeypants")
+    end
+  end
+
+  describe "when loading from JSON" do
+    before do
+    end
+
+    before(:each) do
+      client = {
+        "name" => "black",
+        "clientname" => "black",
+        "public_key" => "crowes",
+        "private_key" => "monkeypants",
+        "admin" => true,
+        "create_key" => true,
+        "validator" => true,
+      }
+
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+      expect(@http_client).to receive(:get).with("clients/black").and_return(client)
+      @client = Chef::ApiClientV1.load(client["name"])
+    end
+
+    it "should deserialize to a Chef::ApiClientV1 object" do
+      expect(@client).to be_a_kind_of(Chef::ApiClientV1)
+    end
+
+    it "preserves the name" do
+      expect(@client.name).to eq("black")
+    end
+
+    it "preserves the public key" do
+      expect(@client.public_key).to eq("crowes")
+    end
+
+    it "preserves the admin status" do
+      expect(@client.admin).to be_a_kind_of(TrueClass)
+    end
+
+    it "preserves the create_key status" do
+      expect(@client.create_key).to be_a_kind_of(TrueClass)
+    end
+
+    it "preserves the 'validator' status" do
+      expect(@client.validator).to be_a_kind_of(TrueClass)
+    end
+
+    it "includes the private key if present" do
+      expect(@client.private_key).to eq("monkeypants")
+    end
+
+  end
+
+  describe "with correctly configured API credentials" do
+    before do
+      Chef::Config[:node_name] = "silent-bob"
+      Chef::Config[:client_key] = File.expand_path("ssl/private_key.pem", CHEF_SPEC_DATA)
+    end
+
+    after do
+      Chef::Config[:node_name] = nil
+      Chef::Config[:client_key] = nil
+    end
+
+    let :private_key_data do
+      File.open(Chef::Config[:client_key], "r") { |f| f.read.chomp }
+    end
+
+  end
+
+  describe "when requesting a new key" do
+    before do
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+    end
+
+    context "and the client does not exist on the server" do
+      before do
+        @a_404_response = Net::HTTPNotFound.new("404 not found and such", nil, nil)
+        @a_404_exception = Net::HTTPServerException.new("404 not found exception", @a_404_response)
+
+        expect(@http_client).to receive(:get).with("clients/lost-my-key").and_raise(@a_404_exception)
+      end
+
+      it "raises a 404 error" do
+        expect { Chef::ApiClientV1.reregister("lost-my-key") }.to raise_error(Net::HTTPServerException)
+      end
+    end
+  end
+
+  describe "Versioned API Interactions" do
+    let(:response_406) { OpenStruct.new(:code => "406") }
+    let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
+    let(:payload) {
+      {
+        :name => "some_name",
+        :validator => true,
+        :admin => true,
+      }
+    }
+
+    before do
+      @client = Chef::ApiClientV1.new
+      allow(@client).to receive(:chef_rest_v0).and_return(double("chef rest root v0 object"))
+      allow(@client).to receive(:chef_rest_v1).and_return(double("chef rest root v1 object"))
+      @client.name "some_name"
+      @client.validator true
+      @client.admin true
+    end
+
+    describe "create" do
+
+      # from spec/support/shared/unit/user_and_client_shared.rb
+      it_should_behave_like "user or client create" do
+        let(:object)  { @client }
+        let(:error)   { Chef::Exceptions::InvalidClientAttribute }
+        let(:rest_v0) { @client.chef_rest_v0 }
+        let(:rest_v1) { @client.chef_rest_v1 }
+        let(:url)     { "clients" }
+      end
+
+      context "when API V1 is not supported by the server" do
+        # from spec/support/shared/unit/api_versioning.rb
+        it_should_behave_like "version handling" do
+          let(:object)    { @client }
+          let(:method)    { :create }
+          let(:http_verb) { :post }
+          let(:rest_v1)   { @client.chef_rest_v1 }
+        end
+      end
+
+    end # create
+
+    describe "update" do
+      context "when a valid client is defined" do
+
+        shared_examples_for "client updating" do
+          it "updates the client" do
+            expect(rest). to receive(:put).with("clients/some_name", payload).and_return(payload)
+            @client.update
+          end
+
+          context "when only the name field exists" do
+
+            before do
+              # needed since there is no way to set to nil via code
+              @client.instance_variable_set(:@validator, nil)
+              @client.instance_variable_set(:@admin, nil)
+            end
+
+            after do
+              @client.validator true
+              @client.admin true
+            end
+
+            it "updates the client with only the name" do
+              expect(rest). to receive(:put).with("clients/some_name", { :name => "some_name" }).and_return({ :name => "some_name" })
+              @client.update
+            end
+          end
+
+        end
+
+        context "when API V1 is supported by the server" do
+
+          it_should_behave_like "client updating" do
+            let(:rest) { @client.chef_rest_v1 }
+          end
+
+        end # when API V1 is supported by the server
+
+        context "when API V1 is not supported by the server" do
+          context "when no version is supported" do
+            # from spec/support/shared/unit/api_versioning.rb
+            it_should_behave_like "version handling" do
+              let(:object)    { @client }
+              let(:method)    { :create }
+              let(:http_verb) { :post }
+              let(:rest_v1)   { @client.chef_rest_v1 }
+            end
+          end # when no version is supported
+
+          context "when API V0 is supported" do
+
+            before do
+              allow(@client.chef_rest_v1).to receive(:put).and_raise(exception_406)
+              allow(@client).to receive(:server_client_api_version_intersection).and_return([0])
+            end
+
+            it_should_behave_like "client updating" do
+              let(:rest) { @client.chef_rest_v0 }
+            end
+
+          end
+
+        end # when API V1 is not supported by the server
+      end # when a valid client is defined
+    end # update
+
+    # DEPRECATION
+    # This can be removed after API V0 support is gone
+    describe "reregister" do
+      context "when server API V0 is valid on the Chef Server receiving the request" do
+        it "creates a new object via the API" do
+          expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({ :private_key => true })).and_return({})
+          @client.reregister
+        end
+      end # when server API V0 is valid on the Chef Server receiving the request
+
+      context "when server API V0 is not supported by the Chef Server" do
+        # from spec/support/shared/unit/api_versioning.rb
+        it_should_behave_like "user and client reregister" do
+          let(:object)    { @client }
+          let(:rest_v0)   { @client.chef_rest_v0 }
+        end
+      end # when server API V0 is not supported by the Chef Server
+    end # reregister
+
+  end
+end
diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb
index f6cd0ba..d7298d0 100644
--- a/spec/unit/application/apply_spec.rb
+++ b/spec/unit/application/apply_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan W. Berry (<bryan.berry at gmail.com>)
-# Copyright:: Copyright (c) 2012 Bryan W. Berry
+# Copyright:: Copyright 2012-2016, Bryan W. Berry
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Application::Apply do
 
@@ -92,7 +92,7 @@ describe Chef::Application::Apply do
 
   end
   describe "when the json_attribs configuration option is specified" do
-    let(:json_attribs) { {"a" => "b"} }
+    let(:json_attribs) { { "a" => "b" } }
     let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
     let(:json_source) { "https://foo.com/foo.json" }
 
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index c753ca0..ff6f460 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Application::Client, "reconfigure" do
   let(:app) do
@@ -36,17 +36,34 @@ describe Chef::Application::Client, "reconfigure" do
     Chef::Config[:interval] = 10
 
     Chef::Config[:once] = false
+
+    # protect the unit tests against accidental --delete-entire-chef-repo from firing
+    # for real during tests.  DO NOT delete this line.
+    expect(FileUtils).not_to receive(:rm_rf)
   end
 
   after do
     ARGV.replace(@original_argv)
   end
 
-  describe 'parse cli_arguments' do
-    it 'should call set_specific_recipes' do
+  describe "parse cli_arguments" do
+    it "should call set_specific_recipes" do
       expect(app).to receive(:set_specific_recipes).and_return(true)
       app.reconfigure
     end
+
+    context "when given a named_run_list" do
+
+      before do
+        ARGV.replace( %w{ --named-run-list arglebargle-example } )
+        app.reconfigure
+      end
+
+      it "sets named_run_list in Chef::Config" do
+        expect(Chef::Config[:named_run_list]).to eq("arglebargle-example")
+      end
+
+    end
   end
 
   describe "when configured to not fork the client process" do
@@ -60,7 +77,7 @@ describe Chef::Application::Client, "reconfigure" do
     context "when interval is given" do
       before do
         Chef::Config[:interval] = 600
-        allow(Chef::Platform).to receive(:windows?).and_return(false)
+        allow(ChefConfig).to receive(:windows?).and_return(false)
       end
 
       it "should terminate with message" do
@@ -77,7 +94,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
     context "when interval is given on windows" do
       before do
         Chef::Config[:interval] = 600
-        allow(Chef::Platform).to receive(:windows?).and_return(true)
+        allow(ChefConfig).to receive(:windows?).and_return(true)
       end
 
       it "should not terminate" do
@@ -143,7 +160,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
 
   describe "when the json_attribs configuration option is specified" do
 
-    let(:json_attribs) { {"a" => "b"} }
+    let(:json_attribs) { { "a" => "b" } }
     let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
     let(:json_source) { "https://foo.com/foo.json" }
 
@@ -165,11 +182,6 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
       before do
         allow(Chef::Log).to receive(:warn)
       end
-
-      it "emits a warning that audit mode is an experimental feature" do
-        expect(Chef::Log).to receive(:warn).with(/Audit mode is an experimental feature/)
-        app.reconfigure
-      end
     end
 
     shared_examples "unrecognized setting" do
@@ -242,12 +254,11 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
     end
 
     it "should throw an exception" do
-      expect { @app.reconfigure }.to raise_error
+      expect { app.reconfigure }.to raise_error(Chef::Exceptions::PIDFileLockfileMatch)
     end
   end
 end
 
-
 describe Chef::Application::Client, "setup_application" do
   before do
     @app = Chef::Application::Client.new
@@ -280,9 +291,9 @@ describe Chef::Application::Client, "configure_chef" do
     ARGV.replace(@original_argv)
   end
 
-  it "should set the colored output to false by default on windows and true otherwise" do
+  it "should set the colored output to true by default on windows and true on all other platforms as well" do
     if windows?
-      expect(Chef::Config[:color]).to be_falsey
+      expect(Chef::Config[:color]).to be_truthy
     else
       expect(Chef::Config[:color]).to be_truthy
     end
@@ -302,9 +313,9 @@ describe Chef::Application::Client, "run_application", :unix_only do
     @client = Chef::Client.new
     allow(Chef::Client).to receive(:new).and_return(@client)
     allow(@client).to receive(:run) do
-      @pipe[1].puts 'started'
+      @pipe[1].puts "started"
       sleep 1
-      @pipe[1].puts 'finished'
+      @pipe[1].puts "finished"
     end
   end
 
diff --git a/spec/unit/application/knife_spec.rb b/spec/unit/application/knife_spec.rb
index 3c215ea..90ecde6 100644
--- a/spec/unit/application/knife_spec.rb
+++ b/spec/unit/application/knife_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 require "#{CHEF_SPEC_DATA}/knife_subcommand/test_yourself"
 
 describe Chef::Application::Knife do
@@ -70,21 +70,73 @@ describe Chef::Application::Knife do
     end
   end
 
-  it "should set the colored output to false by default on windows and true otherwise" do
+  it "should set the colored output to true by default on windows and true on all other platforms as well" do
     with_argv(*%w{noop knife command}) do
       expect(@knife).to receive(:exit).with(0)
       @knife.run
     end
     if windows?
-      expect(Chef::Config[:color]).to be_falsey
+      expect(Chef::Config[:color]).to be_truthy
     else
       expect(Chef::Config[:color]).to be_truthy
     end
   end
 
+  context "when given fips flags" do
+    context "when Chef::Config[:fips]=false" do
+      before do
+        # This is required because the chef-fips pipeline does
+        # has a default value of true for fips
+        Chef::Config[:fips] = false
+      end
+
+      it "does not initialize fips mode when no flags are passed" do
+        with_argv(*%w{noop knife command}) do
+          expect(@knife).to receive(:exit).with(0)
+          expect(Chef::Config).not_to receive(:enable_fips_mode)
+          @knife.run
+          expect(Chef::Config[:fips]).to eq(false)
+        end
+      end
+
+      it "overwrites the Chef::Config value when passed --fips" do
+        with_argv(*%w{noop knife command --fips}) do
+          expect(@knife).to receive(:exit).with(0)
+          expect(Chef::Config).to receive(:enable_fips_mode)
+          @knife.run
+          expect(Chef::Config[:fips]).to eq(true)
+        end
+      end
+    end
+
+    context "when Chef::Config[:fips]=true" do
+      before do
+        Chef::Config[:fips] = true
+      end
+
+      it "initializes fips mode when passed --fips" do
+        with_argv(*%w{noop knife command --fips}) do
+          expect(@knife).to receive(:exit).with(0)
+          expect(Chef::Config).to receive(:enable_fips_mode)
+          @knife.run
+          expect(Chef::Config[:fips]).to eq(true)
+        end
+      end
+
+      it "overwrites the Chef::Config value when passed --no-fips" do
+        with_argv(*%w{noop knife command --no-fips}) do
+          expect(@knife).to receive(:exit).with(0)
+          expect(Chef::Config).not_to receive(:enable_fips_mode)
+          @knife.run
+          expect(Chef::Config[:fips]).to eq(false)
+        end
+      end
+    end
+  end
+
   describe "when given a path to the client key" do
     it "expands a relative path relative to the CWD" do
-      relative_path = '.chef/client.pem'
+      relative_path = ".chef/client.pem"
       allow(Dir).to receive(:pwd).and_return(CHEF_SPEC_DATA)
       with_argv(*%W{noop knife command -k #{relative_path}}) do
         expect(@knife).to receive(:exit).with(0)
@@ -94,20 +146,20 @@ describe Chef::Application::Knife do
     end
 
     it "expands a ~/home/path to the correct full path" do
-      home_path = '~/.chef/client.pem'
+      home_path = "~/.chef/client.pem"
       with_argv(*%W{noop knife command -k #{home_path}}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
       end
-      expect(Chef::Config[:client_key]).to eq(File.join(ENV['HOME'], '.chef/client.pem').gsub((File::ALT_SEPARATOR || '\\'), File::SEPARATOR))
+      expect(Chef::Config[:client_key]).to eq(File.join(ENV["HOME"], ".chef/client.pem").gsub((File::ALT_SEPARATOR || '\\'), File::SEPARATOR))
     end
 
     it "does not expand a full path" do
       full_path = if windows?
-        'C:/chef/client.pem'
-      else
-        '/etc/chef/client.pem'
-      end
+                    "C:/chef/client.pem"
+                  else
+                    "/etc/chef/client.pem"
+                  end
       with_argv(*%W{noop knife command -k #{full_path}}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
@@ -130,38 +182,38 @@ describe Chef::Application::Knife do
     end
 
     it "should load the environment from the config file" do
-      config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+      config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
       with_argv(*%W{noop knife command -c #{config_file}}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
       end
-      expect(Chef::Config[:environment]).to eq('production')
+      expect(Chef::Config[:environment]).to eq("production")
     end
 
     it "should load the environment from the CLI options" do
-      with_argv(*%W{noop knife command -E development}) do
+      with_argv(*%w{noop knife command -E development}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
       end
-      expect(Chef::Config[:environment]).to eq('development')
+      expect(Chef::Config[:environment]).to eq("development")
     end
 
     it "should override the config file environment with the CLI environment" do
-      config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+      config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
       with_argv(*%W{noop knife command -c #{config_file} -E override}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
       end
-      expect(Chef::Config[:environment]).to eq('override')
+      expect(Chef::Config[:environment]).to eq("override")
     end
 
     it "should override the config file environment with the CLI environment regardless of order" do
-      config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb")
+      config_file = File.join(CHEF_SPEC_DATA, "environment-config.rb")
       with_argv(*%W{noop knife command -E override -c #{config_file}}) do
         expect(@knife).to receive(:exit).with(0)
         @knife.run
       end
-      expect(Chef::Config[:environment]).to eq('override')
+      expect(Chef::Config[:environment]).to eq("override")
     end
 
     it "should run a sub command with the applications command line option prototype" do
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index 1785ecf..4361a2c 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Application::Solo do
 
@@ -28,13 +28,16 @@ describe Chef::Application::Solo do
     allow(app).to receive(:configure_logging).and_return(true)
     allow(app).to receive(:trap)
 
-    Chef::Config[:recipe_url] = false
     Chef::Config[:json_attribs] = false
     Chef::Config[:solo] = true
+
+    # protect the unit tests against accidental --delete-entire-chef-repo from firing
+    # for real during tests.  DO NOT delete this line.
+    expect(FileUtils).not_to receive(:rm_rf)
   end
 
   describe "configuring the application" do
-    it 'should call set_specific_recipes' do
+    it "should call set_specific_recipes" do
       expect(app).to receive(:set_specific_recipes)
       app.reconfigure
     end
@@ -87,7 +90,7 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
     end
 
     describe "when the json_attribs configuration option is specified" do
-      let(:json_attribs) { {"a" => "b"} }
+      let(:json_attribs) { { "a" => "b" } }
       let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
       let(:json_source) { "https://foo.com/foo.json" }
 
@@ -103,60 +106,39 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
       end
     end
 
-    describe "when the recipe_url configuration option is specified" do
-      let(:tarfile) { StringIO.new("remote_tarball_content") }
-      let(:target_file) { StringIO.new }
+    it "downloads a tarball when the recipe_url configuration option is specified" do
+      Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
+      Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
 
-      before do
-        Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
-        Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
+      expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
 
-        allow(FileUtils).to receive(:rm_rf).and_return(true)
-        allow(FileUtils).to receive(:mkdir_p).and_return(true)
+      tarfile = StringIO.new("remote_tarball_content")
+      target_file = StringIO.new
 
-        allow(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
-        allow(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
+      expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
+      expect(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
 
-        allow(Chef::Mixin::Command).to receive(:run_command).and_return(true)
-      end
+      shellout = instance_double("Mixlib::ShellOut", run_command: nil, error!: nil, stdout: "")
 
-      it "should create the recipes path based on the parent of the cookbook path" do
-        expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
-        app.reconfigure
-      end
-
-      it "should download the recipes" do
-        expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
-        app.reconfigure
-      end
-
-      it "should write the recipes to the target path" do
-        app.reconfigure
-        expect(target_file.string).to eq("remote_tarball_content")
-      end
-
-      it "should untar the target file to the parent of the cookbook path" do
-        expect(Chef::Mixin::Command).to receive(:run_command).with({:command => "tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo"}).and_return(true)
-        app.reconfigure
-      end
+      expect(app).to receive(:shell_out!).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo").and_return(shellout)
+      app.reconfigure
+      expect(target_file.string).to eq("remote_tarball_content")
     end
-  end
 
-  describe "when the json_attribs and recipe_url configuration options are both specified" do
-    let(:json_attribs) { {"a" => "b"} }
-    let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) }
-    let(:json_source) { "https://foo.com/foo.json" }
+    it "fetches the recipe_url first when both json_attribs and recipe_url are specified" do
+      json_attribs = { "a" => "b" }
+      config_fetcher = instance_double("Chef::ConfigFetcher", :fetch_json => json_attribs)
 
-    before do
-      Chef::Config[:json_attribs] = json_source
+      Chef::Config[:json_attribs] = "https://foo.com/foo.json"
       Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats"
       Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
-      allow(FileUtils).to receive(:rm_rf).and_return(true)
-      allow(FileUtils).to receive(:mkdir_p).and_return(true)
+      expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
+
       allow(Chef::Mixin::Command).to receive(:run_command).and_return(true)
-    end
 
-    it "should fetch the recipe_url first" do
+      shellout = instance_double("Mixlib::ShellOut", run_command: nil, error!: nil, stdout: "")
+
+      expect(app).to receive(:shell_out!).with("tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo").and_return(shellout)
       expect(app).to receive(:fetch_recipe_tarball).ordered
       expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
       app.reconfigure
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index f5a2c72..462b731 100644
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Author:: Mark Mzyk (mmzyk at opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Mark Mzyk (mmzyk at chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Application do
   before do
@@ -34,389 +34,229 @@ describe Chef::Application do
     ARGV.replace(@original_argv)
   end
 
-  describe "reconfigure" do
-    before do
-      @app = Chef::Application.new
-      allow(@app).to receive(:configure_chef).and_return(true)
-      allow(@app).to receive(:configure_logging).and_return(true)
-      allow(@app).to receive(:configure_proxy_environment_variables).and_return(true)
-    end
-
-    it "should configure chef" do
-      expect(@app).to receive(:configure_chef).and_return(true)
-      @app.reconfigure
-    end
-
-    it "should configure logging" do
-      expect(@app).to receive(:configure_logging).and_return(true)
-      @app.reconfigure
-    end
-
-    it "should configure environment variables" do
-      expect(@app).to receive(:configure_proxy_environment_variables).and_return(true)
-      @app.reconfigure
-    end
+  context "when there are no configuration errors" do
 
-    it 'should not receive set_specific_recipes' do
-      expect(@app).to_not receive(:set_specific_recipes)
-      @app.reconfigure
-    end
-  end
-
-  describe Chef::Application do
     before do
-      @app = Chef::Application.new
+      expect(Chef::Log).to_not receive(:fatal)
+      expect(Chef::Application).to_not receive(:fatal!)
     end
 
-    describe "run" do
+    describe "reconfigure" do
       before do
-        allow(@app).to receive(:setup_application).and_return(true)
-        allow(@app).to receive(:run_application).and_return(true)
+        @app = Chef::Application.new
         allow(@app).to receive(:configure_chef).and_return(true)
         allow(@app).to receive(:configure_logging).and_return(true)
       end
 
-      it "should reconfigure the application before running" do
-        expect(@app).to receive(:reconfigure).and_return(true)
-        @app.run
+      it "should configure chef" do
+        expect(@app).to receive(:configure_chef).and_return(true)
+        @app.reconfigure
       end
 
-      it "should setup the application before running it" do
-        expect(@app).to receive(:setup_application).and_return(true)
-        @app.run
+      it "should configure logging" do
+        expect(@app).to receive(:configure_logging).and_return(true)
+        @app.reconfigure
       end
 
-      it "should run the actual application" do
-        expect(@app).to receive(:run_application).and_return(true)
-        @app.run
+      it "should not receive set_specific_recipes" do
+        expect(@app).to_not receive(:set_specific_recipes)
+        @app.reconfigure
       end
     end
-  end
-
-  describe "configure_chef" do
-    before do
-      # Silence warnings when no config file exists
-      allow(Chef::Log).to receive(:warn)
-
-      @app = Chef::Application.new
-      #Chef::Config.stub(:merge!).and_return(true)
-      allow(@app).to receive(:parse_options).and_return(true)
-    end
-
-    it "should parse the commandline options" do
-      expect(@app).to receive(:parse_options).and_return(true)
-      @app.config[:config_file] = "/etc/chef/default.rb" #have a config file set, to prevent triggering error block
-      @app.configure_chef
-    end
-
-    describe "when a config_file is present" do
-      let(:config_content) { "rspec_ran('true')" }
-      let(:config_location) { "/etc/chef/default.rb" }
-
-      let(:config_location_pathname) do
-        p = Pathname.new(config_location)
-        allow(p).to receive(:realpath).and_return(config_location)
-        p
-      end
 
+    describe Chef::Application do
       before do
-        @app.config[:config_file] = config_location
-
-        # force let binding to get evaluated or else we stub Pathname.new before we try to use it.
-        config_location_pathname
-        allow(Pathname).to receive(:new).with(config_location).and_return(config_location_pathname)
-        expect(File).to receive(:read).
-          with(config_location).
-          and_return(config_content)
+        @app = Chef::Application.new
       end
 
-      it "should configure chef::config from a file" do
-        expect(Chef::Config).to receive(:from_string).with(config_content, config_location)
-        @app.configure_chef
-      end
-
-      it "should merge the local config hash into chef::config" do
-        #File.should_receive(:open).with("/etc/chef/default.rb").and_yield(@config_file)
-        @app.configure_chef
-        expect(Chef::Config.rspec_ran).to eq("true")
-      end
+      describe "run" do
+        before do
+          allow(@app).to receive(:setup_application).and_return(true)
+          allow(@app).to receive(:run_application).and_return(true)
+          allow(@app).to receive(:configure_chef).and_return(true)
+          allow(@app).to receive(:configure_logging).and_return(true)
+        end
 
-    end
+        it "should reconfigure the application before running" do
+          expect(@app).to receive(:reconfigure).and_return(true)
+          @app.run
+        end
 
-    describe "when there is no config_file defined" do
-      before do
-        @app.config[:config_file] = nil
-      end
+        it "should setup the application before running it" do
+          expect(@app).to receive(:setup_application).and_return(true)
+          @app.run
+        end
 
-      it "should emit a warning" do
-        expect(Chef::Config).not_to receive(:from_file).with("/etc/chef/default.rb")
-        expect(Chef::Log).to receive(:warn).with("No config file found or specified on command line, using command line options.")
-        @app.configure_chef
+        it "should run the actual application" do
+          expect(@app).to receive(:run_application).and_return(true)
+          @app.run
+        end
       end
     end
 
-    describe "when the config file is set and not found" do
+    describe "configure_chef" do
       before do
-        @app.config[:config_file] = "/etc/chef/notfound"
+        # Silence warnings when no config file exists
+        allow(Chef::Log).to receive(:warn)
+
+        @app = Chef::Application.new
+        allow(@app).to receive(:parse_options).and_return(true)
+        expect(Chef::Config).to receive(:export_proxies).and_return(true)
       end
-      it "should use the passed in command line options and defaults" do
-        expect(Chef::Config).to receive(:merge!)
+
+      it "should parse the commandline options" do
+        expect(@app).to receive(:parse_options).and_return(true)
+        @app.config[:config_file] = "/etc/chef/default.rb" #have a config file set, to prevent triggering error block
         @app.configure_chef
       end
-    end
-  end
 
-  describe "when configuring the logger" do
-    before do
-      @app = Chef::Application.new
-      allow(Chef::Log).to receive(:init)
-    end
-
-    it "should initialise the chef logger" do
-      allow(Chef::Log).to receive(:level=)
-      @monologger = double("Monologger")
-      expect(MonoLogger).to receive(:new).with(Chef::Config[:log_location]).and_return(@monologger)
-      expect(Chef::Log).to receive(:init).with(@monologger)
-      @app.configure_logging
-    end
+      describe "when a config_file is present" do
+        let(:config_content) { "rspec_ran('true')" }
+        let(:config_location) { "/etc/chef/default.rb" }
 
-    it "should raise fatals if log location is invalid" do
-      Chef::Config[:log_location] = "/tmp/non-existing-dir/logfile"
-      expect(Chef::Log).to receive(:fatal).at_least(:once)
-      expect(Process).to receive(:exit)
-      @app.configure_logging
-    end
+        let(:config_location_pathname) do
+          p = Pathname.new(config_location)
+          allow(p).to receive(:realpath).and_return(config_location)
+          p
+        end
 
-    shared_examples_for "log_level_is_auto" do
-      context "when STDOUT is to a tty" do
         before do
-          allow(STDOUT).to receive(:tty?).and_return(true)
+          @app.config[:config_file] = config_location
+
+          # force let binding to get evaluated or else we stub Pathname.new before we try to use it.
+          config_location_pathname
+          allow(Pathname).to receive(:new).with(config_location).and_return(config_location_pathname)
+          expect(File).to receive(:read).
+            with(config_location).
+            and_return(config_content)
         end
 
-        it "configures the log level to :warn" do
-          @app.configure_logging
-          expect(Chef::Log.level).to eq(:warn)
+        it "should configure chef::config from a file" do
+          expect(Chef::Config).to receive(:from_string).with(config_content, File.expand_path(config_location))
+          @app.configure_chef
         end
 
-        context "when force_logger is configured" do
+        it "should merge the local config hash into chef::config" do
+          #File.should_receive(:open).with("/etc/chef/default.rb").and_yield(@config_file)
+          @app.configure_chef
+          expect(Chef::Config.rspec_ran).to eq("true")
+        end
+
+        context "when openssl fips" do
           before do
-            Chef::Config[:force_logger] = true
+            allow(Chef::Config).to receive(:fips).and_return(true)
           end
 
-          it "configures the log level to info" do
-            @app.configure_logging
-            expect(Chef::Log.level).to eq(:info)
+          it "sets openssl in fips mode" do
+            expect(Chef::Config).to receive(:enable_fips_mode)
+            @app.configure_chef
           end
         end
       end
 
-      context "when STDOUT is not to a tty" do
+      describe "when there is no config_file defined" do
         before do
-          allow(STDOUT).to receive(:tty?).and_return(false)
+          @app.config[:config_file] = nil
         end
 
-        it "configures the log level to :info" do
-          @app.configure_logging
-          expect(Chef::Log.level).to eq(:info)
-        end
-
-        context "when force_formatter is configured" do
-          before do
-            Chef::Config[:force_formatter] = true
-          end
-          it "sets the log level to :warn" do
-            @app.configure_logging
-            expect(Chef::Log.level).to eq(:warn)
-          end
+        it "should emit a warning" do
+          expect(Chef::Config).not_to receive(:from_file).with("/etc/chef/default.rb")
+          expect(Chef::Log).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+          @app.configure_chef
         end
       end
-    end
 
-    context "when log_level is not set" do
-      it_behaves_like "log_level_is_auto"
-    end
-
-    context "when log_level is :auto" do
-      before do
-        Chef::Config[:log_level] = :auto
+      describe "when the config file is set and not found" do
+        before do
+          @app.config[:config_file] = "/etc/chef/notfound"
+        end
+        it "should use the passed in command line options and defaults" do
+          expect(Chef::Config).to receive(:merge!)
+          @app.configure_chef
+        end
       end
-
-      it_behaves_like "log_level_is_auto"
     end
-  end
 
-  describe "when configuring environment variables" do
-    def configure_proxy_environment_variables_stubs
-      allow(@app).to receive(:configure_http_proxy).and_return(true)
-      allow(@app).to receive(:configure_https_proxy).and_return(true)
-      allow(@app).to receive(:configure_ftp_proxy).and_return(true)
-      allow(@app).to receive(:configure_no_proxy).and_return(true)
-    end
-
-    shared_examples_for "setting ENV['http_proxy']" do
+    describe "when configuring the logger" do
       before do
-        Chef::Config[:http_proxy] = http_proxy
-      end
-
-      it "should set ENV['http_proxy']" do
-        @app.configure_proxy_environment_variables
-        expect(@env['http_proxy']).to eq("#{scheme}://#{address}:#{port}")
+        @app = Chef::Application.new
+        allow(Chef::Log).to receive(:init)
       end
 
-      it "should set ENV['HTTP_PROXY']" do
-        @app.configure_proxy_environment_variables
-        expect(@env['HTTP_PROXY']).to eq("#{scheme}://#{address}:#{port}")
+      it "should initialise the chef logger" do
+        allow(Chef::Log).to receive(:level=)
+        @monologger = double("Monologger")
+        expect(MonoLogger).to receive(:new).with(Chef::Config[:log_location]).and_return(@monologger)
+        expect(Chef::Log).to receive(:init).with(@monologger)
+        @app.configure_logging
       end
 
-      describe "when Chef::Config[:http_proxy_user] is set" do
-        before do
-          Chef::Config[:http_proxy_user] = "username"
-        end
-
-        it "should set ENV['http_proxy'] with the username" do
-          @app.configure_proxy_environment_variables
-          expect(@env['http_proxy']).to eq("#{scheme}://username@#{address}:#{port}")
-          expect(@env['HTTP_PROXY']).to eq("#{scheme}://username@#{address}:#{port}")
-        end
-
-        context "when :http_proxy_user contains '@' and/or ':'" do
+      shared_examples_for "log_level_is_auto" do
+        context "when STDOUT is to a tty" do
           before do
-            Chef::Config[:http_proxy_user] = "my:usern at me"
+            allow(STDOUT).to receive(:tty?).and_return(true)
           end
 
-          it "should set ENV['http_proxy'] with the escaped username" do
-            @app.configure_proxy_environment_variables
-            expect(@env['http_proxy']).to eq("#{scheme}://my%3Ausern%40me@#{address}:#{port}")
-            expect(@env['HTTP_PROXY']).to eq("#{scheme}://my%3Ausern%40me@#{address}:#{port}")
+          it "configures the log level to :warn" do
+            @app.configure_logging
+            expect(Chef::Log.level).to eq(:warn)
+          end
+
+          context "when force_logger is configured" do
+            before do
+              Chef::Config[:force_logger] = true
+            end
+
+            it "configures the log level to info" do
+              @app.configure_logging
+              expect(Chef::Log.level).to eq(:info)
+            end
           end
         end
 
-        describe "when Chef::Config[:http_proxy_pass] is set" do
+        context "when STDOUT is not to a tty" do
           before do
-            Chef::Config[:http_proxy_pass] = "password"
+            allow(STDOUT).to receive(:tty?).and_return(false)
           end
 
-          it "should set ENV['http_proxy'] with the password" do
-            @app.configure_proxy_environment_variables
-            expect(@env['http_proxy']).to eq("#{scheme}://username:password@#{address}:#{port}")
-            expect(@env['HTTP_PROXY']).to eq("#{scheme}://username:password@#{address}:#{port}")
+          it "configures the log level to :info" do
+            @app.configure_logging
+            expect(Chef::Log.level).to eq(:info)
           end
 
-          context "when :http_proxy_pass contains '@' and/or ':'" do
+          context "when force_formatter is configured" do
             before do
-              Chef::Config[:http_proxy_pass] = ":P at ssword101"
+              Chef::Config[:force_formatter] = true
             end
-
-            it "should set ENV['http_proxy'] with the escaped password" do
-              @app.configure_proxy_environment_variables
-              expect(@env['http_proxy']).to eq("#{scheme}://username:%3AP%40ssword101@#{address}:#{port}")
-              expect(@env['HTTP_PROXY']).to eq("#{scheme}://username:%3AP%40ssword101@#{address}:#{port}")
+            it "sets the log level to :warn" do
+              @app.configure_logging
+              expect(Chef::Log.level).to eq(:warn)
             end
           end
         end
       end
 
-      describe "when Chef::Config[:http_proxy_pass] is set (but not Chef::Config[:http_proxy_user])" do
-        before do
-          Chef::Config[:http_proxy_user] = nil
-          Chef::Config[:http_proxy_pass] = "password"
-        end
-
-        it "should set ENV['http_proxy']" do
-          @app.configure_proxy_environment_variables
-          expect(@env['http_proxy']).to eq("#{scheme}://#{address}:#{port}")
-          expect(@env['HTTP_PROXY']).to eq("#{scheme}://#{address}:#{port}")
-        end
+      context "when log_level is not set" do
+        it_behaves_like "log_level_is_auto"
       end
-    end
 
-    describe "when configuring ENV['http_proxy']" do
-      before do
-        @env = {}
-        allow(@app).to receive(:env).and_return(@env)
-
-        allow(@app).to receive(:configure_https_proxy).and_return(true)
-        allow(@app).to receive(:configure_ftp_proxy).and_return(true)
-        allow(@app).to receive(:configure_no_proxy).and_return(true)
-      end
-
-      describe "when Chef::Config[:http_proxy] is not set" do
+      context "when log_level is :auto" do
         before do
-          Chef::Config[:http_proxy] = nil
+          Chef::Config[:log_level] = :auto
         end
 
-        it "should not set ENV['http_proxy']" do
-          @app.configure_proxy_environment_variables
-          expect(@env).to eq({})
-        end
+        it_behaves_like "log_level_is_auto"
       end
+    end
+  end
 
-      describe "when Chef::Config[:http_proxy] is set" do
-        context "when given an FQDN" do
-          let(:scheme) { "http" }
-          let(:address) { "proxy.example.org" }
-          let(:port) { 8080 }
-          let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
-          it_should_behave_like "setting ENV['http_proxy']"
-        end
-
-        context "when given an HTTPS URL" do
-          let(:scheme) { "https" }
-          let(:address) { "proxy.example.org" }
-          let(:port) { 8080 }
-          let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
-          it_should_behave_like "setting ENV['http_proxy']"
-        end
-
-        context "when given an IP" do
-          let(:scheme) { "http" }
-          let(:address) { "127.0.0.1" }
-          let(:port) { 22 }
-          let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
-          it_should_behave_like "setting ENV['http_proxy']"
-        end
-
-        context "when given an IPv6" do
-          let(:scheme) { "http" }
-          let(:address) { "[2001:db8::1]" }
-          let(:port) { 80 }
-          let(:http_proxy) { "#{scheme}://#{address}:#{port}" }
-
-          it_should_behave_like "setting ENV['http_proxy']"
-        end
-
-        context "when given without including http://" do
-          let(:scheme) { "http" }
-          let(:address) { "proxy.example.org" }
-          let(:port) { 8181 }
-          let(:http_proxy) { "#{address}:#{port}" }
-
-          it_should_behave_like "setting ENV['http_proxy']"
-        end
-
-        context "when given the full proxy in :http_proxy only" do
-          before do
-            Chef::Config[:http_proxy] = "http://username:password@proxy.example.org:2222"
-            Chef::Config[:http_proxy_user] = nil
-            Chef::Config[:http_proxy_pass] = nil
-          end
-
-          it "should set ENV['http_proxy']" do
-            @app.configure_proxy_environment_variables
-            expect(@env['http_proxy']).to eq(Chef::Config[:http_proxy])
-          end
-        end
+  context "with an invalid log location" do
 
-        context "when the config options aren't URI compliant" do
-          it "raises Chef::Exceptions::BadProxyURI" do
-            Chef::Config[:http_proxy] = "http://proxy.bad_example.org/:8080"
-            expect { @app.configure_proxy_environment_variables }.to raise_error(Chef::Exceptions::BadProxyURI)
-          end
-        end
-      end
+    it "logs a fatal error and exits" do
+      Chef::Config[:log_location] = "/tmp/non-existing-dir/logfile"
+      expect(Chef::Log).to receive(:fatal).at_least(:once)
+      expect(Process).to receive(:exit)
+      @app.configure_logging
     end
   end
 
@@ -478,18 +318,18 @@ describe Chef::Application do
     end
   end
 
-  describe 'run_chef_client' do
-    context 'with an application' do
+  describe "run_chef_client" do
+    context "with an application" do
       let(:app) { Chef::Application.new }
 
-      context 'when called with an invalid argument' do
+      context "when called with an invalid argument" do
         before do
           allow(app).to receive(:fork_chef_client).and_return(true)
           allow(app).to receive(:run_with_graceful_exit_option).and_return(true)
         end
 
-        it 'should raise an argument error detailing the problem' do
-          specific_recipes_regexp = Regexp.new 'received non-Array like specific_recipes argument'
+        it "should raise an argument error detailing the problem" do
+          specific_recipes_regexp = Regexp.new "received non-Array like specific_recipes argument"
           expect { app.run_chef_client(nil) }.to raise_error(ArgumentError, specific_recipes_regexp)
         end
       end
@@ -500,7 +340,7 @@ describe Chef::Application do
           allow(app).to receive(:run_with_graceful_exit_option).and_return(true)
         end
 
-        it 'should be cool' do
+        it "should be cool" do
           expect { app.run_chef_client([]) }.not_to raise_error
         end
       end
diff --git a/spec/unit/audit/audit_event_proxy_spec.rb b/spec/unit/audit/audit_event_proxy_spec.rb
index 17a5d3d..2496aef 100644
--- a/spec/unit/audit/audit_event_proxy_spec.rb
+++ b/spec/unit/audit/audit_event_proxy_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Author:: Claire McQuin (<claire at getchef.com>)
+# Author:: Claire McQuin (<claire at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/audit/audit_event_proxy'
+require "spec_helper"
+require "chef/audit/audit_event_proxy"
 
 describe Chef::Audit::AuditEventProxy do
 
@@ -35,7 +35,7 @@ describe Chef::Audit::AuditEventProxy do
 
     let(:description) { "poots" }
     let(:group) { double("ExampleGroup", :parent_groups => parents,
-      :description => description) }
+                                         :description => description) }
     let(:notification) { double("Notification", :group => group) }
 
     context "when notified from a top-level example group" do
@@ -121,28 +121,28 @@ describe Chef::Audit::AuditEventProxy do
       let(:examples) { [example] }
 
       let(:example) { double("Example", :metadata => metadata,
-        :description => example_description,
-        :full_description => full_description, :exception => nil) }
+                                        :description => example_description,
+                                        :full_description => full_description, :exception => nil) }
 
       let(:metadata) {
         {
           :described_class => described_class,
           :example_group => example_group,
-          :line_number => line
+          :line_number => line,
         }
       }
 
       let(:example_group) {
         {
           :description => group_description,
-          :parent_example_group => parent_group
+          :parent_example_group => parent_group,
         }
       }
 
       let(:parent_group) {
         {
           :description => control_group_name,
-          :parent_example_group => nil
+          :parent_example_group => nil,
         }
       }
 
@@ -155,7 +155,7 @@ describe Chef::Audit::AuditEventProxy do
           :resource_type => resource_type,
           :resource_name => resource_name,
           :context => context,
-          :line_number => line
+          :line_number => line,
         }
       }
 
@@ -287,14 +287,14 @@ describe Chef::Audit::AuditEventProxy do
         let(:parent_group) {
           {
             :description => outer_group_description,
-            :parent_example_group => control_group
+            :parent_example_group => control_group,
           }
         }
 
         let(:control_group) {
           {
             :description => control_group_name,
-            :parent_example_group => nil
+            :parent_example_group => nil,
           }
         }
 
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
index 4bf8895..ed0aa62 100644
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ b/spec/unit/audit/audit_reporter_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Author:: Claire McQuin (<claire at getchef.com>)
+# Author:: Claire McQuin (<claire at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Audit::AuditReporter do
 
@@ -29,7 +29,7 @@ describe Chef::Audit::AuditReporter do
   let(:start_time) { Time.new(2014, 12, 3, 9, 31, 05, "-08:00") }
   let(:end_time) { Time.new(2014, 12, 3, 9, 36, 14, "-08:00") }
   let(:run_status) { instance_double(Chef::RunStatus, :node => node, :run_id => run_id,
-    :start_time => start_time, :end_time => end_time) }
+                                                      :start_time => start_time, :end_time => end_time) }
 
   describe "#audit_phase_start" do
 
@@ -57,7 +57,6 @@ describe Chef::Audit::AuditReporter do
     before do
       allow(reporter).to receive(:auditing_enabled?).and_return(true)
       allow(reporter).to receive(:run_status).and_return(run_status)
-      allow(rest).to receive(:create_url).and_return(true)
       allow(rest).to receive(:post).and_return(true)
       allow(reporter).to receive(:audit_data).and_return(audit_data)
       allow(reporter).to receive(:run_status).and_return(run_status)
@@ -75,19 +74,38 @@ describe Chef::Audit::AuditReporter do
       end
 
       it "posts audit data to server endpoint" do
-        endpoint = "api.opscode.us/orgname/controls"
         headers = {
-          'X-Ops-Audit-Report-Protocol-Version' => Chef::Audit::AuditReporter::PROTOCOL_VERSION
+          "X-Ops-Audit-Report-Protocol-Version" => Chef::Audit::AuditReporter::PROTOCOL_VERSION
         }
 
-        expect(rest).to receive(:create_url).
-          with("controls").
-          and_return(endpoint)
         expect(rest).to receive(:post).
-          with(endpoint, run_data, headers)
+          with("controls", run_data, headers)
         reporter.run_completed(node)
       end
 
+      context "when audit phase failed" do
+
+        let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
+                                                 :message => "Audit phase failed with error message: derpderpderp",
+                                                 :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+
+        before do
+          reporter.instance_variable_set(:@audit_phase_error, audit_error)
+        end
+
+        it "reports an error" do
+          reporter.run_completed(node)
+          expect(run_data).to have_key(:error)
+          expect(run_data).to have_key(:error)
+          expect(run_data[:error]).to eq <<-EOM.strip!
+Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
+/path/recipe.rb:57
+/path/library.rb:106
+EOM
+        end
+
+      end
+
       context "when unable to post to server" do
 
         let(:error) do
@@ -173,7 +191,7 @@ describe Chef::Audit::AuditReporter do
             expect(error).to receive(:respond_to?).with(:response).and_return(false)
             allow(Chef::Log).to receive(:error).and_return(true)
             expect(Chef::Log).to receive(:error).with(/Reporting fatals enabled. Aborting run./)
-            expect{ reporter.run_completed(node) }.to raise_error(error)
+            expect { reporter.run_completed(node) }.to raise_error(error)
           end
 
         end
@@ -215,9 +233,13 @@ describe Chef::Audit::AuditReporter do
     let(:audit_data) { Chef::Audit::AuditData.new(node.name, run_id) }
     let(:run_data) { audit_data.to_hash }
 
-    let(:error) { double("AuditError", :class => "Chef::Exception::AuditError",
-      :message => "Well that certainly didn't work",
-      :backtrace => ["line 0", "line 1", "line 2"]) }
+    let(:audit_error) { double("AuditError", :class => "Chef::Exceptions::AuditError",
+                                             :message => "Audit phase failed with error message: derpderpderp",
+                                             :backtrace => ["/path/recipe.rb:57", "/path/library.rb:106"]) }
+
+    let(:run_error) { double("RunError", :class => "Chef::Exceptions::RunError",
+                                         :message => "This error shouldn't be reported.",
+                                         :backtrace => ["fix it", "fix it", "fix it"]) }
 
     before do
       allow(reporter).to receive(:auditing_enabled?).and_return(true)
@@ -226,15 +248,30 @@ describe Chef::Audit::AuditReporter do
       allow(audit_data).to receive(:to_hash).and_return(run_data)
     end
 
-    it "adds the error information to the reported data" do
-      expect(rest).to receive(:create_url)
-      expect(rest).to receive(:post)
-      reporter.run_failed(error)
-      expect(run_data).to have_key(:error)
-      expect(run_data[:error]).to eq "Chef::Exception::AuditError: Well that certainly didn't work\n" +
-        "line 0\nline 1\nline 2"
+    context "when no prior exception is stored" do
+      it "reports no error" do
+        expect(rest).to receive(:post)
+        reporter.run_failed(run_error)
+        expect(run_data).to_not have_key(:error)
+      end
     end
 
+    context "when some prior exception is stored" do
+      before do
+        reporter.instance_variable_set(:@audit_phase_error, audit_error)
+      end
+
+      it "reports the prior error" do
+        expect(rest).to receive(:post)
+        reporter.run_failed(run_error)
+        expect(run_data).to have_key(:error)
+        expect(run_data[:error]).to eq <<-EOM.strip!
+Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
+/path/recipe.rb:57
+/path/library.rb:106
+EOM
+      end
+    end
   end
 
   shared_context "audit data" do
@@ -247,7 +284,7 @@ describe Chef::Audit::AuditReporter do
     let(:ordered_control_groups) {
       {
         "foo" => control_group_foo,
-        "bar" => control_group_bar
+        "bar" => control_group_bar,
       }
     }
 
@@ -270,14 +307,14 @@ describe Chef::Audit::AuditReporter do
 
     it "notifies audit phase finished to debug log" do
       expect(Chef::Log).to receive(:debug).with(/Audit Reporter completed/)
-      reporter.audit_phase_complete
+      reporter.audit_phase_complete("Output from audit mode")
     end
 
     it "collects audit data" do
       ordered_control_groups.each do |_name, group|
         expect(audit_data).to receive(:add_control_group).with(group)
       end
-      reporter.audit_phase_complete
+      reporter.audit_phase_complete("Output from audit mode")
     end
   end
 
@@ -288,14 +325,14 @@ describe Chef::Audit::AuditReporter do
 
     it "notifies audit phase failed to debug log" do
       expect(Chef::Log).to receive(:debug).with(/Audit Reporter failed/)
-      reporter.audit_phase_failed(error)
+      reporter.audit_phase_failed(error, "Output from audit mode")
     end
 
     it "collects audit data" do
       ordered_control_groups.each do |_name, group|
         expect(audit_data).to receive(:add_control_group).with(group)
       end
-      reporter.audit_phase_failed(error)
+      reporter.audit_phase_failed(error, "Output from audit mode")
     end
   end
 
@@ -329,7 +366,7 @@ describe Chef::Audit::AuditReporter do
     context "when a control group with the same name has been seen" do
       it "raises an exception" do
         expect(ordered_control_groups).to receive(:has_key?).with(name).and_return(true)
-        expect{ reporter.control_group_started(name) }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
+        expect { reporter.control_group_started(name) }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
       end
     end
   end
diff --git a/spec/unit/audit/control_group_data_spec.rb b/spec/unit/audit/control_group_data_spec.rb
index e21ab06..f6935a4 100644
--- a/spec/unit/audit/control_group_data_spec.rb
+++ b/spec/unit/audit/control_group_data_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Author:: Claire McQuin (<claire at getchef.com>)
+# Author:: Claire McQuin (<claire at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'securerandom'
+require "spec_helper"
+require "securerandom"
 
 describe Chef::Audit::AuditData do
 
@@ -72,8 +72,8 @@ describe Chef::Audit::AuditData do
 
     describe ":control_groups" do
 
-      let(:control_hash_1) { {:name => "control group 1"} }
-      let(:control_hash_2) { {:name => "control group 2"} }
+      let(:control_hash_1) { { :name => "control group 1" } }
+      let(:control_hash_2) { { :name => "control group 2" } }
 
       let(:control_groups) { audit_data_hash[:control_groups] }
 
@@ -123,9 +123,8 @@ describe Chef::Audit::ControlData do
   let(:line_number) { 27 }
 
   let(:control_data) { described_class.new(name: name,
-    resource_type: resource_type, resource_name: resource_name,
-    context: context, line_number: line_number) }
-
+                                           resource_type: resource_type, resource_name: resource_name,
+                                           context: context, line_number: line_number) }
 
   describe "#to_hash" do
 
@@ -178,7 +177,7 @@ describe Chef::Audit::ControlGroupData do
         :resource_type => resource_type,
         :resource_name => resource_name,
         :context => context,
-        :line_number => line_number
+        :line_number => line_number,
       }
     }
 
@@ -188,14 +187,14 @@ describe Chef::Audit::ControlGroupData do
     include_context "control data"
 
     let(:control) { Chef::Audit::ControlData.new(name: name,
-      resource_type: resource_type, resource_name: resource_name,
-      context: context, line_number: line_number) }
+                                                 resource_type: resource_type, resource_name: resource_name,
+                                                 context: context, line_number: line_number) }
 
     before do
       allow(Chef::Audit::ControlData).to receive(:new).
         with(name: name, resource_type: resource_type,
-          resource_name: resource_name, context: context,
-          line_number: line_number).
+             resource_name: resource_name, context: context,
+             line_number: line_number).
         and_return(control)
     end
   end
@@ -433,9 +432,9 @@ describe Chef::Audit::ControlGroupData do
 
       context "with multiple controls added" do
 
-        let(:control_hash_1) { {:line_number => 27} }
-        let(:control_hash_2) { {:line_number => 13} }
-        let(:control_hash_3) { {:line_number => 35} }
+        let(:control_hash_1) { { :line_number => 27 } }
+        let(:control_hash_2) { { :line_number => 13 } }
+        let(:control_hash_3) { { :line_number => 35 } }
 
         let(:control_1) { double("control 1",
           :line_number => control_hash_1[:line_number],
diff --git a/spec/unit/audit/logger_spec.rb b/spec/unit/audit/logger_spec.rb
new file mode 100644
index 0000000..51a32d9
--- /dev/null
+++ b/spec/unit/audit/logger_spec.rb
@@ -0,0 +1,42 @@
+#
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Audit::Logger do
+
+  before(:each) do
+    Chef::Audit::Logger.instance_variable_set(:@buffer, nil)
+  end
+
+  it "calling puts creates @buffer and adds the message" do
+    Chef::Audit::Logger.puts("Output message")
+    expect(Chef::Audit::Logger.read_buffer).to eq("Output message\n")
+  end
+
+  it "calling puts multiple times adds to the message" do
+    Chef::Audit::Logger.puts("Output message")
+    Chef::Audit::Logger.puts("Output message")
+    Chef::Audit::Logger.puts("Output message")
+    expect(Chef::Audit::Logger.read_buffer).to eq("Output message\nOutput message\nOutput message\n")
+  end
+
+  it "calling it before @buffer is set returns an empty string" do
+    expect(Chef::Audit::Logger.read_buffer).to eq("")
+  end
+
+end
diff --git a/spec/unit/audit/rspec_formatter_spec.rb b/spec/unit/audit/rspec_formatter_spec.rb
index 471473e..8c266fb 100644
--- a/spec/unit/audit/rspec_formatter_spec.rb
+++ b/spec/unit/audit/rspec_formatter_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Author:: Claire McQuin (<claire at getchef.com>)
+# Author:: Claire McQuin (<claire at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/audit/rspec_formatter'
+require "spec_helper"
+require "chef/audit/rspec_formatter"
 
 describe Chef::Audit::RspecFormatter do
   let(:formatter) { Chef::Audit::RspecFormatter.new(nil) }
diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb
index 0bd4c18..4c03cab 100644
--- a/spec/unit/audit/runner_spec.rb
+++ b/spec/unit/audit/runner_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'rspec/core/sandbox'
-require 'chef/audit/runner'
-require 'chef/audit/audit_event_proxy'
-require 'chef/audit/rspec_formatter'
-require 'rspec/support/spec/in_sub_process'
-require 'rspec/support/spec/stderr_splitter'
-
+require "spec_helper"
+require "rspec/core/sandbox"
+require "chef/audit/runner"
+require "chef/audit/audit_event_proxy"
+require "chef/audit/rspec_formatter"
+require "rspec/support/spec/in_sub_process"
+require "rspec/support/spec/stderr_splitter"
 
 describe Chef::Audit::Runner do
   include RSpec::Support::InSubProcess
@@ -54,7 +53,7 @@ describe Chef::Audit::Runner do
   context "during #run" do
 
     describe "#setup" do
-      let(:log_location) { File.join(Dir.tmpdir, 'audit_log') }
+      let(:log_location) { File.join(Dir.tmpdir, "audit_log") }
       let(:color) { false }
 
       before do
@@ -68,8 +67,8 @@ describe Chef::Audit::Runner do
         in_sub_process do
           runner.send(:setup)
 
-          expect(RSpec.configuration.output_stream).to eq(log_location)
-          expect(RSpec.configuration.error_stream).to eq(log_location)
+          expect(RSpec.configuration.output_stream).to eq(Chef::Audit::Logger)
+          expect(RSpec.configuration.error_stream).to eq(Chef::Audit::Logger)
 
           expect(RSpec.configuration.formatters.size).to eq(2)
           expect(RSpec.configuration.formatters).to include(instance_of(Chef::Audit::AuditEventProxy))
@@ -100,8 +99,8 @@ describe Chef::Audit::Runner do
       end
 
       context "audits exist" do
-        let(:audits) { {"audit_name" => group} }
-        let(:group) {Struct.new(:args, :block).new(["group_name"], nil)}
+        let(:audits) { { "audit_name" => group } }
+        let(:group) { Struct.new(:args, :block).new(["group_name"], nil) }
 
         it "sends the audits to the world" do
           runner.send(:register_control_groups)
diff --git a/spec/unit/chef_class_spec.rb b/spec/unit/chef_class_spec.rb
index 2528246..3c1200e 100644
--- a/spec/unit/chef_class_spec.rb
+++ b/spec/unit/chef_class_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe "Chef class" do
   let(:platform) { "debian" }
 
   let(:node) do
     node = Chef::Node.new
-    node.automatic['platform'] = platform
+    node.automatic["platform"] = platform
     node
   end
 
@@ -46,10 +46,6 @@ describe "Chef class" do
     Chef.set_provider_priority_map(provider_priority_map)
   end
 
-  after do
-    Chef.reset!
-  end
-
   context "priority maps" do
     context "#get_provider_priority_array" do
       it "should use the current node to get the right priority_map" do
@@ -88,4 +84,27 @@ describe "Chef class" do
       expect(Chef.node).to eql(node)
     end
   end
+
+  context '#event_handler' do
+    it "adds a new handler" do
+      x = 1
+      Chef.event_handler do
+        on :converge_start do
+          x = 2
+        end
+      end
+      expect(Chef::Config[:event_handlers]).to_not be_empty
+      Chef::Config[:event_handlers].first.send(:converge_start)
+      expect(x).to eq(2)
+    end
+
+    it "raise error if unknown event type is passed" do
+      expect do
+        Chef.event_handler do
+          on :yolo do
+          end
+        end
+      end.to raise_error(Chef::Exceptions::InvalidEventType)
+    end
+  end
 end
diff --git a/spec/unit/chef_fs/config_spec.rb b/spec/unit/chef_fs/config_spec.rb
index c7c47ad..2f65b6d 100644
--- a/spec/unit/chef_fs/config_spec.rb
+++ b/spec/unit/chef_fs/config_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Jess Mink (<jmink at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Jess Mink (<jmink at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/exceptions'
-require 'lib/chef/chef_fs/config.rb'
+require "spec_helper"
+require "chef/exceptions"
+require "lib/chef/chef_fs/config.rb"
 
 describe Chef::ChefFS::Config do
   describe "initialize" do
     it "warns when hosted setups use 'everything'" do
       base_config = Hash.new()
-      base_config[:repo_mode] = 'everything'
-      base_config[:chef_server_url] = 'http://foo.com/organizations/fake_org/'
+      base_config[:repo_mode] = "everything"
+      base_config[:chef_server_url] = "http://foo.com/organizations/fake_org/"
 
       ui = double("ui")
       expect(ui).to receive(:warn)
@@ -35,8 +35,8 @@ describe Chef::ChefFS::Config do
 
     it "doesn't warn when hosted setups use 'hosted_everything'" do
       base_config = Hash.new()
-      base_config[:repo_mode] = 'hosted_everything'
-      base_config[:chef_server_url] = 'http://foo.com/organizations/fake_org/'
+      base_config[:repo_mode] = "hosted_everything"
+      base_config[:chef_server_url] = "http://foo.com/organizations/fake_org/"
 
       ui = double("ui")
       expect(ui).to receive(:warn).exactly(0).times
@@ -46,8 +46,8 @@ describe Chef::ChefFS::Config do
 
     it "doesn't warn when non-hosted setups use 'everything'" do
       base_config = Hash.new()
-      base_config[:repo_mode] = 'everything'
-      base_config[:chef_server_url] = 'http://foo.com/'
+      base_config[:repo_mode] = "everything"
+      base_config[:chef_server_url] = "http://foo.com/"
 
       ui = double("ui")
       expect(ui).to receive(:warn).exactly(0).times
@@ -67,11 +67,11 @@ describe Chef::ChefFS::Config do
         node_path: "/base_path/nodes",
         role_path: "/base_path/roles",
         user_path: "/base_path/users",
-        policy_path: "/base_path/policies"
-      })
+        policy_path: "/base_path/policies",
+      },)
     end
 
-    let(:chef_fs_config)  { Chef::ChefFS::Config.new(chef_config, Dir.pwd) }
+    let(:chef_fs_config) { Chef::ChefFS::Config.new(chef_config, Dir.pwd) }
 
     subject(:local_fs) { chef_fs_config.local_fs }
 
@@ -102,9 +102,5 @@ describe Chef::ChefFS::Config do
     it "sets the correct user path on the local FS object" do
       expect(local_fs.child_paths["users"]).to eq([platform_path("/base_path/users")])
     end
-
-    it "sets the correct policy path on the local FS object" do
-      expect(local_fs.child_paths["policies"]).to eq([platform_path("/base_path/policies")])
-    end
   end
 end
diff --git a/spec/unit/chef_fs/data_handler/group_handler_spec.rb b/spec/unit/chef_fs/data_handler/group_handler_spec.rb
index 5f14646..849bc84 100644
--- a/spec/unit/chef_fs/data_handler/group_handler_spec.rb
+++ b/spec/unit/chef_fs/data_handler/group_handler_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Ryan Cragun (<ryan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Ryan Cragun (<ryan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'lib/chef/chef_fs/data_handler/group_data_handler'
+require "spec_helper"
+require "lib/chef/chef_fs/data_handler/group_data_handler"
 
 class TestEntry < Mash
   attr_accessor :name, :org
@@ -31,32 +31,32 @@ end
 describe Chef::ChefFS::DataHandler::GroupDataHandler do
   describe '#normalize_for_post' do
     let(:entry) do
-      TestEntry.new('workers.json', 'hive')
+      TestEntry.new("workers.json", "hive")
     end
 
     let(:group) do
-      { 'name' => 'worker_bees',
-        'clients' => %w(honey sting),
-        'users' => %w(fizz buzz),
-        'actors' => %w(honey)
+      { "name" => "worker_bees",
+        "clients" => %w{honey sting},
+        "users" => %w{fizz buzz},
+        "actors" => %w{honey},
       }
     end
 
     let(:normalized) do
-      { 'actors' =>
-          { 'users' => %w(fizz buzz),
-            'clients'=> %w(honey sting),
-            'groups'=> []
+      { "actors" =>
+          { "users" => %w{fizz buzz},
+            "clients" => %w{honey sting},
+            "groups" => [],
           },
-        'groupname' => 'workers',
-        'name' => 'worker_bees',
-        'orgname' => 'hive'
+        "groupname" => "workers",
+        "name" => "worker_bees",
+        "orgname" => "hive",
       }
     end
 
     let(:handler) { described_class.new }
 
-    it 'normalizes the users, clients and groups into actors' do
+    it "normalizes the users, clients and groups into actors" do
       expect(handler.normalize_for_post(group, entry)).to eq(normalized)
     end
   end
diff --git a/spec/unit/chef_fs/diff_spec.rb b/spec/unit/chef_fs/diff_spec.rb
index 7160539..c1c9050 100644
--- a/spec/unit/chef_fs/diff_spec.rb
+++ b/spec/unit/chef_fs/diff_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,24 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/chef_fs/file_pattern'
-require 'chef/chef_fs/command_line'
+require "spec_helper"
+require "chef/chef_fs/file_pattern"
+require "chef/chef_fs/command_line"
 
 # Removes the date stamp from the diff and replaces it with ' DATE'
 # example match: "/dev/null\t2012-10-16 16:15:54.000000000 +0000"
 # windows match: "--- /dev/null\tTue Oct 16 18:04:34 2012"
 def remove_os_differences(diff)
   diff = diff.gsub(/([+-]{3}.*)\t.*/, '\1 DATE')
-  diff.gsub(/^@@ -\d(,\d)? \+\d(,\d)? @@/, 'CONTEXT_LINE_NUMBERS')
+  diff.gsub(/^@@ -\d(,\d)? \+\d(,\d)? @@/, "CONTEXT_LINE_NUMBERS")
 end
 
-describe 'diff', :uses_diff => true do
+describe "diff", :uses_diff => true do
   include FileSystemSupport
 
-  context 'with two filesystems with all types of difference' do
+  context "with two filesystems with all types of difference" do
     let(:a) {
-      memory_fs('a', {
+      memory_fs("a", {
         :both_dirs => {
           :sub_both_dirs => { :subsub => nil },
           :sub_both_files => nil,
@@ -44,7 +44,7 @@ describe 'diff', :uses_diff => true do
           :sub_a_only_dir => { :subsub => nil },
           :sub_a_only_file => nil,
           :sub_dir_in_a_file_in_b => {},
-          :sub_file_in_a_dir_in_b => nil
+          :sub_file_in_a_dir_in_b => nil,
         },
         :both_files => nil,
         :both_files_different => "a\n",
@@ -56,11 +56,11 @@ describe 'diff', :uses_diff => true do
         :a_only_dir => { :subsub => nil },
         :a_only_file => nil,
         :dir_in_a_file_in_b => {},
-        :file_in_a_dir_in_b => nil
+        :file_in_a_dir_in_b => nil,
       }, /cannot_be_in_a/)
     }
     let(:b) {
-      memory_fs('b', {
+      memory_fs("b", {
         :both_dirs => {
           :sub_both_dirs => { :subsub => nil },
           :sub_both_files => nil,
@@ -71,7 +71,7 @@ describe 'diff', :uses_diff => true do
           :sub_b_only_dir => { :subsub => nil },
           :sub_b_only_file => nil,
           :sub_dir_in_a_file_in_b => nil,
-          :sub_file_in_a_dir_in_b => {}
+          :sub_file_in_a_dir_in_b => {},
         },
         :both_files => nil,
         :both_files_different => "b\n",
@@ -83,12 +83,12 @@ describe 'diff', :uses_diff => true do
         :b_only_dir => { :subsub => nil },
         :b_only_file => nil,
         :dir_in_a_file_in_b => nil,
-        :file_in_a_dir_in_b => {}
+        :file_in_a_dir_in_b => {},
       }, /cannot_be_in_b/)
     }
-    it 'Chef::ChefFS::CommandLine.diff_print(/)' do
+    it "Chef::ChefFS::CommandLine.diff_print(/)" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, nil) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, nil) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
@@ -98,63 +98,63 @@ describe 'diff', :uses_diff => true do
 CONTEXT_LINE_NUMBERS
 -a
 +b
-','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
 new file
 --- /dev/null DATE
 +++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE
 CONTEXT_LINE_NUMBERS
 +subsub
-','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
 deleted file
 --- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -subsub
-','Only in a/both_dirs: sub_a_only_dir
-','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
+', "Only in a/both_dirs: sub_a_only_dir
+", 'diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
 deleted file
 --- a/both_dirs/sub_a_only_file DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -sub_a_only_file
-','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
-','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
-','Only in b/both_dirs: sub_b_only_dir
-','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
+', "File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
+", "File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
+", "Only in b/both_dirs: sub_b_only_dir
+", 'diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
 new file
 --- /dev/null DATE
 +++ b/both_dirs/sub_b_only_file DATE
 CONTEXT_LINE_NUMBERS
 +sub_b_only_file
-','diff --knife a/both_files_different b/both_files_different
+', 'diff --knife a/both_files_different b/both_files_different
 --- a/both_files_different DATE
 +++ b/both_files_different DATE
 CONTEXT_LINE_NUMBERS
 -a
 +b
-','diff --knife a/dirs_empty_in_a_filled_in_b/subsub b/dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/dirs_empty_in_a_filled_in_b/subsub b/dirs_empty_in_a_filled_in_b/subsub
 new file
 --- /dev/null DATE
 +++ b/dirs_empty_in_a_filled_in_b/subsub DATE
 CONTEXT_LINE_NUMBERS
 +subsub
-','diff --knife a/dirs_empty_in_b_filled_in_a/subsub b/dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/dirs_empty_in_b_filled_in_a/subsub b/dirs_empty_in_b_filled_in_a/subsub
 deleted file
 --- a/dirs_empty_in_b_filled_in_a/subsub DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -subsub
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
 deleted file
 --- a/a_only_file DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
 new file
 --- /dev/null DATE
 +++ b/b_only_file DATE
@@ -162,9 +162,9 @@ CONTEXT_LINE_NUMBERS
 +b_only_file
 ' ])
     end
-    it 'Chef::ChefFS::CommandLine.diff_print(/both_dirs)' do
+    it "Chef::ChefFS::CommandLine.diff_print(/both_dirs)" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/both_dirs'), a, b, nil, nil) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/both_dirs"), a, b, nil, nil) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
@@ -174,29 +174,29 @@ CONTEXT_LINE_NUMBERS
 CONTEXT_LINE_NUMBERS
 -a
 +b
-','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub
 new file
 --- /dev/null DATE
 +++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE
 CONTEXT_LINE_NUMBERS
 +subsub
-','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
+', 'diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub
 deleted file
 --- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -subsub
-','Only in a/both_dirs: sub_a_only_dir
-','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
+', "Only in a/both_dirs: sub_a_only_dir
+", 'diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file
 deleted file
 --- a/both_dirs/sub_a_only_file DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -sub_a_only_file
-','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
-','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
-','Only in b/both_dirs: sub_b_only_dir
-','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
+', "File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file
+", "File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory
+", "Only in b/both_dirs: sub_b_only_dir
+", 'diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file
 new file
 --- /dev/null DATE
 +++ b/both_dirs/sub_b_only_file DATE
@@ -204,33 +204,33 @@ CONTEXT_LINE_NUMBERS
 +sub_b_only_file
 ' ])
     end
-    it 'Chef::ChefFS::CommandLine.diff_print(/) with depth 1' do
+    it "Chef::ChefFS::CommandLine.diff_print(/) with depth 1" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, 1, nil) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, 1, nil) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
-'Common subdirectories: b/both_dirs
-','diff --knife a/both_files_different b/both_files_different
+"Common subdirectories: b/both_dirs
+", 'diff --knife a/both_files_different b/both_files_different
 --- a/both_files_different DATE
 +++ b/both_files_different DATE
 CONTEXT_LINE_NUMBERS
 -a
 +b
-','Common subdirectories: b/both_dirs_empty
-','Common subdirectories: b/dirs_empty_in_b_filled_in_a
-','Common subdirectories: b/dirs_empty_in_a_filled_in_b
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Common subdirectories: b/both_dirs_empty
+", "Common subdirectories: b/dirs_empty_in_b_filled_in_a
+", "Common subdirectories: b/dirs_empty_in_a_filled_in_b
+", "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
 deleted file
 --- a/a_only_file DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
 new file
 --- /dev/null DATE
 +++ b/b_only_file DATE
@@ -238,33 +238,33 @@ CONTEXT_LINE_NUMBERS
 +b_only_file
 ' ])
     end
-    it 'Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0' do
+    it "Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/*_*'), a, b, 0, nil) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/*_*"), a, b, 0, nil) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
-'Common subdirectories: b/both_dirs
-','diff --knife a/both_files_different b/both_files_different
+"Common subdirectories: b/both_dirs
+", 'diff --knife a/both_files_different b/both_files_different
 --- a/both_files_different DATE
 +++ b/both_files_different DATE
 CONTEXT_LINE_NUMBERS
 -a
 +b
-','Common subdirectories: b/both_dirs_empty
-','Common subdirectories: b/dirs_empty_in_b_filled_in_a
-','Common subdirectories: b/dirs_empty_in_a_filled_in_b
-','Only in a: a_only_dir
-','diff --knife a/a_only_file b/a_only_file
+', "Common subdirectories: b/both_dirs_empty
+", "Common subdirectories: b/dirs_empty_in_b_filled_in_a
+", "Common subdirectories: b/dirs_empty_in_a_filled_in_b
+", "Only in a: a_only_dir
+", 'diff --knife a/a_only_file b/a_only_file
 deleted file
 --- a/a_only_file DATE
 +++ /dev/null DATE
 CONTEXT_LINE_NUMBERS
 -a_only_file
-','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
-','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
-','Only in b: b_only_dir
-','diff --knife a/b_only_file b/b_only_file
+', "File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file
+", "File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory
+", "Only in b: b_only_dir
+", 'diff --knife a/b_only_file b/b_only_file
 new file
 --- /dev/null DATE
 +++ b/b_only_file DATE
@@ -272,9 +272,9 @@ CONTEXT_LINE_NUMBERS
 +b_only_file
 ' ])
     end
-    it 'Chef::ChefFS::CommandLine.diff_print(/) in name-only mode' do
+    it "Chef::ChefFS::CommandLine.diff_print(/) in name-only mode" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_only) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, :name_only) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
@@ -295,12 +295,12 @@ CONTEXT_LINE_NUMBERS
           "b/b_only_dir\n",
           "b/b_only_file\n",
           "b/dir_in_a_file_in_b\n",
-          "b/file_in_a_dir_in_b\n"
+          "b/file_in_a_dir_in_b\n",
       ])
     end
-    it 'Chef::ChefFS::CommandLine.diff_print(/) in name-status mode' do
+    it "Chef::ChefFS::CommandLine.diff_print(/) in name-status mode" do
       results = []
-      Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_status) do |diff|
+      Chef::ChefFS::CommandLine.diff_print(pattern("/"), a, b, nil, :name_status) do |diff|
         results << remove_os_differences(diff)
       end
       expect(results).to match_array([
@@ -321,7 +321,7 @@ CONTEXT_LINE_NUMBERS
           "A\tb/b_only_dir\n",
           "A\tb/b_only_file\n",
           "T\tb/dir_in_a_file_in_b\n",
-          "T\tb/file_in_a_dir_in_b\n"
+          "T\tb/file_in_a_dir_in_b\n",
       ])
     end
   end
diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb
index a9f06e8..c4d076e 100644
--- a/spec/unit/chef_fs/file_pattern_spec.rb
+++ b/spec/unit/chef_fs/file_pattern_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/chef_fs/file_pattern'
+require "spec_helper"
+require "chef/chef_fs/file_pattern"
 
 describe Chef::ChefFS::FilePattern do
   def p(str)
@@ -26,471 +26,458 @@ describe Chef::ChefFS::FilePattern do
 
   # Different kinds of patterns
   context 'with empty pattern ""' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('') }
-    it 'match?' do
-      expect(pattern.match?('')).to be_truthy
-      expect(pattern.match?('/')).to be_falsey
-      expect(pattern.match?('a')).to be_falsey
-      expect(pattern.match?('a/b')).to be_falsey
+    let(:pattern) { Chef::ChefFS::FilePattern.new("") }
+    it "match?" do
+      expect(pattern.match?("")).to be_truthy
+      expect(pattern.match?("/")).to be_falsey
+      expect(pattern.match?("a")).to be_falsey
+      expect(pattern.match?("a/b")).to be_falsey
     end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('')
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("")
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('')).to be_falsey
-      expect(pattern.could_match_children?('a/b')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("")).to be_falsey
+      expect(pattern.could_match_children?("a/b")).to be_falsey
     end
   end
 
   context 'with root pattern "/"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/') }
-    it 'match?' do
-      expect(pattern.match?('/')).to be_truthy
-      expect(pattern.match?('')).to be_falsey
-      expect(pattern.match?('a')).to be_falsey
-      expect(pattern.match?('/a')).to be_falsey
-    end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('/')
-    end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('')).to be_falsey
-      expect(pattern.could_match_children?('/')).to be_falsey
-      expect(pattern.could_match_children?('a')).to be_falsey
-      expect(pattern.could_match_children?('a/b')).to be_falsey
-      expect(pattern.could_match_children?('/a')).to be_falsey
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/") }
+    it "match?" do
+      expect(pattern.match?("/")).to be_truthy
+      expect(pattern.match?("")).to be_falsey
+      expect(pattern.match?("a")).to be_falsey
+      expect(pattern.match?("/a")).to be_falsey
+    end
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("/")
+    end
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("")).to be_falsey
+      expect(pattern.could_match_children?("/")).to be_falsey
+      expect(pattern.could_match_children?("a")).to be_falsey
+      expect(pattern.could_match_children?("a/b")).to be_falsey
+      expect(pattern.could_match_children?("/a")).to be_falsey
     end
   end
 
   context 'with simple pattern "abc"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('abc') }
-    it 'match?' do
-      expect(pattern.match?('abc')).to be_truthy
-      expect(pattern.match?('a')).to be_falsey
-      expect(pattern.match?('abcd')).to be_falsey
-      expect(pattern.match?('/abc')).to be_falsey
-      expect(pattern.match?('')).to be_falsey
-      expect(pattern.match?('/')).to be_falsey
-    end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('abc')
-    end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc')).to be_falsey
+    let(:pattern) { Chef::ChefFS::FilePattern.new("abc") }
+    it "match?" do
+      expect(pattern.match?("abc")).to be_truthy
+      expect(pattern.match?("a")).to be_falsey
+      expect(pattern.match?("abcd")).to be_falsey
+      expect(pattern.match?("/abc")).to be_falsey
+      expect(pattern.match?("")).to be_falsey
+      expect(pattern.match?("/")).to be_falsey
+    end
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("abc")
+    end
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc")).to be_falsey
     end
   end
 
   context 'with simple pattern "/abc"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc') }
-    it 'match?' do
-      expect(pattern.match?('/abc')).to be_truthy
-      expect(pattern.match?('abc')).to be_falsey
-      expect(pattern.match?('a')).to be_falsey
-      expect(pattern.match?('abcd')).to be_falsey
-      expect(pattern.match?('')).to be_falsey
-      expect(pattern.match?('/')).to be_falsey
-    end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('/abc')
-    end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc')).to be_falsey
-      expect(pattern.could_match_children?('/')).to be_truthy
-      expect(pattern.could_match_children?('')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc") }
+    it "match?" do
+      expect(pattern.match?("/abc")).to be_truthy
+      expect(pattern.match?("abc")).to be_falsey
+      expect(pattern.match?("a")).to be_falsey
+      expect(pattern.match?("abcd")).to be_falsey
+      expect(pattern.match?("")).to be_falsey
+      expect(pattern.match?("/")).to be_falsey
+    end
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("/abc")
+    end
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc")).to be_falsey
+      expect(pattern.could_match_children?("/")).to be_truthy
+      expect(pattern.could_match_children?("")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
     end
   end
 
   context 'with simple pattern "abc/def/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('abc/def/ghi') }
-    it 'match?' do
-      expect(pattern.match?('abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/def/ghi')).to be_falsey
-      expect(pattern.match?('abc')).to be_falsey
-      expect(pattern.match?('abc/def')).to be_falsey
-    end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('abc/def/ghi')
-    end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('abc')).to be_truthy
-      expect(pattern.could_match_children?('xyz')).to be_falsey
-      expect(pattern.could_match_children?('/abc')).to be_falsey
-      expect(pattern.could_match_children?('abc/def')).to be_truthy
-      expect(pattern.could_match_children?('abc/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc/def/ghi')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('abc')).to eq('def')
-      expect(pattern.exact_child_name_under('abc/def')).to eq('ghi')
+    let(:pattern) { Chef::ChefFS::FilePattern.new("abc/def/ghi") }
+    it "match?" do
+      expect(pattern.match?("abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/def/ghi")).to be_falsey
+      expect(pattern.match?("abc")).to be_falsey
+      expect(pattern.match?("abc/def")).to be_falsey
+    end
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("abc/def/ghi")
+    end
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("abc")).to be_truthy
+      expect(pattern.could_match_children?("xyz")).to be_falsey
+      expect(pattern.could_match_children?("/abc")).to be_falsey
+      expect(pattern.could_match_children?("abc/def")).to be_truthy
+      expect(pattern.could_match_children?("abc/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc/def/ghi")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("abc")).to eq("def")
+      expect(pattern.exact_child_name_under("abc/def")).to eq("ghi")
     end
   end
 
   context 'with simple pattern "/abc/def/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/def/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('abc/def/ghi')).to be_falsey
-      expect(pattern.match?('/abc')).to be_falsey
-      expect(pattern.match?('/abc/def')).to be_falsey
-    end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('/abc/def/ghi')
-    end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def')).to be_truthy
-      expect(pattern.could_match_children?('/abc/xyz')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq('def')
-      expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/def/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("abc/def/ghi")).to be_falsey
+      expect(pattern.match?("/abc")).to be_falsey
+      expect(pattern.match?("/abc/def")).to be_falsey
+    end
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("/abc/def/ghi")
+    end
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def")).to be_truthy
+      expect(pattern.could_match_children?("/abc/xyz")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq("def")
+      expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
     end
   end
 
-  context 'with simple pattern "a\*\b"', :pending => (Chef::Platform.windows?) do
+  context 'with simple pattern "a\*\b"', :skip => (Chef::Platform.windows?) do
     let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') }
-    it 'match?' do
-      expect(pattern.match?('a*b')).to be_truthy
-      expect(pattern.match?('ab')).to be_falsey
-      expect(pattern.match?('acb')).to be_falsey
-      expect(pattern.match?('ab')).to be_falsey
+    it "match?" do
+      expect(pattern.match?("a*b")).to be_truthy
+      expect(pattern.match?("ab")).to be_falsey
+      expect(pattern.match?("acb")).to be_falsey
+      expect(pattern.match?("ab")).to be_falsey
     end
-    it 'exact_path' do
-      expect(pattern.exact_path).to eq('a*b')
+    it "exact_path" do
+      expect(pattern.exact_path).to eq("a*b")
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('a/*b')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("a/*b")).to be_falsey
     end
   end
 
   context 'with star pattern "/abc/*/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/*/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/ghi')).to be_falsey
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/*/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/ghi")).to be_falsey
     end
-    it 'exact_path' do
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def')).to be_truthy
-      expect(pattern.could_match_children?('/abc/xyz')).to be_truthy
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def")).to be_truthy
+      expect(pattern.could_match_children?("/abc/xyz")).to be_truthy
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
     end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
     end
   end
 
   context 'with star pattern "/abc/d*f/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d*f/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/dxf/ghi')).to be_truthy
-      expect(pattern.match?('/abc/df/ghi')).to be_truthy
-      expect(pattern.match?('/abc/dxyzf/ghi')).to be_truthy
-      expect(pattern.match?('/abc/d/ghi')).to be_falsey
-      expect(pattern.match?('/abc/f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/ghi')).to be_falsey
-      expect(pattern.match?('/abc/xyz/ghi')).to be_falsey
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d*f/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/dxf/ghi")).to be_truthy
+      expect(pattern.match?("/abc/df/ghi")).to be_truthy
+      expect(pattern.match?("/abc/dxyzf/ghi")).to be_truthy
+      expect(pattern.match?("/abc/d/ghi")).to be_falsey
+      expect(pattern.match?("/abc/f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/ghi")).to be_falsey
+      expect(pattern.match?("/abc/xyz/ghi")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def')).to be_truthy
-      expect(pattern.could_match_children?('/abc/xyz')).to be_falsey
-      expect(pattern.could_match_children?('/abc/dxyzf')).to be_truthy
-      expect(pattern.could_match_children?('/abc/df')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d')).to be_falsey
-      expect(pattern.could_match_children?('/abc/f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/def')).to eq('ghi')
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def")).to be_truthy
+      expect(pattern.could_match_children?("/abc/xyz")).to be_falsey
+      expect(pattern.could_match_children?("/abc/dxyzf")).to be_truthy
+      expect(pattern.could_match_children?("/abc/df")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d")).to be_falsey
+      expect(pattern.could_match_children?("/abc/f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/def")).to eq("ghi")
     end
   end
 
   context 'with star pattern "/abc/d??f/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d??f/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/deef/ghi')).to be_truthy
-      expect(pattern.match?('/abc/deeef/ghi')).to be_falsey
-      expect(pattern.match?('/abc/def/ghi')).to be_falsey
-      expect(pattern.match?('/abc/df/ghi')).to be_falsey
-      expect(pattern.match?('/abc/d/ghi')).to be_falsey
-      expect(pattern.match?('/abc/f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/ghi')).to be_falsey
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d??f/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/deef/ghi")).to be_truthy
+      expect(pattern.match?("/abc/deeef/ghi")).to be_falsey
+      expect(pattern.match?("/abc/def/ghi")).to be_falsey
+      expect(pattern.match?("/abc/df/ghi")).to be_falsey
+      expect(pattern.match?("/abc/d/ghi")).to be_falsey
+      expect(pattern.match?("/abc/f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/ghi")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc/deef')).to be_truthy
-      expect(pattern.could_match_children?('/abc/deeef')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def')).to be_falsey
-      expect(pattern.could_match_children?('/abc/df')).to be_falsey
-      expect(pattern.could_match_children?('/abc/d')).to be_falsey
-      expect(pattern.could_match_children?('/abc/f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/deef/ghi')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/deef')).to eq('ghi')
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc/deef")).to be_truthy
+      expect(pattern.could_match_children?("/abc/deeef")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def")).to be_falsey
+      expect(pattern.could_match_children?("/abc/df")).to be_falsey
+      expect(pattern.could_match_children?("/abc/d")).to be_falsey
+      expect(pattern.could_match_children?("/abc/f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/deef/ghi")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/deef")).to eq("ghi")
     end
   end
 
-  context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :pending => (Chef::Platform.windows?) do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d[a-z][0-9]f/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/de1f/ghi')).to be_truthy
-      expect(pattern.match?('/abc/deef/ghi')).to be_falsey
-      expect(pattern.match?('/abc/d11f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/de11f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/dee1f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/df/ghi')).to be_falsey
-      expect(pattern.match?('/abc/d/ghi')).to be_falsey
-      expect(pattern.match?('/abc/f/ghi')).to be_falsey
-      expect(pattern.match?('/abc/ghi')).to be_falsey
-    end
-    it 'exact_path' do
+  context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :skip => (Chef::Platform.windows?) do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/d[a-z][0-9]f/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/de1f/ghi")).to be_truthy
+      expect(pattern.match?("/abc/deef/ghi")).to be_falsey
+      expect(pattern.match?("/abc/d11f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/de11f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/dee1f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/df/ghi")).to be_falsey
+      expect(pattern.match?("/abc/d/ghi")).to be_falsey
+      expect(pattern.match?("/abc/f/ghi")).to be_falsey
+      expect(pattern.match?("/abc/ghi")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/abc/de1f')).to be_truthy
-      expect(pattern.could_match_children?('/abc/deef')).to be_falsey
-      expect(pattern.could_match_children?('/abc/d11f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/de11f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/dee1f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/def')).to be_falsey
-      expect(pattern.could_match_children?('/abc/df')).to be_falsey
-      expect(pattern.could_match_children?('/abc/d')).to be_falsey
-      expect(pattern.could_match_children?('/abc/f')).to be_falsey
-      expect(pattern.could_match_children?('/abc/de1f/ghi')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/de1f')).to eq('ghi')
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/abc/de1f")).to be_truthy
+      expect(pattern.could_match_children?("/abc/deef")).to be_falsey
+      expect(pattern.could_match_children?("/abc/d11f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/de11f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/dee1f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/def")).to be_falsey
+      expect(pattern.could_match_children?("/abc/df")).to be_falsey
+      expect(pattern.could_match_children?("/abc/d")).to be_falsey
+      expect(pattern.could_match_children?("/abc/f")).to be_falsey
+      expect(pattern.could_match_children?("/abc/de1f/ghi")).to be_falsey
+    end
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/de1f")).to eq("ghi")
     end
   end
 
   context 'with star pattern "/abc/**/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
-      expect(pattern.match?('/abc/ghi')).to be_falsey
-      expect(pattern.match?('/abcdef/d/ghi')).to be_falsey
-      expect(pattern.match?('/abc/d/defghi')).to be_falsey
-      expect(pattern.match?('/xyz')).to be_falsey
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/**/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+      expect(pattern.match?("/abc/ghi")).to be_falsey
+      expect(pattern.match?("/abcdef/d/ghi")).to be_falsey
+      expect(pattern.match?("/abc/d/defghi")).to be_falsey
+      expect(pattern.match?("/xyz")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
     end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
     end
   end
 
   context 'with star pattern "/abc**/ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc**/ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
-      expect(pattern.match?('/abc/ghi')).to be_truthy
-      expect(pattern.match?('/abcdef/ghi')).to be_truthy
-      expect(pattern.match?('/abc/defghi')).to be_falsey
-      expect(pattern.match?('/xyz')).to be_falsey
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc**/ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+      expect(pattern.match?("/abc/ghi")).to be_truthy
+      expect(pattern.match?("/abcdef/ghi")).to be_truthy
+      expect(pattern.match?("/abc/defghi")).to be_falsey
+      expect(pattern.match?("/xyz")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/abcdef')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
-      expect(pattern.could_match_children?('abc')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/abcdef")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+      expect(pattern.could_match_children?("abc")).to be_falsey
     end
-    it 'could_match_children? /abc** returns false for /xyz' do
-      pending 'Make could_match_children? more rigorous'
-      # At the moment, we return false for this, but in the end it would be nice to return true:
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
-    end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
     end
   end
 
   context 'with star pattern "/abc/**ghi"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**ghi') }
-    it 'match?' do
-      expect(pattern.match?('/abc/def/ghi')).to be_truthy
-      expect(pattern.match?('/abc/def/ghi/ghi')).to be_truthy
-      expect(pattern.match?('/abc/def/ghi/jkl')).to be_falsey
-      expect(pattern.match?('/abc/d/e/f/ghi')).to be_truthy
-      expect(pattern.match?('/abc/ghi')).to be_truthy
-      expect(pattern.match?('/abcdef/ghi')).to be_falsey
-      expect(pattern.match?('/abc/defghi')).to be_truthy
-      expect(pattern.match?('/xyz')).to be_falsey
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("/abc/**ghi") }
+    it "match?" do
+      expect(pattern.match?("/abc/def/ghi")).to be_truthy
+      expect(pattern.match?("/abc/def/ghi/ghi")).to be_truthy
+      expect(pattern.match?("/abc/def/ghi/jkl")).to be_falsey
+      expect(pattern.match?("/abc/d/e/f/ghi")).to be_truthy
+      expect(pattern.match?("/abc/ghi")).to be_truthy
+      expect(pattern.match?("/abcdef/ghi")).to be_falsey
+      expect(pattern.match?("/abc/defghi")).to be_truthy
+      expect(pattern.match?("/xyz")).to be_falsey
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
-    it 'could_match_children?' do
-      expect(pattern.could_match_children?('/abc')).to be_truthy
-      expect(pattern.could_match_children?('/abcdef')).to be_falsey
-      expect(pattern.could_match_children?('/abc/d/e')).to be_truthy
-      expect(pattern.could_match_children?('/abc/d/e/f')).to be_truthy
-      expect(pattern.could_match_children?('/abc/def/ghi')).to be_truthy
-      expect(pattern.could_match_children?('abc')).to be_falsey
-      expect(pattern.could_match_children?('/xyz')).to be_falsey
+    it "could_match_children?" do
+      expect(pattern.could_match_children?("/abc")).to be_truthy
+      expect(pattern.could_match_children?("/abcdef")).to be_falsey
+      expect(pattern.could_match_children?("/abc/d/e")).to be_truthy
+      expect(pattern.could_match_children?("/abc/d/e/f")).to be_truthy
+      expect(pattern.could_match_children?("/abc/def/ghi")).to be_truthy
+      expect(pattern.could_match_children?("abc")).to be_falsey
+      expect(pattern.could_match_children?("/xyz")).to be_falsey
     end
-    it 'exact_child_name_under' do
-      expect(pattern.exact_child_name_under('/')).to eq('abc')
-      expect(pattern.exact_child_name_under('/abc')).to eq(nil)
-      expect(pattern.exact_child_name_under('/abc/def')).to eq(nil)
+    it "exact_child_name_under" do
+      expect(pattern.exact_child_name_under("/")).to eq("abc")
+      expect(pattern.exact_child_name_under("/abc")).to eq(nil)
+      expect(pattern.exact_child_name_under("/abc/def")).to eq(nil)
     end
   end
 
   context 'with star pattern "a**b**c"' do
-    let(:pattern) { Chef::ChefFS::FilePattern.new('a**b**c') }
-    it 'match?' do
-      expect(pattern.match?('axybzwc')).to be_truthy
-      expect(pattern.match?('abc')).to be_truthy
-      expect(pattern.match?('axyzwc')).to be_falsey
-      expect(pattern.match?('ac')).to be_falsey
-      expect(pattern.match?('a/x/y/b/z/w/c')).to be_truthy
-    end
-    it 'exact_path' do
+    let(:pattern) { Chef::ChefFS::FilePattern.new("a**b**c") }
+    it "match?" do
+      expect(pattern.match?("axybzwc")).to be_truthy
+      expect(pattern.match?("abc")).to be_truthy
+      expect(pattern.match?("axyzwc")).to be_falsey
+      expect(pattern.match?("ac")).to be_falsey
+      expect(pattern.match?("a/x/y/b/z/w/c")).to be_truthy
+    end
+    it "exact_path" do
       expect(pattern.exact_path).to be_nil
     end
   end
 
-  context 'normalization tests' do
-    it 'handles trailing slashes' do
-      expect(p('abc/').normalized_pattern).to eq('abc')
-      expect(p('abc/').exact_path).to eq('abc')
-      expect(p('abc/').match?('abc')).to be_truthy
-      expect(p('//').normalized_pattern).to eq('/')
-      expect(p('//').exact_path).to eq('/')
-      expect(p('//').match?('/')).to be_truthy
-      expect(p('/./').normalized_pattern).to eq('/')
-      expect(p('/./').exact_path).to eq('/')
-      expect(p('/./').match?('/')).to be_truthy
-    end
-    it 'handles multiple slashes' do
-      expect(p('abc//def').normalized_pattern).to eq('abc/def')
-      expect(p('abc//def').exact_path).to eq('abc/def')
-      expect(p('abc//def').match?('abc/def')).to be_truthy
-      expect(p('abc//').normalized_pattern).to eq('abc')
-      expect(p('abc//').exact_path).to eq('abc')
-      expect(p('abc//').match?('abc')).to be_truthy
-    end
-    it 'handles dot' do
-      expect(p('abc/./def').normalized_pattern).to eq('abc/def')
-      expect(p('abc/./def').exact_path).to eq('abc/def')
-      expect(p('abc/./def').match?('abc/def')).to be_truthy
-      expect(p('./abc/def').normalized_pattern).to eq('abc/def')
-      expect(p('./abc/def').exact_path).to eq('abc/def')
-      expect(p('./abc/def').match?('abc/def')).to be_truthy
-      expect(p('/.').normalized_pattern).to eq('/')
-      expect(p('/.').exact_path).to eq('/')
-      expect(p('/.').match?('/')).to be_truthy
-    end
-    it 'handles dot by itself', :pending => "decide what to do with dot by itself" do
-      expect(p('.').normalized_pattern).to eq('.')
-      expect(p('.').exact_path).to eq('.')
-      expect(p('.').match?('.')).to be_truthy
-      expect(p('./').normalized_pattern).to eq('.')
-      expect(p('./').exact_path).to eq('.')
-      expect(p('./').match?('.')).to be_truthy
-    end
-    it 'handles dotdot' do
-      expect(p('abc/../def').normalized_pattern).to eq('def')
-      expect(p('abc/../def').exact_path).to eq('def')
-      expect(p('abc/../def').match?('def')).to be_truthy
-      expect(p('abc/def/../..').normalized_pattern).to eq('')
-      expect(p('abc/def/../..').exact_path).to eq('')
-      expect(p('abc/def/../..').match?('')).to be_truthy
-      expect(p('/*/../def').normalized_pattern).to eq('/def')
-      expect(p('/*/../def').exact_path).to eq('/def')
-      expect(p('/*/../def').match?('/def')).to be_truthy
-      expect(p('/*/*/../def').normalized_pattern).to eq('/*/def')
-      expect(p('/*/*/../def').exact_path).to be_nil
-      expect(p('/*/*/../def').match?('/abc/def')).to be_truthy
-      expect(p('/abc/def/../..').normalized_pattern).to eq('/')
-      expect(p('/abc/def/../..').exact_path).to eq('/')
-      expect(p('/abc/def/../..').match?('/')).to be_truthy
-      expect(p('abc/../../def').normalized_pattern).to eq('../def')
-      expect(p('abc/../../def').exact_path).to eq('../def')
-      expect(p('abc/../../def').match?('../def')).to be_truthy
-    end
-    it 'handles dotdot with double star' do
-      expect(p('abc**/def/../ghi').exact_path).to be_nil
-      expect(p('abc**/def/../ghi').match?('abc/ghi')).to be_truthy
-      expect(p('abc**/def/../ghi').match?('abc/x/y/z/ghi')).to be_truthy
-      expect(p('abc**/def/../ghi').match?('ghi')).to be_falsey
-    end
-    it 'raises error on dotdot with overlapping double star' do
-      expect { Chef::ChefFS::FilePattern.new('abc/**/../def').exact_path }.to raise_error(ArgumentError)
-      expect { Chef::ChefFS::FilePattern.new('abc/**/abc/../../def').exact_path }.to raise_error(ArgumentError)
-    end
-    it 'handles leading dotdot' do
-      expect(p('../abc/def').exact_path).to eq('../abc/def')
-      expect(p('../abc/def').match?('../abc/def')).to be_truthy
-      expect(p('/../abc/def').exact_path).to eq('/abc/def')
-      expect(p('/../abc/def').match?('/abc/def')).to be_truthy
-      expect(p('..').exact_path).to eq('..')
-      expect(p('..').match?('..')).to be_truthy
-      expect(p('/..').exact_path).to eq('/')
-      expect(p('/..').match?('/')).to be_truthy
+  context "normalization tests" do
+    it "handles trailing slashes" do
+      expect(p("abc/").normalized_pattern).to eq("abc")
+      expect(p("abc/").exact_path).to eq("abc")
+      expect(p("abc/").match?("abc")).to be_truthy
+      expect(p("//").normalized_pattern).to eq("/")
+      expect(p("//").exact_path).to eq("/")
+      expect(p("//").match?("/")).to be_truthy
+      expect(p("/./").normalized_pattern).to eq("/")
+      expect(p("/./").exact_path).to eq("/")
+      expect(p("/./").match?("/")).to be_truthy
+    end
+    it "handles multiple slashes" do
+      expect(p("abc//def").normalized_pattern).to eq("abc/def")
+      expect(p("abc//def").exact_path).to eq("abc/def")
+      expect(p("abc//def").match?("abc/def")).to be_truthy
+      expect(p("abc//").normalized_pattern).to eq("abc")
+      expect(p("abc//").exact_path).to eq("abc")
+      expect(p("abc//").match?("abc")).to be_truthy
+    end
+    it "handles dot" do
+      expect(p("abc/./def").normalized_pattern).to eq("abc/def")
+      expect(p("abc/./def").exact_path).to eq("abc/def")
+      expect(p("abc/./def").match?("abc/def")).to be_truthy
+      expect(p("./abc/def").normalized_pattern).to eq("abc/def")
+      expect(p("./abc/def").exact_path).to eq("abc/def")
+      expect(p("./abc/def").match?("abc/def")).to be_truthy
+      expect(p("/.").normalized_pattern).to eq("/")
+      expect(p("/.").exact_path).to eq("/")
+      expect(p("/.").match?("/")).to be_truthy
+    end
+    it "handles dotdot" do
+      expect(p("abc/../def").normalized_pattern).to eq("def")
+      expect(p("abc/../def").exact_path).to eq("def")
+      expect(p("abc/../def").match?("def")).to be_truthy
+      expect(p("abc/def/../..").normalized_pattern).to eq("")
+      expect(p("abc/def/../..").exact_path).to eq("")
+      expect(p("abc/def/../..").match?("")).to be_truthy
+      expect(p("/*/../def").normalized_pattern).to eq("/def")
+      expect(p("/*/../def").exact_path).to eq("/def")
+      expect(p("/*/../def").match?("/def")).to be_truthy
+      expect(p("/*/*/../def").normalized_pattern).to eq("/*/def")
+      expect(p("/*/*/../def").exact_path).to be_nil
+      expect(p("/*/*/../def").match?("/abc/def")).to be_truthy
+      expect(p("/abc/def/../..").normalized_pattern).to eq("/")
+      expect(p("/abc/def/../..").exact_path).to eq("/")
+      expect(p("/abc/def/../..").match?("/")).to be_truthy
+      expect(p("abc/../../def").normalized_pattern).to eq("../def")
+      expect(p("abc/../../def").exact_path).to eq("../def")
+      expect(p("abc/../../def").match?("../def")).to be_truthy
+    end
+    it "handles dotdot with double star" do
+      expect(p("abc**/def/../ghi").exact_path).to be_nil
+      expect(p("abc**/def/../ghi").match?("abc/ghi")).to be_truthy
+      expect(p("abc**/def/../ghi").match?("abc/x/y/z/ghi")).to be_truthy
+      expect(p("abc**/def/../ghi").match?("ghi")).to be_falsey
+    end
+    it "raises error on dotdot with overlapping double star" do
+      expect { Chef::ChefFS::FilePattern.new("abc/**/../def").exact_path }.to raise_error(ArgumentError)
+      expect { Chef::ChefFS::FilePattern.new("abc/**/abc/../../def").exact_path }.to raise_error(ArgumentError)
+    end
+    it "handles leading dotdot" do
+      expect(p("../abc/def").exact_path).to eq("../abc/def")
+      expect(p("../abc/def").match?("../abc/def")).to be_truthy
+      expect(p("/../abc/def").exact_path).to eq("/abc/def")
+      expect(p("/../abc/def").match?("/abc/def")).to be_truthy
+      expect(p("..").exact_path).to eq("..")
+      expect(p("..").match?("..")).to be_truthy
+      expect(p("/..").exact_path).to eq("/")
+      expect(p("/..").match?("/")).to be_truthy
     end
   end
 
-
   # match?
   #  - single element matches (empty, fixed, ?, *, characters, escapes)
   #  - nested matches
diff --git a/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb b/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb
new file mode 100644
index 0000000..92ea8d0
--- /dev/null
+++ b/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb
@@ -0,0 +1,34 @@
+#
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/chef_fs/file_system/chef_server/cookbook_subdir"
+
+describe Chef::ChefFS::FileSystem::ChefServer::CookbookSubdir do
+  let(:root) do
+    Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
+  end
+
+  let(:cookbook_subdir) do
+    Chef::ChefFS::FileSystem::ChefServer::CookbookSubdir.new("test", root, false, true)
+  end
+
+  it "can get child" do
+    cookbook_subdir.child("test")
+  end
+end
diff --git a/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb b/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
index 142755a..b0b5a54 100644
--- a/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
+++ b/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/chef_fs/file_system/operation_failed_error'
+require "spec_helper"
+require "chef/chef_fs/file_system/operation_failed_error"
 
 describe Chef::ChefFS::FileSystem::OperationFailedError do
-  context 'message' do
+  context "message" do
     let(:error_message) { 'HTTP error writing: 400 "Bad Request"' }
 
-    context 'has a cause attribute and HTTP result code is 400' do
-      it 'include error cause' do
+    context "has a cause attribute and HTTP result code is 400" do
+      it "include error cause" do
         allow_message_expectations_on_nil
         response_body = '{"error":["Invalid key test in request body"]}'
         allow(@response).to receive(:code).and_return("400")
@@ -36,8 +36,8 @@ describe Chef::ChefFS::FileSystem::OperationFailedError do
       end
     end
 
-    context 'does not have a cause attribute' do
-      it 'does not include error cause' do
+    context "does not have a cause attribute" do
+      it "does not include error cause" do
         expect {
           raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), error_message
         }.to raise_error(Chef::ChefFS::FileSystem::OperationFailedError, error_message)
diff --git a/spec/unit/chef_fs/file_system_spec.rb b/spec/unit/chef_fs/file_system_spec.rb
index 75ca4d4..9f07197 100644
--- a/spec/unit/chef_fs/file_system_spec.rb
+++ b/spec/unit/chef_fs/file_system_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,132 +16,132 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/chef_fs/file_system'
-require 'chef/chef_fs/file_pattern'
+require "spec_helper"
+require "chef/chef_fs/file_system"
+require "chef/chef_fs/file_pattern"
 
 describe Chef::ChefFS::FileSystem do
   include FileSystemSupport
 
-  context 'with empty filesystem' do
-    let(:fs) { memory_fs('', {}) }
+  context "with empty filesystem" do
+    let(:fs) { memory_fs("", {}) }
 
-    context 'list' do
-      it '/' do
-        list_should_yield_paths(fs, '/', '/')
+    context "list" do
+      it "/" do
+        list_should_yield_paths(fs, "/", "/")
       end
-      it '/a' do
-        list_should_yield_paths(fs, '/a', '/a')
+      it "/a" do
+        list_should_yield_paths(fs, "/a", "/a")
       end
-      it '/a/b' do
-        list_should_yield_paths(fs, '/a/b', '/a/b')
+      it "/a/b" do
+        list_should_yield_paths(fs, "/a/b", "/a/b")
       end
-      it '/*' do
-        list_should_yield_paths(fs, '/*', '/')
+      it "/*" do
+        list_should_yield_paths(fs, "/*", "/")
       end
     end
 
-    context 'resolve_path' do
-      it '/' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').path).to eq('/')
+    context "resolve_path" do
+      it "/" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").path).to eq("/")
       end
-      it 'nonexistent /a' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path).to eq('/a')
+      it "nonexistent /a" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a").path).to eq("/a")
       end
-      it 'nonexistent /a/b' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/b').path).to eq('/a/b')
+      it "nonexistent /a/b" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/b").path).to eq("/a/b")
       end
     end
   end
 
-  context 'with a populated filesystem' do
+  context "with a populated filesystem" do
     let(:fs) {
-      memory_fs('', {
+      memory_fs("", {
         :a => {
           :aa => {
-            :c => '',
-            :zz => ''
+            :c => "",
+            :zz => "",
           },
           :ab => {
-            :c => '',
-          }
+            :c => ""
+          },
         },
-        :x => '',
-        :y => {}
-      })
+        :x => "",
+        :y => {},
+      },)
     }
-    context 'list' do
-      it '/**' do
-        list_should_yield_paths(fs, '/**', '/', '/a', '/x', '/y', '/a/aa', '/a/aa/c', '/a/aa/zz', '/a/ab', '/a/ab/c')
+    context "list" do
+      it "/**" do
+        list_should_yield_paths(fs, "/**", "/", "/a", "/x", "/y", "/a/aa", "/a/aa/c", "/a/aa/zz", "/a/ab", "/a/ab/c")
       end
-      it '/' do
-        list_should_yield_paths(fs, '/', '/')
+      it "/" do
+        list_should_yield_paths(fs, "/", "/")
       end
-      it '/*' do
-        list_should_yield_paths(fs, '/*', '/', '/a', '/x', '/y')
+      it "/*" do
+        list_should_yield_paths(fs, "/*", "/", "/a", "/x", "/y")
       end
-      it '/*/*' do
-        list_should_yield_paths(fs, '/*/*', '/a/aa', '/a/ab')
+      it "/*/*" do
+        list_should_yield_paths(fs, "/*/*", "/a/aa", "/a/ab")
       end
-      it '/*/*/*' do
-        list_should_yield_paths(fs, '/*/*/*', '/a/aa/c', '/a/aa/zz', '/a/ab/c')
+      it "/*/*/*" do
+        list_should_yield_paths(fs, "/*/*/*", "/a/aa/c", "/a/aa/zz", "/a/ab/c")
       end
-      it '/*/*/?' do
-        list_should_yield_paths(fs, '/*/*/?', '/a/aa/c', '/a/ab/c')
+      it "/*/*/?" do
+        list_should_yield_paths(fs, "/*/*/?", "/a/aa/c", "/a/ab/c")
       end
-      it '/a/*/c' do
-        list_should_yield_paths(fs, '/a/*/c', '/a/aa/c', '/a/ab/c')
+      it "/a/*/c" do
+        list_should_yield_paths(fs, "/a/*/c", "/a/aa/c", "/a/ab/c")
       end
-      it '/**b/c' do
-        list_should_yield_paths(fs, '/**b/c', '/a/ab/c')
+      it "/**b/c" do
+        list_should_yield_paths(fs, "/**b/c", "/a/ab/c")
       end
-      it '/a/ab/c' do
+      it "/a/ab/c" do
         no_blocking_calls_allowed
-        list_should_yield_paths(fs, '/a/ab/c', '/a/ab/c')
+        list_should_yield_paths(fs, "/a/ab/c", "/a/ab/c")
       end
-      it 'nonexistent /a/ab/blah' do
+      it "nonexistent /a/ab/blah" do
         no_blocking_calls_allowed
-        list_should_yield_paths(fs, '/a/ab/blah', '/a/ab/blah')
+        list_should_yield_paths(fs, "/a/ab/blah", "/a/ab/blah")
       end
-      it 'nonexistent /a/ab/blah/bjork' do
+      it "nonexistent /a/ab/blah/bjork" do
         no_blocking_calls_allowed
-        list_should_yield_paths(fs, '/a/ab/blah/bjork', '/a/ab/blah/bjork')
+        list_should_yield_paths(fs, "/a/ab/blah/bjork", "/a/ab/blah/bjork")
       end
     end
 
-    context 'resolve_path' do
+    context "resolve_path" do
       before(:each) do
         no_blocking_calls_allowed
       end
-      it 'resolves /' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').path).to eq('/')
+      it "resolves /" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").path).to eq("/")
       end
-      it 'resolves /x' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/x').path).to eq('/x')
+      it "resolves /x" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/x").path).to eq("/x")
       end
-      it 'resolves /a' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path).to eq('/a')
+      it "resolves /a" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a").path).to eq("/a")
       end
-      it 'resolves /a/aa' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa').path).to eq('/a/aa')
+      it "resolves /a/aa" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/aa").path).to eq("/a/aa")
       end
-      it 'resolves /a/aa/zz' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa/zz').path).to eq('/a/aa/zz')
+      it "resolves /a/aa/zz" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/a/aa/zz").path).to eq("/a/aa/zz")
       end
-      it 'resolves nonexistent /q/x/w' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/q/x/w').path).to eq('/q/x/w')
+      it "resolves nonexistent /q/x/w" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/q/x/w").path).to eq("/q/x/w")
       end
     end
 
-    context 'empty?' do
-      it 'is not empty /' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/').empty?).to be false
+    context "empty?" do
+      it "is not empty /" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/").empty?).to be false
       end
-      it 'is empty /y' do
-        expect(Chef::ChefFS::FileSystem.resolve_path(fs, '/y').empty?).to be true
+      it "is empty /y" do
+        expect(Chef::ChefFS::FileSystem.resolve_path(fs, "/y").empty?).to be true
       end
       it 'is not a directory and can\'t be tested /x' do
-        expect { Chef::ChefFS::FileSystem.resolve_path(fs, '/x').empty? }.to raise_error(NoMethodError)
+        expect { Chef::ChefFS::FileSystem.resolve_path(fs, "/x").empty? }.to raise_error(NoMethodError)
       end
     end
   end
diff --git a/spec/unit/chef_fs/parallelizer.rb b/spec/unit/chef_fs/parallelizer.rb
index 9cb9796..da18117 100644
--- a/spec/unit/chef_fs/parallelizer.rb
+++ b/spec/unit/chef_fs/parallelizer.rb
@@ -1,5 +1,5 @@
-require 'spec_helper'
-require 'chef/chef_fs/parallelizer'
+require "spec_helper"
+require "chef/chef_fs/parallelizer"
 
 describe Chef::ChefFS::Parallelizer do
   before :each do
@@ -14,7 +14,7 @@ describe Chef::ChefFS::Parallelizer do
     parallelizer.kill
   end
 
-  context 'With a Parallelizer with 5 threads' do
+  context "With a Parallelizer with 5 threads" do
     let :parallelizer do
       Chef::ChefFS::Parallelizer.new(5)
     end
@@ -25,7 +25,7 @@ describe Chef::ChefFS::Parallelizer do
 
     it "parallel_do creates unordered output as soon as it is available" do
       outputs = []
-      parallelizer.parallel_do([0.5,0.3,0.1]) do |val|
+      parallelizer.parallel_do([0.5, 0.3, 0.1]) do |val|
         sleep val
         outputs << val
       end
@@ -44,46 +44,46 @@ describe Chef::ChefFS::Parallelizer do
       it "10 sleep(0.2)s complete within 0.5 seconds" do
         expect(parallelize(1.upto(10), :ordered => false) do |i|
           sleep 0.2
-          'x'
-        end.to_a).to eq(%w(x x x x x x x x x x))
+          "x"
+        end.to_a).to eq(%w{x x x x x x x x x x})
         expect(elapsed_time).to be < 0.5
       end
 
       it "The output comes as soon as it is available" do
-        enum = parallelize([0.5,0.3,0.1], :ordered => false) do |val|
+        enum = parallelize([0.5, 0.3, 0.1], :ordered => false) do |val|
           sleep val
           val
         end
         expect(enum.map do |value|
-          expect(elapsed_time).to be < value+0.1
+          expect(elapsed_time).to be < value + 0.1
           value
         end).to eq([ 0.1, 0.3, 0.5 ])
       end
 
       it "An exception in input is passed through but does NOT stop processing" do
-        input = TestEnumerable.new(0.5,0.3,0.1) do
-          raise 'hi'
+        input = TestEnumerable.new(0.5, 0.3, 0.1) do
+          raise "hi"
         end
         enum = parallelize(input, :ordered => false) { |x| sleep(x); x }
         results = []
-        expect { enum.each { |value| results << value } }.to raise_error 'hi'
+        expect { enum.each { |value| results << value } }.to raise_error "hi"
         expect(results).to eq([ 0.1, 0.3, 0.5 ])
         expect(elapsed_time).to be < 0.6
       end
 
       it "Exceptions in output are raised after all processing is done" do
         processed = 0
-        enum = parallelize([1,2,'x',3], :ordered => false) do |x|
-          if x == 'x'
+        enum = parallelize([1, 2, "x", 3], :ordered => false) do |x|
+          if x == "x"
             sleep 0.1
-            raise 'hi'
+            raise "hi"
           end
           sleep 0.2
           processed += 1
           x
         end
         results = []
-        expect { enum.each { |value| results << value } }.to raise_error 'hi'
+        expect { enum.each { |value| results << value } }.to raise_error "hi"
         expect(results.sort).to eq([ 1, 2, 3 ])
         expect(elapsed_time).to be < 0.3
         expect(processed).to eq(3)
@@ -91,16 +91,16 @@ describe Chef::ChefFS::Parallelizer do
 
       it "Exceptions with :stop_on_exception are raised after all processing is done" do
         processed = 0
-        parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
-          if x == 'x'
+        parallelized = parallelize([0.3, 0.3, "x", 0.3, 0.3, 0.3, 0.3, 0.3], :ordered => false, :stop_on_exception => true) do |x|
+          if x == "x"
             sleep(0.1)
-            raise 'hi'
+            raise "hi"
           end
           sleep(x)
           processed += 1
           x
         end
-        expect { parallelized.to_a }.to raise_error 'hi'
+        expect { parallelized.to_a }.to raise_error "hi"
         expect(processed).to eq(4)
       end
     end
@@ -116,13 +116,13 @@ describe Chef::ChefFS::Parallelizer do
       it "10 sleep(0.2)s complete within 0.5 seconds" do
         expect(parallelize(1.upto(10), :ordered => true) do |i|
           sleep 0.2
-          'x'
-        end.to_a).to eq(%w(x x x x x x x x x x))
+          "x"
+        end.to_a).to eq(%w{x x x x x x x x x x})
         expect(elapsed_time).to be < 0.5
       end
 
       it "Output comes in the order of the input" do
-        enum = parallelize([0.5,0.3,0.1]) do |val|
+        enum = parallelize([0.5, 0.3, 0.1]) do |val|
           sleep val
           val
         end.enum_for(:each_with_index)
@@ -133,29 +133,29 @@ describe Chef::ChefFS::Parallelizer do
       end
 
       it "Exceptions in input are raised in the correct sequence but do NOT stop processing" do
-        input = TestEnumerable.new(0.5,0.3,0.1) do
-          raise 'hi'
+        input = TestEnumerable.new(0.5, 0.3, 0.1) do
+          raise "hi"
         end
         results = []
         enum = parallelize(input) { |x| sleep(x); x }
-        expect { enum.each { |value| results << value } }.to raise_error 'hi'
+        expect { enum.each { |value| results << value } }.to raise_error "hi"
         expect(elapsed_time).to be < 0.6
         expect(results).to eq([ 0.5, 0.3, 0.1 ])
       end
 
       it "Exceptions in output are raised in the correct sequence and running processes do NOT stop processing" do
         processed = 0
-        enum = parallelize([1,2,'x',3]) do |x|
-          if x == 'x'
+        enum = parallelize([1, 2, "x", 3]) do |x|
+          if x == "x"
             sleep(0.1)
-            raise 'hi'
+            raise "hi"
           end
           sleep(0.2)
           processed += 1
           x
         end
         results = []
-        expect { enum.each { |value| results << value } }.to raise_error 'hi'
+        expect { enum.each { |value| results << value } }.to raise_error "hi"
         expect(results).to eq([ 1, 2 ])
         expect(elapsed_time).to be < 0.3
         expect(processed).to eq(3)
@@ -163,16 +163,16 @@ describe Chef::ChefFS::Parallelizer do
 
       it "Exceptions with :stop_on_exception are raised after all processing is done" do
         processed = 0
-        parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
-          if x == 'x'
+        parallelized = parallelize([0.3, 0.3, "x", 0.3, 0.3, 0.3, 0.3, 0.3], :ordered => false, :stop_on_exception => true) do |x|
+          if x == "x"
             sleep(0.1)
-            raise 'hi'
+            raise "hi"
           end
           sleep(x)
           processed += 1
           x
         end
-        expect { parallelized.to_a }.to raise_error 'hi'
+        expect { parallelized.to_a }.to raise_error "hi"
         expect(processed).to eq(4)
       end
     end
@@ -188,7 +188,7 @@ describe Chef::ChefFS::Parallelizer do
       end
       enum = parallelize(input) { |x| x }
       expect(enum.map do |value|
-        expect(elapsed_time).to be < (value+1)*0.1
+        expect(elapsed_time).to be < (value + 1) * 0.1
         value
       end).to eq([ 1, 2, 3 ])
     end
@@ -205,14 +205,11 @@ describe Chef::ChefFS::Parallelizer do
         started = false
         @occupying_job_finished = occupying_job_finished = [ false ]
         @thread = Thread.new do
-          begin
-            parallelizer.parallelize([0], :main_thread_processing => false) do |x|
-              started = true
-              sleep(0.3)
-              occupying_job_finished[0] = true
-            end.wait
-          ensure
-          end
+          parallelizer.parallelize([0], :main_thread_processing => false) do |x|
+            started = true
+            sleep(0.3)
+            occupying_job_finished[0] = true
+          end.wait
         end
         while !started
           sleep(0.01)
@@ -236,7 +233,7 @@ describe Chef::ChefFS::Parallelizer do
       it "parallelize with :main_thread_processing = false waits for the job to finish" do
         expect(parallelizer.parallelize([1], :main_thread_processing => false) do |x|
           sleep(0.1)
-          x+1
+          x + 1
         end.to_a).to eq([ 2 ])
         expect(elapsed_time).to be > 0.3
       end
@@ -270,7 +267,7 @@ describe Chef::ChefFS::Parallelizer do
     context "enumerable methods should run efficiently" do
       it ".count does not process anything" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+        input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           sleep(0.05) # Just enough to yield and get other inputs in the queue
@@ -283,7 +280,7 @@ describe Chef::ChefFS::Parallelizer do
 
       it ".count with arguments works normally" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,1,1,1,2,2,2,3,3,4)
+        input_mapper = TestEnumerable.new(1, 1, 1, 1, 2, 2, 2, 3, 3, 4)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           x
@@ -296,40 +293,40 @@ describe Chef::ChefFS::Parallelizer do
 
       it ".first does not enumerate anything other than the first result(s)" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+        input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           sleep(0.05) # Just enough to yield and get other inputs in the queue
           x
         end
         expect(enum.first).to eq(1)
-        expect(enum.first(2)).to eq([1,2])
+        expect(enum.first(2)).to eq([1, 2])
         expect(outputs_processed).to eq(3)
         expect(input_mapper.num_processed).to eq(3)
       end
 
       it ".take does not enumerate anything other than the first result(s)" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+        input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           sleep(0.05) # Just enough to yield and get other inputs in the queue
           x
         end
-        expect(enum.take(2)).to eq([1,2])
+        expect(enum.take(2)).to eq([1, 2])
         expect(outputs_processed).to eq(2)
         expect(input_mapper.num_processed).to eq(2)
       end
 
       it ".drop does not process anything other than the last result(s)" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+        input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           sleep(0.05) # Just enough to yield and get other inputs in the queue
           x
         end
-        expect(enum.drop(2)).to eq([3,4,5,6])
+        expect(enum.drop(2)).to eq([3, 4, 5, 6])
         expect(outputs_processed).to eq(4)
         expect(input_mapper.num_processed).to eq(6)
       end
@@ -337,33 +334,33 @@ describe Chef::ChefFS::Parallelizer do
       if Enumerable.method_defined?(:lazy)
         it ".lazy.take does not enumerate anything other than the first result(s)" do
           outputs_processed = 0
-          input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+          input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
           enum = parallelizer.parallelize(input_mapper) do |x|
             outputs_processed += 1
             sleep(0.05) # Just enough to yield and get other inputs in the queue
             x
           end
-          expect(enum.lazy.take(2).to_a).to eq([1,2])
+          expect(enum.lazy.take(2).to_a).to eq([1, 2])
           expect(outputs_processed).to eq(2)
           expect(input_mapper.num_processed).to eq(2)
         end
 
         it ".drop does not process anything other than the last result(s)" do
           outputs_processed = 0
-          input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+          input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
           enum = parallelizer.parallelize(input_mapper) do |x|
             outputs_processed += 1
             sleep(0.05) # Just enough to yield and get other inputs in the queue
             x
           end
-          expect(enum.lazy.drop(2).to_a).to eq([3,4,5,6])
+          expect(enum.lazy.drop(2).to_a).to eq([3, 4, 5, 6])
           expect(outputs_processed).to eq(4)
           expect(input_mapper.num_processed).to eq(6)
         end
 
         it "lazy enumerable is actually lazy" do
           outputs_processed = 0
-          input_mapper = TestEnumerable.new(1,2,3,4,5,6)
+          input_mapper = TestEnumerable.new(1, 2, 3, 4, 5, 6)
           enum = parallelizer.parallelize(input_mapper) do |x|
             outputs_processed += 1
             sleep(0.05) # Just enough to yield and get other inputs in the queue
@@ -381,32 +378,32 @@ describe Chef::ChefFS::Parallelizer do
     context "running enumerable multiple times should function correctly" do
       it ".map twice on the same parallel enumerable returns the correct results and re-processes the input" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3)
+        input_mapper = TestEnumerable.new(1, 2, 3)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           x
         end
-        expect(enum.map { |x| x }).to eq([1,2,3])
-        expect(enum.map { |x| x }).to eq([1,2,3])
+        expect(enum.map { |x| x }).to eq([1, 2, 3])
+        expect(enum.map { |x| x }).to eq([1, 2, 3])
         expect(outputs_processed).to eq(6)
         expect(input_mapper.num_processed).to eq(6)
       end
 
       it ".first and then .map on the same parallel enumerable returns the correct results and re-processes the input" do
         outputs_processed = 0
-        input_mapper = TestEnumerable.new(1,2,3)
+        input_mapper = TestEnumerable.new(1, 2, 3)
         enum = parallelizer.parallelize(input_mapper) do |x|
           outputs_processed += 1
           x
         end
         expect(enum.first).to eq(1)
-        expect(enum.map { |x| x }).to eq([1,2,3])
+        expect(enum.map { |x| x }).to eq([1, 2, 3])
         expect(outputs_processed).to be >= 4
         expect(input_mapper.num_processed).to be >= 4
       end
 
       it "two simultaneous enumerations throws an exception" do
-        enum = parallelizer.parallelize([1,2,3]) { |x| x }
+        enum = parallelizer.parallelize([1, 2, 3]) { |x| x }
         a = enum.enum_for(:each)
         a.next
         expect do
@@ -424,7 +421,7 @@ describe Chef::ChefFS::Parallelizer do
 
     context "And main_thread_processing on" do
       it "succeeds in running" do
-        expect(parallelizer.parallelize([0.5]) { |x| x*2 }.to_a).to eq([1])
+        expect(parallelizer.parallelize([0.5]) { |x| x * 2 }.to_a).to eq([1])
       end
     end
   end
@@ -435,16 +432,16 @@ describe Chef::ChefFS::Parallelizer do
     end
 
     it "does not have contention issues with large numbers of inputs" do
-      expect(parallelizer.parallelize(1.upto(500)) { |x| x+1 }.to_a).to eq(2.upto(501).to_a)
+      expect(parallelizer.parallelize(1.upto(500)) { |x| x + 1 }.to_a).to eq(2.upto(501).to_a)
     end
 
     it "does not have contention issues with large numbers of inputs with ordering off" do
-      expect(parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x+1 }.to_a.sort).to eq(2.upto(501).to_a)
+      expect(parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x + 1 }.to_a.sort).to eq(2.upto(501).to_a)
     end
 
     it "does not have contention issues with large numbers of jobs and inputs with ordering off" do
       parallelizers = 0.upto(99).map do
-        parallelizer.parallelize(1.upto(500)) { |x| x+1 }
+        parallelizer.parallelize(1.upto(500)) { |x| x + 1 }
       end
       outputs = []
       threads = 0.upto(99).map do |i|
diff --git a/spec/unit/chef_fs/path_util_spec.rb b/spec/unit/chef_fs/path_util_spec.rb
new file mode 100644
index 0000000..93205a1
--- /dev/null
+++ b/spec/unit/chef_fs/path_util_spec.rb
@@ -0,0 +1,108 @@
+#
+# Author:: Kartik Null Cating-Subramanian (<ksubramanian at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/chef_fs/path_utils"
+
+describe Chef::ChefFS::PathUtils do
+  context "invoking join" do
+    it "joins well-behaved distinct path elements" do
+      expect(Chef::ChefFS::PathUtils.join("a", "b", "c")).to eq("a/b/c")
+    end
+
+    it "strips extraneous slashes in the middle of paths" do
+      expect(Chef::ChefFS::PathUtils.join("a/", "/b", "/c/")).to eq("a/b/c")
+      expect(Chef::ChefFS::PathUtils.join("a/", "/b", "///c/")).to eq("a/b/c")
+    end
+
+    it "preserves the whether the first element was absolute or not" do
+      expect(Chef::ChefFS::PathUtils.join("/a/", "/b", "c/")).to eq("/a/b/c")
+      expect(Chef::ChefFS::PathUtils.join("///a/", "/b", "c/")).to eq("/a/b/c")
+    end
+  end
+
+  context "invoking is_absolute?" do
+    it "confirms that paths starting with / are absolute" do
+      expect(Chef::ChefFS::PathUtils.is_absolute?("/foo/bar/baz")).to be true
+      expect(Chef::ChefFS::PathUtils.is_absolute?("/foo")).to be true
+    end
+
+    it "confirms that paths starting with // are absolute even though that looks like some windows network path" do
+      expect(Chef::ChefFS::PathUtils.is_absolute?("//foo/bar/baz")).to be true
+    end
+
+    it "confirms that root is indeed absolute" do
+      expect(Chef::ChefFS::PathUtils.is_absolute?("/")).to be true
+    end
+
+    it "confirms that paths starting without / are relative" do
+      expect(Chef::ChefFS::PathUtils.is_absolute?("foo/bar/baz")).to be false
+      expect(Chef::ChefFS::PathUtils.is_absolute?("a")).to be false
+    end
+
+    it "returns false for an empty path." do
+      expect(Chef::ChefFS::PathUtils.is_absolute?("")).to be false
+    end
+  end
+
+  context "invoking realest_path" do
+    let(:good_path) { File.dirname(__FILE__) }
+    let(:parent_path) { File.dirname(good_path) }
+
+    it "handles paths with no wildcards or globs" do
+      expect(Chef::ChefFS::PathUtils.realest_path(good_path)).to eq(File.expand_path(good_path))
+    end
+
+    it "handles paths with .. and ." do
+      expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/../.")).to eq(File.expand_path(parent_path))
+    end
+
+    it "handles paths with *" do
+      expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/*/foo")).to eq(File.expand_path(good_path + "/*/foo"))
+    end
+
+    it "handles directories that do not exist" do
+      expect(Chef::ChefFS::PathUtils.realest_path(good_path + "/something/or/other")).to eq(File.expand_path(good_path + "/something/or/other"))
+    end
+
+    it "handles root correctly" do
+      if Chef::Platform.windows?
+        expect(Chef::ChefFS::PathUtils.realest_path("C:/")).to eq("C:/")
+      else
+        expect(Chef::ChefFS::PathUtils.realest_path("/")).to eq("/")
+      end
+    end
+  end
+
+  context "invoking descendant_path" do
+    it "handles paths with various casing on windows" do
+      allow(Chef::ChefFS).to receive(:windows?) { true }
+      expect(Chef::ChefFS::PathUtils.descendant_path("C:/ab/b/c", "C:/AB/B")).to eq("c")
+      expect(Chef::ChefFS::PathUtils.descendant_path("C:/ab/b/c", "c:/ab/B")).to eq("c")
+    end
+
+    it "returns nil if the path does not have the given ancestor" do
+      expect(Chef::ChefFS::PathUtils.descendant_path("/D/E/F", "/A/B/C")).to be_nil
+      expect(Chef::ChefFS::PathUtils.descendant_path("/A/B/D", "/A/B/C")).to be_nil
+    end
+
+    it "returns blank if the ancestor equals the path" do
+      expect(Chef::ChefFS::PathUtils.descendant_path("/A/B/D", "/A/B/D")).to eq("")
+    end
+  end
+end
diff --git a/spec/unit/chef_spec.rb b/spec/unit/chef_spec.rb
index 8a8d6c6..bbab793 100644
--- a/spec/unit/chef_spec.rb
+++ b/spec/unit/chef_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef do
   it "should have a version defined" do
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index fa83177..fe9b1af 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,65 +18,19 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "spec/support/shared/context/client"
+require "spec/support/shared/examples/client"
 
-require 'chef/run_context'
-require 'chef/rest'
-require 'rbconfig'
+require "chef/run_context"
+require "chef/server_api"
+require "rbconfig"
 
 class FooError < RuntimeError
 end
 
 describe Chef::Client do
-
-  let(:hostname) { "hostname" }
-  let(:machinename) { "machinename.example.org" }
-  let(:fqdn) { "hostname.example.org" }
-
-  let(:ohai_data) do
-    { :fqdn             => fqdn,
-      :hostname         => hostname,
-      :machinename      => machinename,
-      :platform         => 'example-platform',
-      :platform_version => 'example-platform-1.0',
-      :data             => {}
-    }
-  end
-
-  let(:ohai_system) do
-    ohai_system = double( "Ohai::System",
-                          :all_plugins => true,
-                          :data => ohai_data)
-    allow(ohai_system).to receive(:[]) do |key|
-      ohai_data[key]
-    end
-    ohai_system
-  end
-
-  let(:node) do
-    Chef::Node.new.tap do |n|
-      n.name(fqdn)
-      n.chef_environment("_default")
-    end
-  end
-
-  let(:json_attribs) { nil }
-  let(:client_opts) { {} }
-
-  let(:client) do
-    Chef::Config[:event_loggers] = []
-    Chef::Client.new(json_attribs, client_opts).tap do |c|
-      c.node = node
-    end
-  end
-
-  before do
-    Chef::Log.logger = Logger.new(StringIO.new)
-
-    # Node/Ohai data
-    #Chef::Config[:node_name] = fqdn
-    allow(Ohai::System).to receive(:new).and_return(ohai_system)
-  end
+  include_context "client"
 
   context "when minimal ohai is configured" do
     before do
@@ -84,40 +38,39 @@ describe Chef::Client do
     end
 
     it "runs ohai with only the minimum required plugins" do
-      expected_filter = %w[fqdn machinename hostname platform platform_version os os_version]
+      expected_filter = %w{fqdn machinename hostname platform platform_version os os_version}
       expect(ohai_system).to receive(:all_plugins).with(expected_filter)
       client.run_ohai
     end
-
   end
 
   describe "authentication protocol selection" do
-    after do
-      Chef::Config[:authentication_protocol_version] = "1.0"
-    end
+    context "when FIPS is disabled" do
+      before do
+        Chef::Config[:fips] = false
+      end
 
-    context "when the node name is <= 90 bytes" do
-      it "does not force the authentication protocol to 1.1" do
-        Chef::Config[:node_name] = ("f" * 90)
-        # ugly that this happens as a side effect of a getter :(
-        client.node_name
-        expect(Chef::Config[:authentication_protocol_version]).to eq("1.0")
+      it "defaults to 1.1" do
+        expect(Chef::Config[:authentication_protocol_version]).to eq("1.1")
       end
     end
+    context "when FIPS is enabled" do
+      before do
+        Chef::Config[:fips] = true
+      end
 
-    context "when the node name is > 90 bytes" do
-      it "sets the authentication protocol to version 1.1" do
-        Chef::Config[:node_name] = ("f" * 91)
-        # ugly that this happens as a side effect of a getter :(
-        client.node_name
-        expect(Chef::Config[:authentication_protocol_version]).to eq("1.1")
+      it "defaults to 1.3" do
+        expect(Chef::Config[:authentication_protocol_version]).to eq("1.3")
+      end
+
+      after do
+        Chef::Config[:fips] = false
       end
     end
   end
 
   describe "configuring output formatters" do
     context "when no formatter has been configured" do
-
       context "and STDOUT is a TTY" do
         before do
           allow(STDOUT).to receive(:tty?).and_return(true)
@@ -203,135 +156,12 @@ describe Chef::Client do
   end
 
   describe "a full client run" do
-    shared_context "a client run" do
-      let(:http_node_load) { double("Chef::REST (node)") }
-      let(:http_cookbook_sync) { double("Chef::REST (cookbook sync)") }
-      let(:http_node_save) { double("Chef::REST (node save)") }
-      let(:runner) { double("Chef::Runner") }
-      let(:audit_runner) { instance_double("Chef::Audit::Runner", :failed? => false) }
-
-      let(:api_client_exists?) { false }
-
-      let(:stdout) { StringIO.new }
-      let(:stderr) { StringIO.new }
-
-      let(:enable_fork) { false }
-
-      def stub_for_register
-        # --Client.register
-        #   Make sure Client#register thinks the client key doesn't
-        #   exist, so it tries to register and create one.
-        allow(File).to receive(:exists?).and_call_original
-        expect(File).to receive(:exists?).
-          with(Chef::Config[:client_key]).
-          exactly(:once).
-          and_return(api_client_exists?)
-
-        unless api_client_exists?
-          #   Client.register will register with the validation client name.
-          expect_any_instance_of(Chef::ApiClient::Registration).to receive(:run)
-        end
-      end
-
-      def stub_for_node_load
-        #   Client.register will then turn around create another
-        #   Chef::REST object, this time with the client key it got from the
-        #   previous step.
-        expect(Chef::REST).to receive(:new).
-          with(Chef::Config[:chef_server_url], fqdn, Chef::Config[:client_key]).
-          exactly(:once).
-          and_return(http_node_load)
-
-        # --Client#build_node
-        #   looks up the node, which we will return, then later saves it.
-        expect(Chef::Node).to receive(:find_or_create).with(fqdn).and_return(node)
-
-        # --ResourceReporter#node_load_completed
-        #   gets a run id from the server for storing resource history
-        #   (has its own tests, so stubbing it here.)
-        expect_any_instance_of(Chef::ResourceReporter).to receive(:node_load_completed)
-      end
-
-      def stub_for_sync_cookbooks
-        # --Client#setup_run_context
-        # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
-        #
-        expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
-        expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
-        expect(http_cookbook_sync).to receive(:post).
-          with("environments/_default/cookbook_versions", {:run_list => []}).
-          and_return({})
-      end
-
-      def stub_for_converge
-        # --Client#converge
-        expect(Chef::Runner).to receive(:new).and_return(runner)
-        expect(runner).to receive(:converge).and_return(true)
-      end
-
-      def stub_for_audit
-        # -- Client#run_audits
-        expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
-        expect(audit_runner).to receive(:run).and_return(true)
-      end
-
-      def stub_for_node_save
-        allow(node).to receive(:data_for_save).and_return(node.for_json)
-
-        # --Client#save_updated_node
-        expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_node_save)
-        expect(http_node_save).to receive(:put_rest).with("nodes/#{fqdn}", node.for_json).and_return(true)
-      end
-
-      def stub_for_run
-        expect_any_instance_of(Chef::RunLock).to receive(:acquire)
-        expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
-        expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-        # Post conditions: check that node has been filled in correctly
-        expect(client).to receive(:run_started)
-        expect(client).to receive(:run_completed_successfully)
-
-        # --ResourceReporter#run_completed
-        #   updates the server with the resource history
-        #   (has its own tests, so stubbing it here.)
-        expect_any_instance_of(Chef::ResourceReporter).to receive(:run_completed)
-        # --AuditReporter#run_completed
-        #   posts the audit data to server.
-        #   (has its own tests, so stubbing it here.)
-        expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_completed)
-      end
-
-      before do
-        Chef::Config[:client_fork] = enable_fork
-        Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
-        Chef::Config[:why_run] = false
-        Chef::Config[:audit_mode] = :enabled
-
-        stub_const("Chef::Client::STDOUT_FD", stdout)
-        stub_const("Chef::Client::STDERR_FD", stderr)
-
-        stub_for_register
-        stub_for_node_load
-        stub_for_sync_cookbooks
-        stub_for_converge
-        stub_for_audit
-        stub_for_node_save
-        stub_for_run
-      end
-    end
-
     shared_examples_for "a successful client run" do
       include_context "a client run"
+      include_context "converge completed"
+      include_context "audit phase completed"
 
-      it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges, and runs audits" do
-        # This is what we're testing.
-        client.run
-
-        # fork is stubbed, so we can see the outcome of the run
-        expect(node.automatic_attrs[:platform]).to eq("example-platform")
-        expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
-      end
+      include_examples "a completed run"
     end
 
     describe "when running chef-client without fork" do
@@ -339,33 +169,28 @@ describe Chef::Client do
     end
 
     describe "when the client key already exists" do
-      let(:api_client_exists?) { true }
-      include_examples "a successful client run"
+      include_examples "a successful client run" do
+        let(:api_client_exists?) { true }
+      end
     end
 
-    describe "when an override run list is given" do
-      let(:client_opts) { {:override_runlist => "recipe[override_recipe]"} }
-
-      it "should permit spaces in overriding run list" do
-        Chef::Client.new(nil, :override_runlist => 'role[a], role[b]')
+    context "when an override run list is given" do
+      it "permits spaces in overriding run list" do
+        Chef::Client.new(nil, :override_runlist => "role[a], role[b]")
       end
 
-      describe "when running the client" do
+      describe "calling run" do
         include_examples "a successful client run" do
-
-          before do
-            # Client will try to compile and run override_recipe
-            expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
-          end
+          let(:client_opts) { { :override_runlist => "recipe[override_recipe]" } }
 
           def stub_for_sync_cookbooks
             # --Client#setup_run_context
             # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
             #
             expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
-            expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+            expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
             expect(http_cookbook_sync).to receive(:post).
-              with("environments/_default/cookbook_versions", {:run_list => ["override_recipe"]}).
+              with("environments/_default/cookbook_versions", { :run_list => ["override_recipe"] }).
               and_return({})
           end
 
@@ -373,24 +198,33 @@ describe Chef::Client do
             # Expect NO node save
             expect(node).not_to receive(:save)
           end
+
+          before do
+            # Client will try to compile and run override_recipe
+            expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
+          end
         end
       end
     end
 
     describe "when a permanent run list is passed as an option" do
-      include_examples "a successful client run" do
+      it "sets the new run list on the node" do
+        client.run
+        expect(node.run_list).to eq(Chef::RunList.new(new_runlist))
+      end
 
+      include_examples "a successful client run" do
         let(:new_runlist) { "recipe[new_run_list_recipe]" }
-        let(:client_opts) { {:runlist => new_runlist} }
+        let(:client_opts) { { :runlist => new_runlist } }
 
         def stub_for_sync_cookbooks
           # --Client#setup_run_context
           # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync
           #
           expect_any_instance_of(Chef::CookbookSynchronizer).to receive(:sync_cookbooks)
-          expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
+          expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync)
           expect(http_cookbook_sync).to receive(:post).
-            with("environments/_default/cookbook_versions", {:run_list => ["new_run_list_recipe"]}).
+            with("environments/_default/cookbook_versions", { :run_list => ["new_run_list_recipe"] }).
             and_return({})
         end
 
@@ -399,214 +233,62 @@ describe Chef::Client do
           # do not create a fixture for this.
           expect_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:compile)
         end
-
-        it "sets the new run list on the node" do
-          client.run
-          expect(node.run_list).to eq(Chef::RunList.new(new_runlist))
-        end
       end
     end
 
-    describe "when converge fails" do
-      include_context "a client run" do
-        let(:e) { Exception.new }
-        def stub_for_converge
-          expect(Chef::Runner).to receive(:new).and_return(runner)
-          expect(runner).to receive(:converge).and_raise(e)
-          expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
-        end
-
-        def stub_for_node_save
-          expect(client).to_not receive(:save_updated_node)
-        end
-
-        def stub_for_run
-          expect_any_instance_of(Chef::RunLock).to receive(:acquire)
-          expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
-          expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-          # Post conditions: check that node has been filled in correctly
-          expect(client).to receive(:run_started)
-          expect(client).to receive(:run_failed)
-
-          expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
-          expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
-        end
-      end
-
-      it "runs the audits and raises the error" do
-        expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
-          expect(error.wrapped_errors.size).to eq(1)
-          expect(error.wrapped_errors[0]).to eq(e)
-        end
-      end
-    end
-
-    describe "when the audit phase fails" do
-      context "with an exception" do
-        context "when audit mode is enabled" do
-          include_context "a client run" do
-            let(:e) { Exception.new }
-            def stub_for_audit
-              expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
-              expect(audit_runner).to receive(:run).and_raise(e)
-              expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
-            end
-
-            def stub_for_run
-              expect_any_instance_of(Chef::RunLock).to receive(:acquire)
-              expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
-              expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-              # Post conditions: check that node has been filled in correctly
-              expect(client).to receive(:run_started)
-              expect(client).to receive(:run_failed)
-
-              expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
-              expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
-            end
-          end
-
-          it "should save the node after converge and raise exception" do
-            expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
-              expect(error.wrapped_errors.size).to eq(1)
-              expect(error.wrapped_errors[0]).to eq(e)
-            end
+    describe "when converge completes successfully" do
+      include_context "a client run"
+      include_context "converge completed"
+      context "when audit mode is enabled" do
+        describe "when audit phase errors" do
+          include_context "audit phase failed with error"
+          include_examples "a completed run with audit failure" do
+            let(:run_errors) { [audit_error] }
           end
         end
 
-        context "when audit mode is disabled" do
-          include_context "a client run" do
-            before do
-              Chef::Config[:audit_mode] = :disabled
-            end
-
-            let(:e) { FooError.new }
-
-            def stub_for_audit
-              expect(Chef::Audit::Runner).to_not receive(:new)
-            end
-
-            def stub_for_converge
-              expect(Chef::Runner).to receive(:new).and_return(runner)
-              expect(runner).to receive(:converge).and_raise(e)
-              expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(FooError)
-            end
-
-            def stub_for_node_save
-              expect(client).to_not receive(:save_updated_node)
-            end
-
-            def stub_for_run
-              expect_any_instance_of(Chef::RunLock).to receive(:acquire)
-              expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
-              expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-
-              # Post conditions: check that node has been filled in correctly
-              expect(client).to receive(:run_started)
-              expect(client).to receive(:run_failed)
-
-              expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
-
-            end
-
-            it "re-raises an unwrapped exception" do
-              expect { client.run }.to raise_error(FooError)
-            end
-          end
+        describe "when audit phase completed" do
+          include_context "audit phase completed"
+          include_examples "a completed run"
         end
 
-
-      end
-
-      context "with failed audits" do
-        include_context "a client run" do
-          let(:audit_runner) do
-            instance_double("Chef::Audit::Runner", :run => true, :failed? => true, :num_failed => 1, :num_total => 1)
-          end
-
-          def stub_for_audit
-            expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
-            expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
-          end
-
-          def stub_for_run
-            expect_any_instance_of(Chef::RunLock).to receive(:acquire)
-            expect_any_instance_of(Chef::RunLock).to receive(:save_pid)
-            expect_any_instance_of(Chef::RunLock).to receive(:release)
-
-            # Post conditions: check that node has been filled in correctly
-            expect(client).to receive(:run_started)
-            expect(client).to receive(:run_failed)
-
-            expect_any_instance_of(Chef::ResourceReporter).to receive(:run_failed)
-            expect_any_instance_of(Chef::Audit::AuditReporter).to receive(:run_failed)
-          end
-        end
-
-        it "should save the node after converge and raise exception" do
-          expect{ client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
-            expect(error.wrapped_errors.size).to eq(1)
-            expect(error.wrapped_errors[0]).to be_instance_of(Chef::Exceptions::AuditsFailed)
+        describe "when audit phase completed with failed controls" do
+          include_context "audit phase completed with failed controls"
+          include_examples "a completed run with audit failure" do
+            let(:run_errors) { [audit_error] }
           end
         end
       end
     end
 
-    describe "when why_run mode is enabled" do
-      include_context "a client run" do
-
-        before do
-          Chef::Config[:why_run] = true
-        end
-
-        def stub_for_audit
-          expect(Chef::Audit::Runner).to_not receive(:new)
-        end
-
-        def stub_for_node_save
-          # This is how we should be mocking external calls - not letting it fall all the way through to the
-          # REST call
-          expect(node).to receive(:save)
-        end
-
-        it "runs successfully without enabling the audit runner" do
-          client.run
+    describe "when converge errors" do
+      include_context "a client run"
+      include_context "converge failed"
 
-          # fork is stubbed, so we can see the outcome of the run
-          expect(node.automatic_attrs[:platform]).to eq("example-platform")
-          expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
+      describe "when audit phase errors" do
+        include_context "audit phase failed with error"
+        include_examples "a failed run" do
+          let(:run_errors) { [converge_error, audit_error] }
         end
       end
-    end
-
-    describe "when audits are disabled" do
-      include_context "a client run" do
-
-        before do
-          Chef::Config[:audit_mode] = :disabled
-        end
 
-        def stub_for_audit
-          expect(Chef::Audit::Runner).to_not receive(:new)
+      describe "when audit phase completed" do
+        include_context "audit phase completed"
+        include_examples "a failed run" do
+          let(:run_errors) { [converge_error] }
         end
+      end
 
-        it "runs successfully without enabling the audit runner" do
-          client.run
-
-          # fork is stubbed, so we can see the outcome of the run
-          expect(node.automatic_attrs[:platform]).to eq("example-platform")
-          expect(node.automatic_attrs[:platform_version]).to eq("example-platform-1.0")
+      describe "when audit phase completed with failed controls" do
+        include_context "audit phase completed with failed controls"
+        include_examples "a failed run" do
+          let(:run_errors) { [converge_error, audit_error] }
         end
       end
     end
-
   end
 
-
   describe "when handling run failures" do
-
     it "should remove the run_lock on failure of #load_node" do
       @run_lock = double("Chef::RunLock", :acquire => true)
       allow(Chef::RunLock).to receive(:new).and_return(@run_lock)
@@ -673,15 +355,18 @@ describe Chef::Client do
 
       # build_node will call Node#expand! with server, which will
       # eventually hit the server to expand the included role.
-      mock_chef_rest = double("Chef::REST")
-      expect(mock_chef_rest).to receive(:get_rest).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1)
-      expect(Chef::REST).to receive(:new).and_return(mock_chef_rest)
+      mock_chef_rest = double("Chef::ServerAPI")
+      expect(mock_chef_rest).to receive(:get).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1.to_hash)
+      expect(Chef::ServerAPI).to receive(:new).and_return(mock_chef_rest)
 
       # check pre-conditions.
       expect(node[:roles]).to be_nil
       expect(node[:recipes]).to be_nil
+      expect(node[:expanded_run_list]).to be_nil
 
       allow(client.policy_builder).to receive(:node).and_return(node)
+      client.policy_builder.select_implementation(node)
+      allow(client.policy_builder.implementation).to receive(:node).and_return(node)
 
       # chefspec and possibly others use the return value of this method
       expect(client.build_node).to eq(node)
@@ -691,21 +376,26 @@ describe Chef::Client do
       expect(node[:roles].length).to eq(1)
       expect(node[:roles]).to include("role_containing_cookbook1")
       expect(node[:recipes]).not_to be_nil
-      expect(node[:recipes].length).to eq(1)
+      expect(node[:recipes].length).to eq(2)
       expect(node[:recipes]).to include("cookbook1")
+      expect(node[:recipes]).to include("cookbook1::default")
+      expect(node[:expanded_run_list]).not_to be_nil
+      expect(node[:expanded_run_list].length).to eq(1)
+      expect(node[:expanded_run_list]).to include("cookbook1::default")
     end
 
     it "should set the environment from the specified configuration value" do
       expect(node.chef_environment).to eq("_default")
       Chef::Config[:environment] = "A"
 
-      test_env = Chef::Environment.new
-      test_env.name("A")
+      test_env = { "name" => "A" }
 
-      mock_chef_rest = double("Chef::REST")
-      expect(mock_chef_rest).to receive(:get_rest).with("environments/A").and_return(test_env)
-      expect(Chef::REST).to receive(:new).and_return(mock_chef_rest)
+      mock_chef_rest = double("Chef::ServerAPI")
+      expect(mock_chef_rest).to receive(:get).with("environments/A").and_return(test_env)
+      expect(Chef::ServerAPI).to receive(:new).and_return(mock_chef_rest)
       allow(client.policy_builder).to receive(:node).and_return(node)
+      client.policy_builder.select_implementation(node)
+      allow(client.policy_builder.implementation).to receive(:node).and_return(node)
       expect(client.build_node).to eq(node)
 
       expect(node.chef_environment).to eq("A")
@@ -715,7 +405,7 @@ describe Chef::Client do
   describe "windows_admin_check" do
     context "platform is not windows" do
       before do
-        allow(Chef::Platform).to receive(:windows?).and_return(false)
+        allow(ChefConfig).to receive(:windows?).and_return(false)
       end
 
       it "shouldn't be called" do
@@ -726,7 +416,7 @@ describe Chef::Client do
 
     context "platform is windows" do
       before do
-        allow(Chef::Platform).to receive(:windows?).and_return(true)
+        allow(ChefConfig).to receive(:windows?).and_return(true)
       end
 
       it "should be called" do
@@ -775,6 +465,7 @@ describe Chef::Client do
       Chef::Config[:solo] = true
       Chef::Config[:cookbook_path] = ["/path/to/invalid/cookbook_path"]
     end
+
     context "when any directory of cookbook_path contains no cookbook" do
       it "raises CookbookNotFound error" do
         expect do
@@ -819,4 +510,35 @@ describe Chef::Client do
     end
 
   end
+
+  describe "always attempt to run handlers" do
+    subject { client }
+    before do
+      # fail on the first thing in begin block
+      allow_any_instance_of(Chef::RunLock).to receive(:save_pid).and_raise(NoMethodError)
+    end
+
+    context "when audit mode is enabled" do
+      before do
+        Chef::Config[:audit_mode] = :enabled
+      end
+      it "should run exception handlers on early fail" do
+        expect(subject).to receive(:run_failed)
+        expect { subject.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
+          expect(error.wrapped_errors.size).to eq 1
+          expect(error.wrapped_errors).to include(NoMethodError)
+        end
+      end
+    end
+
+    context "when audit mode is disabled" do
+      before do
+        Chef::Config[:audit_mode] = :disabled
+      end
+      it "should run exception handlers on early fail" do
+        expect(subject).to receive(:run_failed)
+        expect { subject.run }.to raise_error(NoMethodError)
+      end
+    end
+  end
 end
diff --git a/spec/unit/config_fetcher_spec.rb b/spec/unit/config_fetcher_spec.rb
index 1b4a490..35cf27f 100644
--- a/spec/unit/config_fetcher_spec.rb
+++ b/spec/unit/config_fetcher_spec.rb
@@ -1,13 +1,13 @@
-require 'spec_helper'
-require 'chef/config_fetcher'
+require "spec_helper"
+require "chef/config_fetcher"
 
 describe Chef::ConfigFetcher do
-  let(:valid_json) { Chef::JSONCompat.to_json({:a=>"b"}) }
+  let(:valid_json) { Chef::JSONCompat.to_json({ :a => "b" }) }
   let(:invalid_json) { %q[{"syntax-error": "missing quote}] }
   let(:http) { double("Chef::HTTP::Simple") }
 
   let(:config_location_regex) { Regexp.escape(config_location) }
-  let(:invalid_json_error_regex) { %r[Could not parse the provided JSON file \(#{config_location_regex}\)] }
+  let(:invalid_json_error_regex) { %r{Could not parse the provided JSON file \(#{config_location_regex}\)} }
 
   let(:fetcher) { Chef::ConfigFetcher.new(config_location) }
 
@@ -22,24 +22,37 @@ describe Chef::ConfigFetcher do
       expect(fetcher.read_config).to eq(config_content)
     end
 
+    it "gives the expanded path to the config file" do
+      expect(fetcher.expanded_path).to eq(File.expand_path(config_location))
+    end
+
+    context "with a relative path" do
+
+      let(:config_location) { "client.rb" }
+
+      it "gives the expanded path to the config file" do
+        expected = File.join(Dir.pwd, config_location)
+        expect(fetcher.expanded_path).to eq(expected)
+      end
+
+    end
+
     context "and consuming JSON" do
 
       let(:config_location) { "/etc/chef/first-boot.json" }
 
-
       it "returns the parsed JSON" do
         expect(::File).to receive(:read).
           with(config_location).
           and_return(valid_json)
 
-        expect(fetcher.fetch_json).to eq({"a" => "b"})
+        expect(fetcher.fetch_json).to eq({ "a" => "b" })
       end
 
       context "and the JSON is invalid" do
 
         it "reports the JSON error" do
 
-
           expect(::File).to receive(:read).
             with(config_location).
             and_return(invalid_json)
@@ -53,45 +66,60 @@ describe Chef::ConfigFetcher do
 
   end
 
-  context "when loading a file over HTTP" do
+  context "with an HTTP URL config location" do
 
     let(:config_location) { "https://example.com/client.rb" }
     let(:config_content) { "# The client.rb content" }
 
-    before do
-      expect(Chef::HTTP::Simple).to receive(:new).
-        with(config_location).
-        and_return(http)
+    it "returns the config location unchanged for #expanded_path" do
+      expect(fetcher.expanded_path).to eq(config_location)
     end
 
-    it "reads the file over HTTP" do
-        expect(http).to receive(:get).
-          with("").and_return(config_content)
-      expect(fetcher.read_config).to eq(config_content)
-    end
+    describe "reading the file" do
 
-    context "and consuming JSON" do
-      let(:config_location) { "https://example.com/foo.json" }
+      before do
+        expect(Chef::HTTP::Simple).to receive(:new).
+          with(config_location).
+          and_return(http)
+      end
 
-      it "fetches the file and parses it" do
+      it "reads the file over HTTP" do
         expect(http).to receive(:get).
-          with("").and_return(valid_json)
-        expect(fetcher.fetch_json).to eq({"a" => "b"})
+          with("").and_return(config_content)
+        expect(fetcher.read_config).to eq(config_content)
       end
 
-      context "and the JSON is invalid" do
-        it "reports the JSON error" do
+      context "and consuming JSON" do
+        let(:config_location) { "https://example.com/foo.json" }
+
+        it "fetches the file and parses it" do
           expect(http).to receive(:get).
-            with("").and_return(invalid_json)
+            with("").and_return(valid_json)
+          expect(fetcher.fetch_json).to eq({ "a" => "b" })
+        end
 
-          expect(Chef::Application).to receive(:fatal!).
-            with(invalid_json_error_regex, 2)
-          fetcher.fetch_json
+        context "and the JSON is invalid" do
+          it "reports the JSON error" do
+            expect(http).to receive(:get).
+              with("").and_return(invalid_json)
+
+            expect(Chef::Application).to receive(:fatal!).
+              with(invalid_json_error_regex, 2)
+            fetcher.fetch_json
+          end
         end
       end
     end
 
   end
 
+  context "with a nil config file argument" do
+
+    let(:config_location) { nil }
+
+    it "returns the config location unchanged for #expanded_path" do
+      expect(fetcher.expanded_path).to eq(nil)
+    end
+  end
 
 end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index 6ea6724..68cb589 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -1,544 +1,31 @@
-#
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
 
-require 'spec_helper'
-require 'chef/exceptions'
-require 'chef/util/path_helper'
+require "spec_helper"
 
-describe Chef::Config do
-  describe "config attribute writer: chef_server_url" do
-    before do
-      Chef::Config.chef_server_url = "https://junglist.gen.nz"
-    end
-
-    it "sets the server url" do
-      expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
-    end
-
-    context "when the url has a leading space" do
-      before do
-        Chef::Config.chef_server_url = " https://junglist.gen.nz"
-      end
-
-      it "strips the space from the url when setting" do
-        expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
-      end
-
-    end
+require "chef/config"
 
-    context "when the url is a frozen string" do
-      before do
-        Chef::Config.chef_server_url = " https://junglist.gen.nz".freeze
-      end
+RSpec.describe Chef::Config do
 
-      it "strips the space from the url when setting without raising an error" do
-        expect(Chef::Config.chef_server_url).to eq("https://junglist.gen.nz")
-      end
+  shared_examples_for "deprecated by ohai but not deprecated" do
+    it "does not emit a deprecation warning when set" do
+      expect(Chef::Log).to_not receive(:warn).
+        with(/Ohai::Config\[:#{option}\] is deprecated/)
+      Chef::Config[option] = value
+      expect(Chef::Config[option]).to eq(value)
     end
-
   end
 
-  describe "when configuring formatters" do
-      # if TTY and not(force-logger)
-      #   formatter = configured formatter or default formatter
-      #   formatter goes to STDOUT/ERR
-      #   if log file is writeable
-      #     log level is configured level or info
-      #     log location is file
-      #   else
-      #     log level is warn
-      #     log location is STDERR
-      #    end
-      # elsif not(TTY) and force formatter
-      #   formatter = configured formatter or default formatter
-      #   if log_location specified
-      #     formatter goes to log_location
-      #   else
-      #     formatter goes to STDOUT/ERR
-      #   end
-      # else
-      #   formatter = "null"
-      #   log_location = configured-value or defualt
-      #   log_level = info or defualt
-      # end
-      #
-    it "has an empty list of formatters by default" do
-      expect(Chef::Config.formatters).to eq([])
-    end
-
-    it "configures a formatter with a short name" do
-      Chef::Config.add_formatter(:doc)
-      expect(Chef::Config.formatters).to eq([[:doc, nil]])
+  describe ":log_level" do
+    include_examples "deprecated by ohai but not deprecated" do
+      let(:option) { :log_level }
+      let(:value) { :debug }
     end
-
-    it "configures a formatter with a file output" do
-      Chef::Config.add_formatter(:doc, "/var/log/formatter.log")
-      expect(Chef::Config.formatters).to eq([[:doc, "/var/log/formatter.log"]])
-    end
-
   end
 
-  describe "class method: manage_secret_key" do
-    before do
-      allow(Chef::FileCache).to receive(:load).and_return(true)
-      allow(Chef::FileCache).to receive(:has_key?).with("chef_server_cookie_id").and_return(false)
+  describe ":log_location" do
+    include_examples "deprecated by ohai but not deprecated" do
+      let(:option) { :log_location }
+      let(:value) { "path/to/log" }
     end
-
-    it "should generate and store a chef server cookie id" do
-      expect(Chef::FileCache).to receive(:store).with("chef_server_cookie_id", /\w{40}/).and_return(true)
-      Chef::Config.manage_secret_key
-    end
-
-    describe "when the filecache has a chef server cookie id key" do
-      before do
-        allow(Chef::FileCache).to receive(:has_key?).with("chef_server_cookie_id").and_return(true)
-      end
-
-      it "should not generate and store a chef server cookie id" do
-        expect(Chef::FileCache).not_to receive(:store).with("chef_server_cookie_id", /\w{40}/)
-        Chef::Config.manage_secret_key
-      end
-    end
-
   end
 
-  [ false, true ].each do |is_windows|
-
-    context "On #{is_windows ? 'Windows' : 'Unix'}" do
-      def to_platform(*args)
-        Chef::Config.platform_specific_path(*args)
-      end
-
-      before :each do
-        allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
-      end
-
-      describe "class method: platform_specific_path" do
-        if is_windows
-          it "should return a windows path on windows systems" do
-            path = "/etc/chef/cookbooks"
-            allow(Chef::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
-            # match on a regex that looks for the base path with an optional
-            # system drive at the beginning (c:)
-            # system drive is not hardcoded b/c it can change and b/c it is not present on linux systems
-            expect(Chef::Config.platform_specific_path(path)).to eq("C:\\chef\\cookbooks")
-          end
-        else
-          it "should return given path on non-windows systems" do
-            path = "/etc/chef/cookbooks"
-            expect(Chef::Config.platform_specific_path(path)).to eq("/etc/chef/cookbooks")
-          end
-        end
-      end
-
-      describe "default values" do
-        let :primary_cache_path do
-          if is_windows
-            "#{Chef::Config.env['SYSTEMDRIVE']}\\chef"
-          else
-            "/var/chef"
-          end
-        end
-
-        let :secondary_cache_path do
-          if is_windows
-            "#{Chef::Config[:user_home]}\\.chef"
-          else
-            "#{Chef::Config[:user_home]}/.chef"
-          end
-        end
-
-        before do
-          if is_windows
-            allow(Chef::Config).to receive(:env).and_return({ 'SYSTEMDRIVE' => 'C:' })
-            Chef::Config[:user_home] = 'C:\Users\charlie'
-          else
-            Chef::Config[:user_home] = '/Users/charlie'
-          end
-
-          allow(Chef::Config).to receive(:path_accessible?).and_return(false)
-        end
-
-        describe "Chef::Config[:cache_path]" do
-          context "when /var/chef exists and is accessible" do
-            it "defaults to /var/chef" do
-              allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var/chef")).and_return(true)
-              expect(Chef::Config[:cache_path]).to eq(primary_cache_path)
-            end
-          end
-
-          context "when /var/chef does not exist and /var is accessible" do
-            it "defaults to /var/chef" do
-              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
-              allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(true)
-              expect(Chef::Config[:cache_path]).to eq(primary_cache_path)
-            end
-          end
-
-          context "when /var/chef does not exist and /var is not accessible" do
-            it "defaults to $HOME/.chef" do
-              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(false)
-              allow(Chef::Config).to receive(:path_accessible?).with(to_platform("/var")).and_return(false)
-              expect(Chef::Config[:cache_path]).to eq(secondary_cache_path)
-            end
-          end
-
-          context "when /var/chef exists and is not accessible" do
-            it "defaults to $HOME/.chef" do
-              allow(File).to receive(:exists?).with(to_platform("/var/chef")).and_return(true)
-              allow(File).to receive(:readable?).with(to_platform("/var/chef")).and_return(true)
-              allow(File).to receive(:writable?).with(to_platform("/var/chef")).and_return(false)
-
-              expect(Chef::Config[:cache_path]).to eq(secondary_cache_path)
-            end
-          end
-
-          context "when chef is running in local mode" do
-            before do
-              Chef::Config.local_mode = true
-            end
-
-            context "and config_dir is /a/b/c" do
-              before do
-                Chef::Config.config_dir to_platform('/a/b/c')
-              end
-
-              it "cache_path is /a/b/c/local-mode-cache" do
-                expect(Chef::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
-              end
-            end
-
-            context "and config_dir is /a/b/c/" do
-              before do
-                Chef::Config.config_dir to_platform('/a/b/c/')
-              end
-
-              it "cache_path is /a/b/c/local-mode-cache" do
-                expect(Chef::Config.cache_path).to eq(to_platform('/a/b/c/local-mode-cache'))
-              end
-            end
-          end
-        end
-
-        it "Chef::Config[:file_backup_path] defaults to /var/chef/backup" do
-          allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
-          backup_path = is_windows ? "#{primary_cache_path}\\backup" : "#{primary_cache_path}/backup"
-          expect(Chef::Config[:file_backup_path]).to eq(backup_path)
-        end
-
-        it "Chef::Config[:ssl_verify_mode] defaults to :verify_peer" do
-          expect(Chef::Config[:ssl_verify_mode]).to eq(:verify_peer)
-        end
-
-        it "Chef::Config[:ssl_ca_path] defaults to nil" do
-          expect(Chef::Config[:ssl_ca_path]).to be_nil
-        end
-
-        # TODO can this be removed?
-        if !is_windows
-          it "Chef::Config[:ssl_ca_file] defaults to nil" do
-            expect(Chef::Config[:ssl_ca_file]).to be_nil
-          end
-        end
-
-        it "Chef::Config[:data_bag_path] defaults to /var/chef/data_bags" do
-          allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
-          data_bag_path = is_windows ? "#{primary_cache_path}\\data_bags" : "#{primary_cache_path}/data_bags"
-          expect(Chef::Config[:data_bag_path]).to eq(data_bag_path)
-        end
-
-        it "Chef::Config[:environment_path] defaults to /var/chef/environments" do
-          allow(Chef::Config).to receive(:cache_path).and_return(primary_cache_path)
-          environment_path = is_windows ? "#{primary_cache_path}\\environments" : "#{primary_cache_path}/environments"
-          expect(Chef::Config[:environment_path]).to eq(environment_path)
-        end
-
-        describe "setting the config dir" do
-
-          context "when the config file is /etc/chef/client.rb" do
-
-            before do
-              Chef::Config.config_file = to_platform("/etc/chef/client.rb")
-            end
-
-            it "config_dir is /etc/chef" do
-              expect(Chef::Config.config_dir).to eq(to_platform("/etc/chef"))
-            end
-
-            context "and chef is running in local mode" do
-              before do
-                Chef::Config.local_mode = true
-              end
-
-              it "config_dir is /etc/chef" do
-                expect(Chef::Config.config_dir).to eq(to_platform("/etc/chef"))
-              end
-            end
-
-            context "when config_dir is set to /other/config/dir/" do
-              before do
-                Chef::Config.config_dir = to_platform("/other/config/dir/")
-              end
-
-              it "yields the explicit value" do
-                expect(Chef::Config.config_dir).to eq(to_platform("/other/config/dir/"))
-              end
-            end
-
-          end
-
-          context "when the user's home dir is /home/charlie/" do
-            before do
-              Chef::Config.user_home = to_platform("/home/charlie")
-            end
-
-            it "config_dir is /home/charlie/.chef/" do
-              expect(Chef::Config.config_dir).to eq(Chef::Util::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
-            end
-
-            context "and chef is running in local mode" do
-              before do
-                Chef::Config.local_mode = true
-              end
-
-              it "config_dir is /home/charlie/.chef/" do
-                expect(Chef::Config.config_dir).to eq(Chef::Util::PathHelper.join(to_platform("/home/charlie/.chef"), ''))
-              end
-            end
-          end
-
-        end
-
-        if is_windows
-          describe "finding the windows embedded dir" do
-            let(:default_config_location) { "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
-            let(:alternate_install_location) { "c:/my/alternate/install/place/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
-            let(:non_omnibus_location) { "c:/my/dev/stuff/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" }
-
-            let(:default_ca_file) { "c:/opscode/chef/embedded/ssl/certs/cacert.pem" }
-
-            it "finds the embedded dir in the default location" do
-              allow(Chef::Config).to receive(:_this_file).and_return(default_config_location)
-              expect(Chef::Config.embedded_dir).to eq("c:/opscode/chef/embedded")
-            end
-
-            it "finds the embedded dir in a custom install location" do
-              allow(Chef::Config).to receive(:_this_file).and_return(alternate_install_location)
-              expect(Chef::Config.embedded_dir).to eq("c:/my/alternate/install/place/chef/embedded")
-            end
-
-            it "doesn't error when not in an omnibus install" do
-              allow(Chef::Config).to receive(:_this_file).and_return(non_omnibus_location)
-              expect(Chef::Config.embedded_dir).to be_nil
-            end
-
-            it "sets the ssl_ca_cert path if the cert file is available" do
-              allow(Chef::Config).to receive(:_this_file).and_return(default_config_location)
-              allow(File).to receive(:exist?).with(default_ca_file).and_return(true)
-              expect(Chef::Config.ssl_ca_file).to eq(default_ca_file)
-            end
-          end
-        end
-      end
-
-      describe "Chef::Config[:user_home]" do
-        it "should set when HOME is provided" do
-          expected = to_platform("/home/kitten")
-          allow(Chef::Util::PathHelper).to receive(:home).and_return(expected)
-          expect(Chef::Config[:user_home]).to eq(expected)
-        end
-
-        it "falls back to the current working directory when HOME and USERPROFILE is not set" do
-          allow(Chef::Util::PathHelper).to receive(:home).and_return(nil)
-          expect(Chef::Config[:user_home]).to eq(Dir.pwd)
-        end
-      end
-
-      describe "Chef::Config[:encrypted_data_bag_secret]" do
-        let(:db_secret_default_path){ to_platform("/etc/chef/encrypted_data_bag_secret") }
-
-        before do
-          allow(File).to receive(:exist?).with(db_secret_default_path).and_return(secret_exists)
-        end
-
-        context "/etc/chef/encrypted_data_bag_secret exists" do
-          let(:secret_exists) { true }
-          it "sets the value to /etc/chef/encrypted_data_bag_secret" do
-            expect(Chef::Config[:encrypted_data_bag_secret]).to eq db_secret_default_path
-          end
-        end
-
-        context "/etc/chef/encrypted_data_bag_secret does not exist" do
-          let(:secret_exists) { false }
-          it "sets the value to nil" do
-            expect(Chef::Config[:encrypted_data_bag_secret]).to be_nil
-          end
-        end
-      end
-
-      describe "Chef::Config[:event_handlers]" do
-        it "sets a event_handlers to an empty array by default" do
-          expect(Chef::Config[:event_handlers]).to eq([])
-        end
-        it "should be able to add custom handlers" do
-          o = Object.new
-          Chef::Config[:event_handlers] << o
-          expect(Chef::Config[:event_handlers]).to be_include(o)
-        end
-      end
-
-      describe "Chef::Config[:user_valid_regex]" do
-        context "on a platform that is not Windows" do
-          it "allows one letter usernames" do
-            any_match = Chef::Config[:user_valid_regex].any? { |regex| regex.match('a') }
-            expect(any_match).to be_truthy
-          end
-        end
-      end
-
-      describe "Chef::Config[:internal_locale]" do
-        let(:shell_out) do
-          double("Chef::Mixin::ShellOut double", :exitstatus => 0, :stdout => locales)
-        end
-
-        let(:locales) { locale_array.join("\n") }
-
-        before do
-          allow(Chef::Config).to receive(:shell_out_with_systems_locale!).with("locale -a").and_return(shell_out)
-        end
-
-        shared_examples_for "a suitable locale" do
-          it "returns an English UTF-8 locale" do
-            expect(Chef::Log).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
-            expect(Chef::Log).to_not receive(:debug).with(/Defaulting to locale en_US.UTF-8 on Windows/)
-            expect(Chef::Log).to_not receive(:debug).with(/No usable locale -a command found/)
-            expect(Chef::Config.guess_internal_locale).to eq expected_locale
-          end
-        end
-
-        context "when the result includes 'C.UTF-8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { [expected_locale, "en_US.UTF-8"] }
-            let(:expected_locale) { "C.UTF-8" }
-          end
-        end
-
-        context "when the result includes 'en_US.UTF-8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { ["en_CA.UTF-8", expected_locale, "en_NZ.UTF-8"] }
-            let(:expected_locale) { "en_US.UTF-8" }
-          end
-        end
-
-        context "when the result includes 'en_US.utf8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { ["en_CA.utf8", "en_US.utf8", "en_NZ.utf8"] }
-            let(:expected_locale) { "en_US.UTF-8" }
-          end
-        end
-
-        context "when the result includes 'en.UTF-8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { ["en.ISO8859-1", expected_locale] }
-            let(:expected_locale) { "en.UTF-8" }
-          end
-        end
-
-        context "when the result includes 'en_*.UTF-8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { [expected_locale, "en_CA.UTF-8", "en_GB.UTF-8"] }
-            let(:expected_locale) { "en_AU.UTF-8" }
-          end
-        end
-
-        context "when the result includes 'en_*.utf8'" do
-          include_examples "a suitable locale" do
-            let(:locale_array) { ["en_AU.utf8", "en_CA.utf8", "en_GB.utf8"] }
-            let(:expected_locale) { "en_AU.UTF-8" }
-          end
-        end
-
-        context "when the result does not include 'en_*.UTF-8'" do
-          let(:locale_array) { ["af_ZA", "af_ZA.ISO8859-1", "af_ZA.ISO8859-15", "af_ZA.UTF-8"] }
-
-          it "should fall back to C locale" do
-            expect(Chef::Log).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
-            expect(Chef::Config.guess_internal_locale).to eq 'C'
-          end
-        end
-
-        context "on error" do
-          let(:locale_array) { [] }
-
-          before do
-            allow(Chef::Config).to receive(:shell_out_with_systems_locale!).and_raise("THIS IS AN ERROR")
-          end
-
-          it "should default to 'en_US.UTF-8'" do
-            if is_windows
-              expect(Chef::Log).to receive(:debug).with("Defaulting to locale en_US.UTF-8 on Windows, until it matters that we do something else.")
-            else
-              expect(Chef::Log).to receive(:debug).with("No usable locale -a command found, assuming you have en_US.UTF-8 installed.")
-            end
-            expect(Chef::Config.guess_internal_locale).to eq "en_US.UTF-8"
-          end
-        end
-      end
-    end
-  end
-
-  describe "Treating deprecation warnings as errors" do
-
-    context "when using our default RSpec configuration" do
-
-      it "defaults to treating deprecation warnings as errors" do
-        expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true)
-      end
-
-      it "sets CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS environment variable" do
-        expect(ENV['CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS']).to eq("1")
-      end
-
-      it "treats deprecation warnings as errors in child processes when testing" do
-        # Doing a full integration test where we launch a child process is slow
-        # and liable to break for weird reasons (bundler env stuff, etc.), so
-        # we're just checking that the presence of the environment variable
-        # causes treat_deprecation_warnings_as_errors to be set to true after a
-        # config reset.
-        Chef::Config.reset
-        expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(true)
-      end
-
-    end
-
-    context "outside of our test environment" do
-
-      before do
-        ENV.delete('CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS')
-        Chef::Config.reset
-      end
-
-      it "defaults to NOT treating deprecation warnings as errors" do
-        expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be(false)
-      end
-    end
-
-
-  end
 end
diff --git a/spec/unit/cookbook/chefignore_spec.rb b/spec/unit/cookbook/chefignore_spec.rb
index 9f5546d..95b9295 100644
--- a/spec/unit/cookbook/chefignore_spec.rb
+++ b/spec/unit/cookbook/chefignore_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,35 +15,35 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Cookbook::Chefignore do
   before do
-    @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+    @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
   end
 
   it "loads the globs in the chefignore file" do
-    expect(@chefignore.ignores).to match_array(%w[recipes/ignoreme.rb ignored])
+    expect(@chefignore.ignores).to match_array(%w{recipes/ignoreme.rb ignored})
   end
 
   it "removes items from an array that match the ignores" do
-    file_list = %w[ recipes/ignoreme.rb recipes/dontignoreme.rb ]
-    expect(@chefignore.remove_ignores_from(file_list)).to eq(%w[recipes/dontignoreme.rb])
+    file_list = %w{ recipes/ignoreme.rb recipes/dontignoreme.rb }
+    expect(@chefignore.remove_ignores_from(file_list)).to eq(%w{recipes/dontignoreme.rb})
   end
 
   it "determines if a file is ignored" do
-    expect(@chefignore.ignored?('ignored')).to be_truthy
-    expect(@chefignore.ignored?('recipes/ignoreme.rb')).to be_truthy
-    expect(@chefignore.ignored?('recipes/dontignoreme.rb')).to be_falsey
+    expect(@chefignore.ignored?("ignored")).to be_truthy
+    expect(@chefignore.ignored?("recipes/ignoreme.rb")).to be_truthy
+    expect(@chefignore.ignored?("recipes/dontignoreme.rb")).to be_falsey
   end
 
   context "when using the single cookbook pattern" do
     before do
-      @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'standalone_cookbook'))
+      @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, "standalone_cookbook"))
     end
 
     it "loads the globs in the chefignore file" do
-      expect(@chefignore.ignores).to match_array(%w[recipes/ignoreme.rb ignored vendor/bundle/*])
+      expect(@chefignore.ignores).to match_array(%w{recipes/ignoreme.rb ignored vendor/bundle/*})
     end
   end
 end
diff --git a/spec/unit/cookbook/cookbook_version_loader_spec.rb b/spec/unit/cookbook/cookbook_version_loader_spec.rb
index 2c4ad11..a32eb05 100644
--- a/spec/unit/cookbook/cookbook_version_loader_spec.rb
+++ b/spec/unit/cookbook/cookbook_version_loader_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Cookbook::CookbookVersionLoader do
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
   end
 
   describe "loading a cookbook" do
@@ -58,8 +58,8 @@ describe Chef::Cookbook::CookbookVersionLoader do
     end
 
     it "loads libraries" do
-      expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap.rb'))
-      expect(loaded_cookbook.library_filenames).to include(full_path('/libraries/openldap/version.rb'))
+      expect(loaded_cookbook.library_filenames).to include(full_path("/libraries/openldap.rb"))
+      expect(loaded_cookbook.library_filenames).to include(full_path("/libraries/openldap/version.rb"))
     end
 
     it "loads static files in the files/ dir" do
@@ -184,4 +184,3 @@ describe Chef::Cookbook::CookbookVersionLoader do
   end
 
 end
-
diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb
index 145541a..139a593 100644
--- a/spec/unit/cookbook/file_vendor_spec.rb
+++ b/spec/unit/cookbook/file_vendor_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Cookbook::FileVendor do
 
@@ -23,7 +23,7 @@ describe Chef::Cookbook::FileVendor do
 
   context "when configured to fetch files over http" do
 
-    let(:http) { double("Chef::REST") }
+    let(:http) { double("Chef::ServerAPI") }
 
     before do
       file_vendor_class.fetch_from_remote(http)
@@ -40,7 +40,7 @@ describe Chef::Cookbook::FileVendor do
     context "with a manifest from a cookbook version" do
 
       # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
-      let(:manifest) { {:cookbook_name => "bob", :name => "bob-1.2.3"} }
+      let(:manifest) { { :cookbook_name => "bob", :name => "bob-1.2.3" } }
 
       it "creates a RemoteFileVendor for a given manifest" do
         file_vendor = file_vendor_class.create_from_manifest(manifest)
@@ -54,7 +54,7 @@ describe Chef::Cookbook::FileVendor do
     context "with a manifest from a cookbook artifact" do
 
       # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
-      let(:manifest) { {:name => "bob"} }
+      let(:manifest) { { :name => "bob" } }
 
       it "creates a RemoteFileVendor for a given manifest" do
         file_vendor = file_vendor_class.create_from_manifest(manifest)
@@ -68,10 +68,10 @@ describe Chef::Cookbook::FileVendor do
 
   context "when configured to load files from disk" do
 
-    let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] }
+    let(:cookbook_path) { %w{/var/chef/cookbooks /var/chef/other_cookbooks} }
 
     # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest
-    let(:manifest) { {:cookbook_name => "bob"} }
+    let(:manifest) { { :cookbook_name => "bob" } }
 
     before do
       file_vendor_class.fetch_from_disk(cookbook_path)
@@ -95,4 +95,3 @@ describe Chef::Cookbook::FileVendor do
   end
 
 end
-
diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb
index 760ae5d..ff18333 100644
--- a/spec/unit/cookbook/metadata_spec.rb
+++ b/spec/unit/cookbook/metadata_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/cookbook/metadata'
+require "spec_helper"
+require "chef/cookbook/metadata"
 
 describe Chef::Cookbook::Metadata do
 
@@ -30,7 +30,7 @@ describe Chef::Cookbook::Metadata do
                   :maintainer_email, :license, :platforms, :dependencies,
                   :recommendations, :suggestions, :conflicting, :providing,
                   :replacing, :attributes, :groupings, :recipes, :version,
-                  :source_url, :issues_url ]
+                  :source_url, :issues_url, :privacy, :ohai_versions, :chef_versions ]
     end
 
     it "does not depend on object identity for equality" do
@@ -142,11 +142,15 @@ describe Chef::Cookbook::Metadata do
     end
 
     it "has an empty source_url string" do
-      expect(metadata.source_url).to eq('')
+      expect(metadata.source_url).to eq("")
     end
 
     it "has an empty issues_url string" do
-      expect(metadata.issues_url).to eq('')
+      expect(metadata.issues_url).to eq("")
+    end
+
+    it "is not private" do
+      expect(metadata.privacy).to eq(false)
     end
   end
 
@@ -185,7 +189,7 @@ describe Chef::Cookbook::Metadata do
   describe "adding a supported platform" do
     it "should support adding a supported platform with a single expression" do
       metadata.supports("ubuntu", ">= 8.04")
-      expect(metadata.platforms["ubuntu"]).to eq('>= 8.04')
+      expect(metadata.platforms["ubuntu"]).to eq(">= 8.04")
     end
   end
 
@@ -198,9 +202,10 @@ describe Chef::Cookbook::Metadata do
       :long_description => "Much Longer\nSeriously",
       :version => "0.6.0",
       :source_url => "http://example.com",
-      :issues_url => "http://example.com/issues"
+      :issues_url => "http://example.com/issues",
+      :privacy => true,
     }
-    params.sort { |a,b| a.to_s <=> b.to_s }.each do |field, field_value|
+    params.sort { |a, b| a.to_s <=> b.to_s }.each do |field, field_value|
       describe field do
         it "should be set-able via #{field}" do
           expect(metadata.send(field, field_value)).to eql(field_value)
@@ -234,7 +239,7 @@ describe Chef::Cookbook::Metadata do
       :provides    => [ :providing, "foo::bar", "<= 0.2" ],
       :replaces    => [ :replacing, "foo::bar", "= 0.2.1" ],
     }
-    dep_types.sort { |a,b| a.to_s <=> b.to_s }.each do |dep, dep_args|
+    dep_types.sort { |a, b| a.to_s <=> b.to_s }.each do |dep, dep_args|
       check_with = dep_args.shift
       describe dep do
         it "should be set-able via #{dep}" do
@@ -255,7 +260,7 @@ describe Chef::Cookbook::Metadata do
       :provides    => [ :providing, "foo::bar", "<=0.2", "<= 0.2" ],
       :replaces    => [ :replacing, "foo::bar", "=0.2.1", "= 0.2.1" ],
     }
-    dep_types.sort { |a,b| a.to_s <=> b.to_s }.each do |dep, dep_args|
+    dep_types.sort { |a, b| a.to_s <=> b.to_s }.each do |dep, dep_args|
       check_with = dep_args.shift
       normalized_version = dep_args.pop
       describe dep do
@@ -269,7 +274,6 @@ describe Chef::Cookbook::Metadata do
       end
     end
 
-
     describe "in the obsoleted format" do
       dep_types = {
         :depends     => [ "foo::bar", "> 0.2", "< 1.0" ],
@@ -282,12 +286,11 @@ describe Chef::Cookbook::Metadata do
 
       dep_types.each do |dep, dep_args|
         it "for #{dep} raises an informative error instead of vomiting on your shoes" do
-          expect {metadata.send(dep, *dep_args)}.to raise_error(Chef::Exceptions::ObsoleteDependencySyntax)
+          expect { metadata.send(dep, *dep_args) }.to raise_error(Chef::Exceptions::ObsoleteDependencySyntax)
         end
       end
     end
 
-
     describe "with obsolete operators" do
       dep_types = {
         :depends     => [ "foo::bar", ">> 0.2"],
@@ -300,17 +303,136 @@ describe Chef::Cookbook::Metadata do
 
       dep_types.each do |dep, dep_args|
         it "for #{dep} raises an informative error instead of vomiting on your shoes" do
-          expect {metadata.send(dep, *dep_args)}.to raise_error(Chef::Exceptions::InvalidVersionConstraint)
+          expect { metadata.send(dep, *dep_args) }.to raise_error(Chef::Exceptions::InvalidVersionConstraint)
         end
       end
     end
+
+    it "strips out self-dependencies", :chef_lt_13_only do
+      metadata.name("foo")
+      expect(Chef::Log).to receive(:warn).with(
+        "Ignoring self-dependency in cookbook foo, please remove it (in the future this will be fatal)."
+      )
+      metadata.depends("foo")
+      expect(metadata.dependencies).to eql({})
+    end
+
+    it "errors on self-dependencies", :chef_gte_13_only do
+      metadata.name("foo")
+      expect { metadata.depends("foo") }.to raise_error
+      # FIXME: add the error type
+    end
+  end
+
+  describe "chef_version" do
+    def expect_chef_version_works(*args)
+      ret = []
+      args.each do |arg|
+        metadata.send(:chef_version, *arg)
+        ret << Gem::Dependency.new("chef", *arg)
+      end
+      expect(metadata.send(:chef_versions)).to eql(ret)
+    end
+
+    it "should work with a single simple constraint" do
+      expect_chef_version_works(["~> 12"])
+    end
+
+    it "should work with a single complex constraint" do
+      expect_chef_version_works([">= 12.0.1", "< 12.5.1"])
+    end
+
+    it "should work with multiple simple constraints" do
+      expect_chef_version_works(["~> 12.5.1"], ["~> 11.18.10"])
+    end
+
+    it "should work with multiple complex constraints" do
+      expect_chef_version_works([">= 11.14.2", "< 11.18.10"], [">= 12.2.1", "< 12.5.1"])
+    end
+
+    it "should fail validation on a simple pessimistic constraint" do
+      expect_chef_version_works(["~> 999.0"])
+      expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+    end
+
+    it "should fail validation when that valid chef versions are too big" do
+      expect_chef_version_works([">= 999.0", "< 999.9"])
+      expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+    end
+
+    it "should fail validation when that valid chef versions are too small" do
+      expect_chef_version_works([">= 0.0.1", "< 0.0.9"])
+      expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+    end
+
+    it "should fail validation when all ranges fail" do
+      expect_chef_version_works([">= 999.0", "< 999.9"], [">= 0.0.1", "< 0.0.9"])
+      expect { metadata.validate_chef_version! }.to raise_error(Chef::Exceptions::CookbookChefVersionMismatch)
+    end
+
+    it "should pass validation when one constraint passes" do
+      expect_chef_version_works([">= 999.0", "< 999.9"], ["= #{Chef::VERSION}"])
+      expect { metadata.validate_chef_version! }.not_to raise_error
+    end
+  end
+
+  describe "ohai_version" do
+    def expect_ohai_version_works(*args)
+      ret = []
+      args.each do |arg|
+        metadata.send(:ohai_version, *arg)
+        ret << Gem::Dependency.new("ohai", *arg)
+      end
+      expect(metadata.send(:ohai_versions)).to eql(ret)
+    end
+
+    it "should work with a single simple constraint" do
+      expect_ohai_version_works(["~> 12"])
+    end
+
+    it "should work with a single complex constraint" do
+      expect_ohai_version_works([">= 12.0.1", "< 12.5.1"])
+    end
+
+    it "should work with multiple simple constraints" do
+      expect_ohai_version_works(["~> 12.5.1"], ["~> 11.18.10"])
+    end
+
+    it "should work with multiple complex constraints" do
+      expect_ohai_version_works([">= 11.14.2", "< 11.18.10"], [">= 12.2.1", "< 12.5.1"])
+    end
+
+    it "should fail validation on a simple pessimistic constraint" do
+      expect_ohai_version_works(["~> 999.0"])
+      expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+    end
+
+    it "should fail validation when that valid chef versions are too big" do
+      expect_ohai_version_works([">= 999.0", "< 999.9"])
+      expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+    end
+
+    it "should fail validation when that valid chef versions are too small" do
+      expect_ohai_version_works([">= 0.0.1", "< 0.0.9"])
+      expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+    end
+
+    it "should fail validation when all ranges fail" do
+      expect_ohai_version_works([">= 999.0", "< 999.9"], [">= 0.0.1", "< 0.0.9"])
+      expect { metadata.validate_ohai_version! }.to raise_error(Chef::Exceptions::CookbookOhaiVersionMismatch)
+    end
+
+    it "should pass validation when one constraint passes" do
+      expect_ohai_version_works([">= 999.0", "< 999.9"], ["= #{Ohai::VERSION}"])
+      expect { metadata.validate_ohai_version! }.not_to raise_error
+    end
   end
 
   describe "attribute groupings" do
     it "should allow you set a grouping" do
       group = {
         "title" => "MySQL Tuning",
-        "description" => "Setting from the my.cnf file that allow you to tune your mysql server"
+        "description" => "Setting from the my.cnf file that allow you to tune your mysql server",
       }
       expect(metadata.grouping("/db/mysql/databases/tuning", group)).to eq(group)
     end
@@ -338,14 +460,15 @@ describe Chef::Cookbook::Metadata do
       attrs = {
         "display_name" => "MySQL Databases",
         "description" => "Description of MySQL",
-        "choice" => ['dedicated', 'shared'],
+        "choice" => ["dedicated", "shared"],
         "calculated" => false,
-        "type" => 'string',
-        "required" => 'recommended',
+        "type" => "string",
+        "required" => "recommended",
         "recipes" => [ "mysql::server", "mysql::master" ],
         "default" => [ ],
         "source_url" => "http://example.com",
-        "issues_url" => "http://example.com/issues"
+        "issues_url" => "http://example.com/issues",
+        "privacy" => true,
       }
       expect(metadata.attribute("/db/mysql/databases", attrs)).to eq(attrs)
     end
@@ -386,12 +509,24 @@ describe Chef::Cookbook::Metadata do
       }.to raise_error(ArgumentError)
     end
 
+    it "should not accept anything but true or false for the privacy flag" do
+      expect {
+        metadata.attribute("db/mysql/databases", :privacy => true)
+      }.not_to raise_error
+      expect {
+        metadata.attribute("db/mysql/databases", :privacy => false)
+      }.not_to raise_error
+      expect {
+        metadata.attribute("db/mysql/databases", :privacy => "true")
+      }.to raise_error(ArgumentError)
+    end
+
     it "should not accept anything but an array of strings for choice" do
       expect {
-        metadata.attribute("db/mysql/databases", :choice => ['dedicated', 'shared'])
+        metadata.attribute("db/mysql/databases", :choice => ["dedicated", "shared"])
       }.not_to raise_error
       expect {
-        metadata.attribute("db/mysql/databases", :choice => [10, 'shared'])
+        metadata.attribute("db/mysql/databases", :choice => [10, "shared"])
       }.to raise_error(ArgumentError)
       expect {
         metadata.attribute("db/mysql/databases", :choice => Hash.new)
@@ -403,22 +538,22 @@ describe Chef::Cookbook::Metadata do
       expect(metadata.attributes["db/mysql/databases"][:choice]).to eq([])
     end
 
-     it "should let calculated be true or false" do
-       expect {
-         metadata.attribute("db/mysql/databases", :calculated => true)
-       }.not_to raise_error
-       expect {
-         metadata.attribute("db/mysql/databases", :calculated => false)
-       }.not_to raise_error
-       expect {
-         metadata.attribute("db/mysql/databases", :calculated => Hash.new)
-       }.to raise_error(ArgumentError)
-     end
+    it "should let calculated be true or false" do
+      expect {
+        metadata.attribute("db/mysql/databases", :calculated => true)
+      }.not_to raise_error
+      expect {
+        metadata.attribute("db/mysql/databases", :calculated => false)
+      }.not_to raise_error
+      expect {
+        metadata.attribute("db/mysql/databases", :calculated => Hash.new)
+      }.to raise_error(ArgumentError)
+    end
 
-     it "should set calculated to false by default" do
-       metadata.attribute("db/mysql/databases", {})
-       expect(metadata.attributes["db/mysql/databases"][:calculated]).to eq(false)
-     end
+    it "should set calculated to false by default" do
+      metadata.attribute("db/mysql/databases", {})
+      expect(metadata.attributes["db/mysql/databases"][:calculated]).to eq(false)
+    end
 
     it "accepts String for the attribute type" do
       expect {
@@ -441,7 +576,7 @@ describe Chef::Cookbook::Metadata do
       }.not_to raise_error
     end
 
-     it "should let type be hash (backwards compatibility only)" do
+    it "should let type be hash (backwards compatibility only)" do
       expect {
         metadata.attribute("db/mysql/databases", :type => "hash")
       }.not_to raise_error
@@ -449,13 +584,13 @@ describe Chef::Cookbook::Metadata do
 
     it "should let required be required, recommended or optional" do
       expect {
-        metadata.attribute("db/mysql/databases", :required => 'required')
+        metadata.attribute("db/mysql/databases", :required => "required")
       }.not_to raise_error
       expect {
-        metadata.attribute("db/mysql/databases", :required => 'recommended')
+        metadata.attribute("db/mysql/databases", :required => "recommended")
       }.not_to raise_error
       expect {
-        metadata.attribute("db/mysql/databases", :required => 'optional')
+        metadata.attribute("db/mysql/databases", :required => "optional")
       }.not_to raise_error
     end
 
@@ -475,7 +610,7 @@ describe Chef::Cookbook::Metadata do
 
     it "should set required to 'optional' by default" do
       metadata.attribute("db/mysql/databases", {})
-      expect(metadata.attributes["db/mysql/databases"][:required]).to eq('optional')
+      expect(metadata.attributes["db/mysql/databases"][:required]).to eq("optional")
     end
 
     it "should make sure recipes is an array" do
@@ -517,7 +652,7 @@ describe Chef::Cookbook::Metadata do
       options = {
         :type => "string",
         :choice => [ "test1", "test2" ],
-        :default => "test1"
+        :default => "test1",
       }
       expect {
         metadata.attribute("test_cookbook/test", options)
@@ -526,7 +661,7 @@ describe Chef::Cookbook::Metadata do
       options = {
         :type => "boolean",
         :choice => [ true, false ],
-        :default => true
+        :default => true,
       }
       expect {
         metadata.attribute("test_cookbook/test", options)
@@ -535,7 +670,7 @@ describe Chef::Cookbook::Metadata do
       options = {
         :type => "numeric",
         :choice => [ 1337, 420 ],
-        :default => 1337
+        :default => 1337,
       }
       expect {
         metadata.attribute("test_cookbook/test", options)
@@ -544,7 +679,7 @@ describe Chef::Cookbook::Metadata do
       options = {
         :type => "numeric",
         :choice => [ true, "false" ],
-        :default => false
+        :default => false,
       }
       expect {
         metadata.attribute("test_cookbook/test", options)
@@ -555,14 +690,14 @@ describe Chef::Cookbook::Metadata do
       expect {
         attrs = {
           :calculated => true,
-          :default => [ "I thought you said calculated" ]
+          :default => [ "I thought you said calculated" ],
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.to raise_error(ArgumentError)
       expect {
         attrs = {
           :calculated => true,
-          :default => "I thought you said calculated"
+          :default => "I thought you said calculated",
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.to raise_error(ArgumentError)
@@ -572,31 +707,31 @@ describe Chef::Cookbook::Metadata do
       expect {
         attrs = {
           :choice => [ "a", "b", "c"],
-          :default => "b"
+          :default => "b",
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.not_to raise_error
       expect {
         attrs = {
           :choice => [ "a", "b", "c", "d", "e"],
-          :default => ["b", "d"]
+          :default => ["b", "d"],
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.not_to raise_error
-     end
+    end
 
     it "should error if default is not a choice" do
       expect {
         attrs = {
           :choice => [ "a", "b", "c"],
-          :default => "d"
+          :default => "d",
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.to raise_error(ArgumentError)
       expect {
         attrs = {
           :choice => [ "a", "b", "c", "d", "e"],
-          :default => ["b", "z"]
+          :default => ["b", "z"],
         }
         metadata.attribute("db/mysql/databases", attrs)
       }.to raise_error(ArgumentError)
@@ -605,7 +740,7 @@ describe Chef::Cookbook::Metadata do
 
   describe "recipes" do
     let(:cookbook) do
-      c = Chef::CookbookVersion.new('test_cookbook')
+      c = Chef::CookbookVersion.new("test_cookbook")
       c.recipe_files = [ "default.rb", "enlighten.rb" ]
       c
     end
@@ -651,9 +786,14 @@ describe Chef::Cookbook::Metadata do
       metadata.attribute "bizspark/has_login",
         :display_name => "You have nothing"
       metadata.version "1.2.3"
+      metadata.chef_version ">= 11.14.2", "< 11.18.10"
+      metadata.chef_version ">= 12.2.1", "< 12.5.1"
+      metadata.ohai_version ">= 7.1.0", "< 7.5.0"
+      metadata.ohai_version ">= 8.0.1", "< 8.6.0"
     end
 
     it "should produce the same output from to_json and Chef::JSONCompat" do
+      # XXX: fairly certain this is testing ruby method dispatch
       expect(metadata.to_json).to eq(Chef::JSONCompat.to_json(metadata))
     end
 
@@ -684,18 +824,27 @@ describe Chef::Cookbook::Metadata do
         version
         source_url
         issues_url
+        privacy
       }.each do |t|
         it "should include '#{t}'" do
           expect(deserialized_metadata[t]).to eq(metadata.send(t.to_sym))
         end
       end
+
+      %w{
+        ohai_versions
+        chef_versions
+      }.each do |t|
+        it "should include '#{t}'" do
+          expect(deserialized_metadata[t]).to eq(metadata.gem_requirements_to_array(*metadata.send(t.to_sym)))
+        end
+      end
     end
 
     describe "deserialize" do
 
       let(:deserialized_metadata) { Chef::Cookbook::Metadata.from_json(Chef::JSONCompat.to_json(metadata)) }
 
-
       it "should deserialize to a Chef::Cookbook::Metadata object" do
         expect(deserialized_metadata).to be_a_kind_of(Chef::Cookbook::Metadata)
       end
@@ -719,6 +868,9 @@ describe Chef::Cookbook::Metadata do
         version
         source_url
         issues_url
+        privacy
+        chef_versions
+        ohai_versions
       }.each do |t|
         it "should match '#{t}'" do
           expect(deserialized_metadata.send(t.to_sym)).to eq(metadata.send(t.to_sym))
@@ -736,31 +888,31 @@ describe Chef::Cookbook::Metadata do
        :suggestions,
        :conflicting,
        :replacing].each do |to_check|
-        it "should transform deprecated greater than syntax for :#{to_check.to_s}" do
+        it "should transform deprecated greater than syntax for :#{to_check}" do
           @hash[to_check.to_s]["foo::bar"] = ">> 0.2"
           deserial = Chef::Cookbook::Metadata.from_hash(@hash)
-          expect(deserial.send(to_check)["foo::bar"]).to eq('> 0.2')
+          expect(deserial.send(to_check)["foo::bar"]).to eq("> 0.2")
         end
 
-        it "should transform deprecated less than syntax for :#{to_check.to_s}" do
+        it "should transform deprecated less than syntax for :#{to_check}" do
           @hash[to_check.to_s]["foo::bar"] = "<< 0.2"
           deserial = Chef::Cookbook::Metadata.from_hash(@hash)
-          expect(deserial.send(to_check)["foo::bar"]).to eq('< 0.2')
+          expect(deserial.send(to_check)["foo::bar"]).to eq("< 0.2")
         end
 
-        it "should ignore multiple dependency constraints for :#{to_check.to_s}" do
+        it "should ignore multiple dependency constraints for :#{to_check}" do
           @hash[to_check.to_s]["foo::bar"] = [ ">= 1.0", "<= 5.2" ]
           deserial = Chef::Cookbook::Metadata.from_hash(@hash)
           expect(deserial.send(to_check)["foo::bar"]).to eq([])
         end
 
-        it "should accept an empty array of dependency constraints for :#{to_check.to_s}" do
+        it "should accept an empty array of dependency constraints for :#{to_check}" do
           @hash[to_check.to_s]["foo::bar"] = []
           deserial = Chef::Cookbook::Metadata.from_hash(@hash)
           expect(deserial.send(to_check)["foo::bar"]).to eq([])
         end
 
-        it "should accept single-element arrays of dependency constraints for :#{to_check.to_s}" do
+        it "should accept single-element arrays of dependency constraints for :#{to_check}" do
           @hash[to_check.to_s]["foo::bar"] = [ ">= 2.0" ]
           deserial = Chef::Cookbook::Metadata.from_hash(@hash)
           expect(deserial.send(to_check)["foo::bar"]).to eq(">= 2.0")
diff --git a/spec/unit/cookbook/synchronizer_spec.rb b/spec/unit/cookbook/synchronizer_spec.rb
index 2b040f3..c869ee8 100644
--- a/spec/unit/cookbook/synchronizer_spec.rb
+++ b/spec/unit/cookbook/synchronizer_spec.rb
@@ -1,6 +1,6 @@
-require 'spec_helper'
-require 'chef/cookbook/synchronizer'
-require 'chef/cookbook_version'
+require "spec_helper"
+require "chef/cookbook/synchronizer"
+require "chef/cookbook_version"
 
 describe Chef::CookbookCacheCleaner do
   describe "when cleaning up unused cookbook components" do
@@ -38,7 +38,6 @@ describe Chef::CookbookCacheCleaner do
       unused_template_files.each do |cbf|
         expect(file_cache).to receive(:delete).with(cbf)
       end
-      cookbook_hash = {"valid1"=> {}, "valid2" => {}}
       allow(cleaner).to receive(:cache).and_return(file_cache)
       cleaner.cleanup_file_cache
     end
@@ -94,7 +93,7 @@ describe Chef::CookbookSynchronizer do
 
   let(:cookbook_a_manifest) do
     segments = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
-    cookbook_a_manifest = segments.inject({}) {|h, segment| h[segment.to_s] = []; h}
+    cookbook_a_manifest = segments.inject({}) { |h, segment| h[segment.to_s] = []; h }
     cookbook_a_manifest["recipes"] = [ cookbook_a_default_recipe ]
     cookbook_a_manifest["attributes"] = [ cookbook_a_default_attrs ]
     cookbook_a_manifest["templates"] = [ cookbook_a_template ]
@@ -124,7 +123,7 @@ describe Chef::CookbookSynchronizer do
   end
 
   it "lists the cookbook names" do
-    expect(synchronizer.cookbook_names).to eq(%w[cookbook_a])
+    expect(synchronizer.cookbook_names).to eq(%w{cookbook_a})
   end
 
   it "lists the cookbook manifests" do
@@ -158,15 +157,15 @@ describe Chef::CookbookSynchronizer do
     let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
 
     let(:cookbook_manifest) do
-      {"valid1"=> {}, "valid2" => {}}
+      { "valid1" => {}, "valid2" => {} }
     end
 
     it "removes unneeded cookbooks" do
       valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}
       obsolete_cb_files = %w{cookbooks/old1/recipes/default.rb cookbooks/old2/recipes/default.rb}
       expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + obsolete_cb_files)
-      expect(file_cache).to receive(:delete).with('cookbooks/old1/recipes/default.rb')
-      expect(file_cache).to receive(:delete).with('cookbooks/old2/recipes/default.rb')
+      expect(file_cache).to receive(:delete).with("cookbooks/old1/recipes/default.rb")
+      expect(file_cache).to receive(:delete).with("cookbooks/old2/recipes/default.rb")
       allow(synchronizer).to receive(:cache).and_return(file_cache)
       synchronizer.remove_old_cookbooks
     end
@@ -176,7 +175,7 @@ describe Chef::CookbookSynchronizer do
     let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") }
 
     let(:cookbook_manifest) do
-      {"valid1"=> {}, "valid2" => {}}
+      { "valid1" => {}, "valid2" => {} }
     end
 
     it "removes only deleted files" do
@@ -187,7 +186,7 @@ describe Chef::CookbookSynchronizer do
       expect(synchronizer).to receive(:have_cookbook?).with("valid1").at_least(:once).and_return(true)
       # valid2 is a cookbook not in our run_list (we're simulating an override run_list where valid2 needs to be preserved)
       expect(synchronizer).to receive(:have_cookbook?).with("valid2").at_least(:once).and_return(false)
-      expect(file_cache).to receive(:delete).with('cookbooks/valid1/recipes/deleted.rb')
+      expect(file_cache).to receive(:delete).with("cookbooks/valid1/recipes/deleted.rb")
       expect(synchronizer).to receive(:cookbook_segment).with("valid1", "recipes").at_least(:once).and_return([ { "path" => "recipes/default.rb" }])
       allow(synchronizer).to receive(:cache).and_return(file_cache)
       synchronizer.remove_deleted_files
@@ -224,8 +223,8 @@ describe Chef::CookbookSynchronizer do
       and_return(false)
 
     # Fetch and copy default.rb recipe
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/abc123', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/abc123").
       and_return(cookbook_a_default_recipe_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
@@ -234,8 +233,8 @@ describe Chef::CookbookSynchronizer do
       and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb")
 
     # Fetch and copy default.rb attribute file
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/abc456', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/abc456").
       and_return(cookbook_a_default_attribute_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
@@ -252,8 +251,8 @@ describe Chef::CookbookSynchronizer do
       with("cookbooks/cookbook_a/templates/default/apache2.conf.erb").
       and_return(false)
 
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/megaman.conf', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/megaman.conf").
       and_return(cookbook_a_file_default_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
@@ -261,8 +260,8 @@ describe Chef::CookbookSynchronizer do
       with("cookbooks/cookbook_a/files/default/megaman.conf", false).
       and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
 
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/ffffff', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/ffffff").
       and_return(cookbook_a_template_default_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
@@ -281,8 +280,8 @@ describe Chef::CookbookSynchronizer do
       and_return(true)
 
     # Fetch and copy default.rb recipe
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/abc123', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/abc123").
       and_return(cookbook_a_default_recipe_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb")
@@ -297,8 +296,8 @@ describe Chef::CookbookSynchronizer do
       and_return("fff000")
 
     # Fetch and copy default.rb attribute file
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/abc456', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/abc456").
       and_return(cookbook_a_default_attribute_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb")
@@ -323,8 +322,8 @@ describe Chef::CookbookSynchronizer do
       and_return(true)
 
     # Fetch and copy megaman.conf
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/megaman.conf', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/megaman.conf").
       and_return(cookbook_a_file_default_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf")
@@ -334,8 +333,8 @@ describe Chef::CookbookSynchronizer do
       and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf")
 
     # Fetch and copy apache2.conf template
-    expect(server_api).to receive(:get_rest).
-      with('http://chef.example.com/ffffff', true).
+    expect(server_api).to receive(:streaming_request).
+      with("http://chef.example.com/ffffff").
       and_return(cookbook_a_template_default_tempfile)
     expect(file_cache).to receive(:move_to).
       with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb")
@@ -416,7 +415,7 @@ describe Chef::CookbookSynchronizer do
   end
 
   describe "when syncing cookbooks with the server" do
-    let(:server_api) { double("Chef::REST (mock)") }
+    let(:server_api) { double("Chef::ServerAPI (mock)") }
 
     let(:file_cache) { double("Chef::FileCache (mock)") }
 
@@ -442,8 +441,8 @@ describe Chef::CookbookSynchronizer do
 
         it "does not fetch templates or cookbook files" do
           # Implicitly tested in previous test; this test is just for behavior specification.
-          expect(server_api).not_to receive(:get_rest).
-            with('http://chef.example.com/ffffff', true)
+          expect(server_api).not_to receive(:streaming_request).
+            with("http://chef.example.com/ffffff")
 
           synchronizer.sync_cookbooks
         end
@@ -502,7 +501,7 @@ describe Chef::CookbookSynchronizer do
 
         it "does not update files" do
           expect(file_cache).not_to receive(:move_to)
-          expect(server_api).not_to receive(:get_rest)
+          expect(server_api).not_to receive(:streaming_request)
           synchronizer.sync_cookbooks
         end
       end
@@ -512,7 +511,7 @@ describe Chef::CookbookSynchronizer do
 
         it "does not update files" do
           expect(file_cache).not_to receive(:move_to)
-          expect(server_api).not_to receive(:get_rest)
+          expect(server_api).not_to receive(:streaming_request)
           synchronizer.sync_cookbooks
         end
       end
diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb
index 471fc01..6d0ce96 100644
--- a/spec/unit/cookbook/syntax_check_spec.rb
+++ b/spec/unit/cookbook/syntax_check_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 require "chef/cookbook/syntax_check"
 
 describe Chef::Cookbook::SyntaxCheck do
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
   end
 
-  let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'cookbooks', 'openldap') }
+  let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks", "openldap") }
   let(:syntax_check) { Chef::Cookbook::SyntaxCheck.new(cookbook_path) }
 
   let(:open_ldap_cookbook_files) do
@@ -38,7 +38,7 @@ describe Chef::Cookbook::SyntaxCheck do
         recipes/default.rb
         recipes/gigantor.rb
         recipes/one.rb
-        recipes/return.rb }.map{ |f| File.join(cookbook_path, f) }
+        recipes/return.rb }.map { |f| File.join(cookbook_path, f) }
   end
 
   before do
@@ -46,20 +46,23 @@ describe Chef::Cookbook::SyntaxCheck do
     @original_log_level = Chef::Log.level
     Chef::Log.level = :warn # suppress "Syntax OK" messages
 
-    @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', f) }
-    @libr_files = %w{openldap.rb openldap/version.rb}.map { |f| File.join(cookbook_path, 'libraries', f) }
-    @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)}
-    @recipes = %w{default.rb gigantor.rb one.rb return.rb}.map { |f| File.join(cookbook_path, 'recipes', f) }
+    @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, "attributes", f) }
+    @libr_files = %w{openldap.rb openldap/version.rb}.map { |f| File.join(cookbook_path, "libraries", f) }
+    @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, "definitions", f) }
+    @recipes = %w{default.rb gigantor.rb one.rb return.rb}.map { |f| File.join(cookbook_path, "recipes", f) }
     @ruby_files = @attr_files + @libr_files + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")]
     basenames = %w{ helpers_via_partial_test.erb
                     helper_test.erb
+                    helpers.erb
                     openldap_stuff.conf.erb
+                    nested_openldap_partials.erb
+                    nested_partial.erb
                     openldap_variable_stuff.conf.erb
                     test.erb
                     some_windows_line_endings.erb
                     all_windows_line_endings.erb
                     no_windows_line_endings.erb }
-    @template_files = basenames.map { |f| File.join(cookbook_path, 'templates', 'default', f)}
+    @template_files = basenames.map { |f| File.join(cookbook_path, "templates", "default", f) }
   end
 
   after do
@@ -74,18 +77,18 @@ describe Chef::Cookbook::SyntaxCheck do
   end
 
   it "creates a syntax checker given the cookbook name and cookbook_path" do
-    syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap, File.join(CHEF_SPEC_DATA, 'cookbooks'))
+    syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap, File.join(CHEF_SPEC_DATA, "cookbooks"))
     expect(syntax_check.cookbook_path).to eq(cookbook_path)
     expect(syntax_check.ruby_files.sort).to eq(open_ldap_cookbook_files.sort)
   end
 
   context "when using a standalone cookbook" do
-    let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'standalone_cookbook') }
+    let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "standalone_cookbook") }
 
     it "creates a syntax checker given the cookbook name and cookbook_path for a standalone cookbook" do
       syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:standalone_cookbook, CHEF_SPEC_DATA)
       expect(syntax_check.cookbook_path).to eq(cookbook_path)
-      expect(syntax_check.ruby_files).to eq([File.join(cookbook_path, 'recipes/default.rb')])
+      expect(syntax_check.ruby_files).to eq([File.join(cookbook_path, "recipes/default.rb")])
     end
   end
 
@@ -125,13 +128,13 @@ describe Chef::Cookbook::SyntaxCheck do
       end
 
       it "removes a ruby file from the list of untested files after it is marked as validated" do
-        recipe = File.join(cookbook_path, 'recipes', 'default.rb')
+        recipe = File.join(cookbook_path, "recipes", "default.rb")
         syntax_check.validated(recipe)
         expect(syntax_check.untested_ruby_files).not_to include(recipe)
       end
 
       it "removes a template file from the list of untested files after it is marked as validated" do
-        template = File.join(cookbook_path, 'templates', 'default', 'test.erb')
+        template = File.join(cookbook_path, "templates", "default", "test.erb")
         syntax_check.validated(template)
         expect(syntax_check.untested_template_files).not_to include(template)
       end
@@ -148,7 +151,7 @@ describe Chef::Cookbook::SyntaxCheck do
 
       describe "and a file has a syntax error" do
         before do
-          cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'borken')
+          cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks", "borken")
           syntax_check.cookbook_path.replace(cookbook_path)
         end
 
@@ -157,9 +160,9 @@ describe Chef::Cookbook::SyntaxCheck do
         end
 
         it "does not remove the invalid file from the list of untested files" do
-          expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, 'recipes', 'default.rb'))
+          expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, "recipes", "default.rb"))
           syntax_check.validate_ruby_files
-          expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, 'recipes', 'default.rb'))
+          expect(syntax_check.untested_ruby_files).to include(File.join(cookbook_path, "recipes", "default.rb"))
         end
 
         it "indicates that a template file has a syntax error" do
@@ -167,18 +170,18 @@ describe Chef::Cookbook::SyntaxCheck do
         end
 
         it "does not remove the invalid template from the list of untested templates" do
-          expect(syntax_check.untested_template_files).to include(File.join(cookbook_path, 'templates', 'default', 'borken.erb'))
-          expect {syntax_check.validate_templates}.not_to change(syntax_check, :untested_template_files)
+          expect(syntax_check.untested_template_files).to include(File.join(cookbook_path, "templates", "default", "borken.erb"))
+          expect { syntax_check.validate_templates }.not_to change(syntax_check, :untested_template_files)
         end
 
       end
 
       describe "and an ignored file has a syntax error" do
         before do
-          cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'ignorken')
+          cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks", "ignorken")
           Chef::Config[:cookbook_path] = File.dirname(cookbook_path)
           syntax_check.cookbook_path.replace(cookbook_path)
-          @ruby_files = [File.join(cookbook_path, 'metadata.rb'), File.join(cookbook_path, 'recipes/default.rb')]
+          @ruby_files = [File.join(cookbook_path, "metadata.rb"), File.join(cookbook_path, "recipes/default.rb")]
         end
 
         it "shows that ignored ruby files do not require a syntax check" do
diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb
index 45a985b..3f4a748 100644
--- a/spec/unit/cookbook_loader_spec.rb
+++ b/spec/unit/cookbook_loader_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::CookbookLoader do
   before do
-    allow(Chef::Platform).to receive(:windows?) {false}
+    allow(ChefConfig).to receive(:windows?) { false }
   end
   let(:repo_paths) do
     [
       File.expand_path(File.join(CHEF_SPEC_DATA, "kitchen")),
-      File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
+      File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")),
     ]
   end
 
@@ -48,7 +48,6 @@ describe Chef::CookbookLoader do
     cookbook_loader.load_cookbooks
   end
 
-
   context "after loading all cookbooks" do
     before(:each) do
       cookbook_loader.load_cookbooks
@@ -86,7 +85,7 @@ describe Chef::CookbookLoader do
         seen = Array.new
         cookbook_loader.each do |cookbook_name, cookbook|
           seen << cookbook_name
-          end
+        end
         expect(seen[0]).to eq("angrybash")
         expect(seen[1]).to eq("apache2")
         expect(seen[2]).to eq("borken")
@@ -179,7 +178,7 @@ describe Chef::CookbookLoader do
       [
         File.join(CHEF_SPEC_DATA, "kitchen"),
         File.join(CHEF_SPEC_DATA, "cookbooks"),
-        File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo")
+        File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo"),
       ]
     end
 
@@ -223,7 +222,7 @@ describe Chef::CookbookLoader do
     end
 
     it "should not load the cookbook again when accessed" do
-      expect(cookbook_loader).not_to receive('load_cookbook')
+      expect(cookbook_loader).not_to receive("load_cookbook")
       cookbook_loader["openldap"]
     end
 
@@ -245,7 +244,7 @@ describe Chef::CookbookLoader do
         [
           File.join(CHEF_SPEC_DATA, "kitchen"),
           File.join(CHEF_SPEC_DATA, "cookbooks"),
-          File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo")
+          File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo"),
         ]
       end
 
diff --git a/spec/unit/cookbook_manifest_spec.rb b/spec/unit/cookbook_manifest_spec.rb
index f985942..acf0ade 100644
--- a/spec/unit/cookbook_manifest_spec.rb
+++ b/spec/unit/cookbook_manifest_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at chef.io>)
-# Copyright:: Copyright (c) 2015 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/cookbook_manifest'
-require 'chef/digester'
-require 'pathname'
+require "spec_helper"
+require "chef/cookbook_manifest"
+require "chef/digester"
+require "pathname"
 
 describe Chef::CookbookManifest do
 
@@ -32,7 +32,7 @@ describe Chef::CookbookManifest do
     end
   end
 
-  let(:cookbook_root) { '/tmp/blah' }
+  let(:cookbook_root) { "/tmp/blah" }
 
   let(:cookbook_version) do
     Chef::CookbookVersion.new("tatft", cookbook_root).tap do |c|
@@ -62,7 +62,7 @@ describe Chef::CookbookManifest do
     end
 
     it "delegates `root_paths' to cookbook_version" do
-      expect(cookbook_manifest.root_paths).to eq(['/tmp/blah'])
+      expect(cookbook_manifest.root_paths).to eq(["/tmp/blah"])
     end
 
     it "delegates `metadata' to cookbook_version" do
@@ -101,15 +101,15 @@ describe Chef::CookbookManifest do
 
         "frozen?" => false,
 
-        "recipes"     =>[],
-        "definitions" =>[],
-        "libraries"   =>[],
-        "attributes"  =>[],
-        "files"       =>[],
-        "templates"   =>[],
-        "resources"   =>[],
-        "providers"   =>[],
-        "root_files"  =>[],
+        "recipes" => [],
+        "definitions" => [],
+        "libraries" => [],
+        "attributes" => [],
+        "files" => [],
+        "templates" => [],
+        "resources" => [],
+        "providers" => [],
+        "root_files" => [],
       }
     end
 
@@ -121,18 +121,18 @@ describe Chef::CookbookManifest do
 
   context "when given a cookbook with files" do
 
-    let(:cookbook_root) { File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft') }
+    let(:cookbook_root) { File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "tatft") }
 
-    let(:attribute_filenames)   { Dir[File.join(cookbook_root, 'attributes', '**', '*.rb')] }
-    let(:definition_filenames)  { Dir[File.join(cookbook_root, 'definitions', '**', '*.rb')] }
-    let(:file_filenames)        { Dir[File.join(cookbook_root, 'files', '**', '*.tgz')] }
-    let(:recipe_filenames)      { Dir[File.join(cookbook_root, 'recipes', '**', '*.rb')] }
-    let(:template_filenames)    { Dir[File.join(cookbook_root, 'templates', '**', '*.erb')] }
-    let(:library_filenames)     { Dir[File.join(cookbook_root, 'libraries', '**', '*.rb')] }
-    let(:resource_filenames)    { Dir[File.join(cookbook_root, 'resources', '**', '*.rb')] }
-    let(:provider_filenames)    { Dir[File.join(cookbook_root, 'providers', '**', '*.rb')] }
-    let(:root_filenames)        { Array(File.join(cookbook_root, 'README.rdoc')) }
-    let(:metadata_filenames)    { Array(File.join(cookbook_root, 'metadata.json')) }
+    let(:attribute_filenames)   { Dir[File.join(cookbook_root, "attributes", "**", "*.rb")] }
+    let(:definition_filenames)  { Dir[File.join(cookbook_root, "definitions", "**", "*.rb")] }
+    let(:file_filenames)        { Dir[File.join(cookbook_root, "files", "**", "*.tgz")] }
+    let(:recipe_filenames)      { Dir[File.join(cookbook_root, "recipes", "**", "*.rb")] }
+    let(:template_filenames)    { Dir[File.join(cookbook_root, "templates", "**", "*.erb")] }
+    let(:library_filenames)     { Dir[File.join(cookbook_root, "libraries", "**", "*.rb")] }
+    let(:resource_filenames)    { Dir[File.join(cookbook_root, "resources", "**", "*.rb")] }
+    let(:provider_filenames)    { Dir[File.join(cookbook_root, "providers", "**", "*.rb")] }
+    let(:root_filenames)        { Array(File.join(cookbook_root, "README.rdoc")) }
+    let(:metadata_filenames)    { Array(File.join(cookbook_root, "metadata.json")) }
 
     let(:match_md5) { /[0-9a-f]{32}/ }
 
@@ -241,4 +241,3 @@ describe Chef::CookbookManifest do
   end
 
 end
-
diff --git a/spec/unit/cookbook_site_streaming_uploader_spec.rb b/spec/unit/cookbook_site_streaming_uploader_spec.rb
index ef0f649..a2511fc 100644
--- a/spec/unit/cookbook_site_streaming_uploader_spec.rb
+++ b/spec/unit/cookbook_site_streaming_uploader_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/cookbook_site_streaming_uploader'
+require "chef/cookbook_site_streaming_uploader"
 
 class FakeTempfile
   def initialize(basename)
@@ -39,7 +39,7 @@ describe Chef::CookbookSiteStreamingUploader do
   describe "create_build_dir" do
 
     before(:each) do
-      @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks'))
+      @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
       @loader = Chef::CookbookLoader.new(@cookbook_repo)
       @loader.load_cookbooks
       allow(File).to receive(:unlink)
@@ -47,7 +47,7 @@ describe Chef::CookbookSiteStreamingUploader do
 
     it "should create the cookbook tmp dir" do
       cookbook = @loader[:openldap]
-      files_count = Dir.glob(File.join(@cookbook_repo, cookbook.name.to_s, '**', '*'), File::FNM_DOTMATCH).count { |file| File.file?(file) }
+      files_count = Dir.glob(File.join(@cookbook_repo, cookbook.name.to_s, "**", "*"), File::FNM_DOTMATCH).count { |file| File.file?(file) }
 
       expect(Tempfile).to receive(:new).with("chef-#{cookbook.name}-build").and_return(FakeTempfile.new("chef-#{cookbook.name}-build"))
       expect(FileUtils).to receive(:mkdir_p).exactly(files_count + 1).times
@@ -61,25 +61,25 @@ describe Chef::CookbookSiteStreamingUploader do
 
     before(:each) do
       @uri = "http://cookbooks.dummy.com/api/v1/cookbooks"
-      @secret_filename = File.join(CHEF_SPEC_DATA, 'ssl/private_key.pem')
+      @secret_filename = File.join(CHEF_SPEC_DATA, "ssl/private_key.pem")
       @rsa_key = File.read(@secret_filename)
-      response = Net::HTTPResponse.new('1.0', '200', 'OK')
+      response = Net::HTTPResponse.new("1.0", "200", "OK")
       allow_any_instance_of(Net::HTTP).to receive(:request).and_return(response)
     end
 
     it "should send an http request" do
       expect_any_instance_of(Net::HTTP).to receive(:request)
-      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
     end
 
     it "should read the private key file" do
       expect(File).to receive(:read).with(@secret_filename).and_return(@rsa_key)
-      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
     end
 
     it "should add the authentication signed header" do
       expect_any_instance_of(Mixlib::Authentication::SigningObject).to receive(:sign).and_return({})
-      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
     end
 
     it "should be able to send post requests" do
@@ -88,7 +88,7 @@ describe Chef::CookbookSiteStreamingUploader do
       expect(Net::HTTP::Post).to receive(:new).once.and_return(post)
       expect(Net::HTTP::Put).not_to receive(:new)
       expect(Net::HTTP::Get).not_to receive(:new)
-      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
+      Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, "bill", @secret_filename)
     end
 
     it "should be able to send put requests" do
@@ -97,56 +97,35 @@ describe Chef::CookbookSiteStreamingUploader do
       expect(Net::HTTP::Post).not_to receive(:new)
       expect(Net::HTTP::Put).to receive(:new).once.and_return(put)
       expect(Net::HTTP::Get).not_to receive(:new)
-      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename)
+      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename)
     end
 
     it "should be able to receive files to attach as argument" do
-      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
-        :myfile => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')), # a dummy file
+      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+        :myfile => File.new(File.join(CHEF_SPEC_DATA, "config.rb")), # a dummy file
       })
     end
 
     it "should be able to receive strings to attach as argument" do
-      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
-        :mystring => 'Lorem ipsum',
+      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+        :mystring => "Lorem ipsum"
       })
     end
 
     it "should be able to receive strings and files as argument at the same time" do
-      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, {
-        :myfile1 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')),
-        :mystring1 => 'Lorem ipsum',
-        :myfile2 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')),
-        :mystring2 => 'Dummy text',
+      Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, "bill", @secret_filename, {
+        :myfile1 => File.new(File.join(CHEF_SPEC_DATA, "config.rb")),
+        :mystring1 => "Lorem ipsum",
+        :myfile2 => File.new(File.join(CHEF_SPEC_DATA, "config.rb")),
+        :mystring2 => "Dummy text",
       })
     end
 
-    describe "http verify mode" do
-      before do
-        @uri = "https://cookbooks.dummy.com/api/v1/cookbooks"
-        uri_info = URI.parse(@uri)
-        @http = Net::HTTP.new(uri_info.host, uri_info.port)
-        expect(Net::HTTP).to receive(:new).with(uri_info.host, uri_info.port).and_return(@http)
-      end
-
-      it "should be VERIFY_NONE when ssl_verify_mode is :verify_none" do
-        Chef::Config[:ssl_verify_mode] = :verify_none
-        Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
-        expect(@http.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
-      end
-
-      it "should be VERIFY_PEER when ssl_verify_mode is :verify_peer" do
-        Chef::Config[:ssl_verify_mode] = :verify_peer
-        Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename)
-        expect(@http.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
-      end
-    end
-
   end # make_request
 
   describe "StreamPart" do
     before(:each) do
-      @file = File.new(File.join(CHEF_SPEC_DATA, 'config.rb'))
+      @file = File.new(File.join(CHEF_SPEC_DATA, "config.rb"))
       @stream_part = Chef::CookbookSiteStreamingUploader::StreamPart.new(@file, File.size(@file))
     end
 
@@ -168,7 +147,7 @@ describe Chef::CookbookSiteStreamingUploader do
 
   describe "StringPart" do
     before(:each) do
-      @str = 'What a boring string'
+      @str = "What a boring string"
       @string_part = Chef::CookbookSiteStreamingUploader::StringPart.new(@str)
     end
 
@@ -210,7 +189,7 @@ describe Chef::CookbookSiteStreamingUploader do
     end
 
     it "should read receiving destination buffer as second argument (CHEF-4456: Ruby 2 compat)" do
-      dst_buf = ''
+      dst_buf = ""
       @multipart_stream.read(10, dst_buf)
       expect(dst_buf).to eql("#{@string1}#{@string2}"[0, 10])
     end
diff --git a/spec/unit/cookbook_spec.rb b/spec/unit/cookbook_spec.rb
index 7b3cda2..f931b43 100644
--- a/spec/unit/cookbook_spec.rb
+++ b/spec/unit/cookbook_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::CookbookVersion do
 #  COOKBOOK_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks", "openldap"))
@@ -59,15 +59,6 @@ describe Chef::CookbookVersion do
     expect(@cookbook.fully_qualified_recipe_names.include?("openldap::three")).to eq(true)
   end
 
-  it "should find a preferred file" do
-    skip
-  end
-
-  it "should not return an unchanged preferred file" do
-    pending
-    expect(@cookbook.preferred_filename(@node, :files, 'a-filename', 'the-checksum')).to be_nil
-  end
-
   it "should raise an ArgumentException if you try to load a bad recipe name" do
     expect { @cookbook.load_recipe("doesnt_exist", @node) }.to raise_error(ArgumentError)
   end
diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb
index 76727c1..c30df71 100644
--- a/spec/unit/cookbook_uploader_spec.rb
+++ b/spec/unit/cookbook_uploader_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::CookbookUploader do
 
-  let(:http_client) { double("Chef::REST") }
+  let(:http_client) { double("Chef::ServerAPI") }
 
   let(:cookbook_loader) do
     loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks"))
@@ -64,8 +64,8 @@ describe Chef::CookbookUploader do
   end
 
   it "creates an HTTP client with default configuration when not initialized with one" do
-    default_http_client = double("Chef::REST")
-    expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
+    default_http_client = double("Chef::ServerAPI")
+    expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(default_http_client)
     uploader = described_class.new(cookbooks_to_upload)
     expect(uploader.rest).to eq(default_http_client)
   end
@@ -78,7 +78,7 @@ describe Chef::CookbookUploader do
 
     let(:sandbox_response) do
       sandbox_checksums = cksums_not_on_remote.inject({}) do |cksum_map, cksum|
-        cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum)}
+        cksum_map[cksum] = { "needs_upload" => true, "url" => url_for(cksum) }
         cksum_map
       end
       { "checksums" => sandbox_checksums, "uri" => sandbox_commit_uri }
@@ -86,7 +86,7 @@ describe Chef::CookbookUploader do
 
     def expect_sandbox_create
       expect(http_client).to receive(:post).
-        with("sandboxes", {:checksums => checksums_set}).
+        with("sandboxes", { :checksums => checksums_set }).
         and_return(sandbox_response)
     end
 
@@ -97,7 +97,7 @@ describe Chef::CookbookUploader do
         upload_headers = {
           "content-type" => "application/x-binary",
           "content-md5"  => an_instance_of(String),
-          "accept"       => "application/json"
+          "accept"       => "application/json",
         }
 
         expect(http_client).to receive(:put).
@@ -111,7 +111,7 @@ describe Chef::CookbookUploader do
     end
 
     def expect_sandbox_commit
-      expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true})
+      expect(http_client).to receive(:put).with(sandbox_commit_uri, { :is_completed => true })
     end
 
     def expect_cookbook_create
@@ -193,7 +193,6 @@ describe Chef::CookbookUploader do
         uploader.upload_cookbooks
       end
 
-
     end
   end
 
diff --git a/spec/unit/cookbook_version_file_specificity_spec.rb b/spec/unit/cookbook_version_file_specificity_spec.rb
index 73b1089..13be1c2 100644
--- a/spec/unit/cookbook_version_file_specificity_spec.rb
+++ b/spec/unit/cookbook_version_file_specificity_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::CookbookVersion, "file specificity" do
   before(:each) do
@@ -30,31 +30,31 @@ describe Chef::CookbookVersion, "file specificity" do
          :name => "afile.rb",
          :path => "files/host-examplehost.example.org/afile.rb",
          :checksum => "csum-host",
-         :specificity => "host-examplehost.example.org"
+         :specificity => "host-examplehost.example.org",
        },
        {
          :name => "afile.rb",
          :path => "files/ubuntu-9.10/afile.rb",
          :checksum => "csum-platver-full",
-         :specificity => "ubuntu-9.10"
+         :specificity => "ubuntu-9.10",
        },
        {
          :name => "afile.rb",
          :path => "files/newubuntu-9/afile.rb",
          :checksum => "csum-platver-partial",
-         :specificity => "newubuntu-9"
+         :specificity => "newubuntu-9",
        },
        {
          :name => "afile.rb",
          :path => "files/ubuntu/afile.rb",
          :checksum => "csum-plat",
-         :specificity => "ubuntu"
+         :specificity => "ubuntu",
        },
        {
          :name => "afile.rb",
          :path => "files/default/afile.rb",
          :checksum => "csum-default",
-         :specificity => "default"
+         :specificity => "default",
        },
 
        # for different/odd platform_versions
@@ -62,25 +62,25 @@ describe Chef::CookbookVersion, "file specificity" do
          :name => "bfile.rb",
          :path => "files/fakeos-2.0.rc.1/bfile.rb",
          :checksum => "csum2-platver-full",
-         :specificity => "fakeos-2.0.rc.1"
+         :specificity => "fakeos-2.0.rc.1",
        },
        {
          :name => "bfile.rb",
          :path => "files/newfakeos-2.0.rc/bfile.rb",
          :checksum => "csum2-platver-partial",
-         :specificity => "newfakeos-2.0.rc"
+         :specificity => "newfakeos-2.0.rc",
        },
        {
          :name => "bfile.rb",
          :path => "files/fakeos-maple tree/bfile.rb",
          :checksum => "csum3-platver-full",
-         :specificity => "maple tree"
+         :specificity => "maple tree",
        },
        {
          :name => "bfile.rb",
          :path => "files/fakeos-1/bfile.rb",
          :checksum => "csum4-platver-full",
-         :specificity => "fakeos-1"
+         :specificity => "fakeos-1",
        },
 
        # directory adirectory
@@ -88,121 +88,120 @@ describe Chef::CookbookVersion, "file specificity" do
          :name => "anotherfile1.rb",
          :path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host",
          :checksum => "csum-host-1",
-         :specificity => "host-examplehost.example.org"
+         :specificity => "host-examplehost.example.org",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/host-examplehost.example.org/adirectory/anotherfile2.rb.host",
          :checksum => "csum-host-2",
-         :specificity => "host-examplehost.example.org"
+         :specificity => "host-examplehost.example.org",
        },
 
        {
          :name => "anotherfile1.rb",
          :path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version",
          :checksum => "csum-platver-full-1",
-         :specificity => "ubuntu-9.10"
+         :specificity => "ubuntu-9.10",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/ubuntu-9.10/adirectory/anotherfile2.rb.platform-full-version",
          :checksum => "csum-platver-full-2",
-         :specificity => "ubuntu-9.10"
+         :specificity => "ubuntu-9.10",
        },
 
        {
          :name => "anotherfile1.rb",
          :path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version",
          :checksum => "csum-platver-partial-1",
-         :specificity => "newubuntu-9"
+         :specificity => "newubuntu-9",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version",
          :checksum => "csum-platver-partial-2",
-         :specificity => "nweubuntu-9"
+         :specificity => "nweubuntu-9",
        },
 
        {
          :name => "anotherfile1.rb",
          :path => "files/ubuntu/adirectory/anotherfile1.rb.platform",
          :checksum => "csum-plat-1",
-         :specificity => "ubuntu"
+         :specificity => "ubuntu",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/ubuntu/adirectory/anotherfile2.rb.platform",
          :checksum => "csum-plat-2",
-         :specificity => "ubuntu"
+         :specificity => "ubuntu",
        },
 
        {
          :name => "anotherfile1.rb",
          :path => "files/default/adirectory/anotherfile1.rb.default",
          :checksum => "csum-default-1",
-         :specificity => "default"
+         :specificity => "default",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/default/adirectory/anotherfile2.rb.default",
          :checksum => "csum-default-2",
-         :specificity => "default"
+         :specificity => "default",
        },
        # for different/odd platform_versions
        {
          :name => "anotherfile1.rb",
          :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-full-version",
          :checksum => "csum2-platver-full-1",
-         :specificity => "fakeos-2.0.rc.1"
+         :specificity => "fakeos-2.0.rc.1",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-full-version",
          :checksum => "csum2-platver-full-2",
-         :specificity => "fakeos-2.0.rc.1"
+         :specificity => "fakeos-2.0.rc.1",
        },
        {
          :name => "anotherfile1.rb",
          :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-partial-version",
          :checksum => "csum2-platver-partial-1",
-         :specificity => "newfakeos-2.0.rc"
+         :specificity => "newfakeos-2.0.rc",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-partial-version",
          :checksum => "csum2-platver-partial-2",
-         :specificity => "newfakeos-2.0.rc"
+         :specificity => "newfakeos-2.0.rc",
        },
        {
          :name => "anotherfile1.rb",
          :path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version",
          :checksum => "csum3-platver-full-1",
-         :specificity => "fakeos-maple tree"
+         :specificity => "fakeos-maple tree",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/fakeos-maple tree/adirectory/anotherfile2.rb.platform-full-version",
          :checksum => "csum3-platver-full-2",
-         :specificity => "fakeos-maple tree"
+         :specificity => "fakeos-maple tree",
        },
        {
          :name => "anotherfile1.rb",
          :path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version",
          :checksum => "csum4-platver-full-1",
-         :specificity => "fakeos-1"
+         :specificity => "fakeos-1",
        },
        {
          :name => "anotherfile2.rb",
          :path => "files/fakeos-1/adirectory/anotherfile2.rb.platform-full-version",
          :checksum => "csum4-platver-full-2",
-         :specificity => "fakeos-1"
+         :specificity => "fakeos-1",
        },
       ]
     }
 
   end
 
-
   it "should return a manifest record based on priority preference: host" do
     node = Chef::Node.new
     node.automatic_attrs[:platform] = "ubuntu"
@@ -314,7 +313,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum-host-1", "csum-host-2"])
     end
 
@@ -328,7 +327,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum-platver-full-1", "csum-platver-full-2"])
     end
 
@@ -342,7 +341,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum-platver-partial-1", "csum-platver-partial-2"])
     end
 
@@ -356,7 +355,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum-plat-1", "csum-plat-2"])
     end
 
@@ -370,7 +369,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum-default-1", "csum-default-2"])
     end
 
@@ -384,7 +383,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum2-platver-full-1", "csum2-platver-full-2"])
     end
 
@@ -398,7 +397,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum2-platver-partial-1", "csum2-platver-partial-2"])
     end
 
@@ -412,7 +411,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum3-platver-full-1", "csum3-platver-full-2"])
     end
 
@@ -426,7 +425,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(manifest_records).not_to be_nil
       expect(manifest_records.size).to eq(2)
 
-      checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] }
+      checksums = manifest_records.map { |manifest_record| manifest_record[:checksum] }
       expect(checksums.sort).to eq(["csum4-platver-full-1", "csum4-platver-full-2"])
     end
   end
@@ -444,7 +443,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.host', 'anotherfile2.rb.host'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.host", "anotherfile2.rb.host"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & full version" do
@@ -457,7 +456,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & partial version" do
@@ -470,7 +469,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-partial-version", "anotherfile2.rb.platform-partial-version"])
     end
 
     it "should return a list of relative paths based on priority preference: platform only" do
@@ -483,7 +482,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform', 'anotherfile2.rb.platform'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform", "anotherfile2.rb.platform"])
     end
 
     it "should return a list of relative paths based on priority preference: default" do
@@ -496,7 +495,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.default', 'anotherfile2.rb.default'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.default", "anotherfile2.rb.default"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 1" do
@@ -509,7 +508,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & partial version - platform_version variant 1" do
@@ -522,7 +521,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-partial-version", "anotherfile2.rb.platform-partial-version"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 2" do
@@ -535,7 +534,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
     end
 
     it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 3" do
@@ -548,7 +547,7 @@ describe Chef::CookbookVersion, "file specificity" do
       expect(filenames).not_to be_nil
       expect(filenames.size).to eq(2)
 
-      expect(filenames.sort).to eq(['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'])
+      expect(filenames.sort).to eq(["anotherfile1.rb.platform-full-version", "anotherfile2.rb.platform-full-version"])
     end
   end
 end
diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb
index 440dd9d..0eafe65 100644
--- a/spec/unit/cookbook_version_spec.rb
+++ b/spec/unit/cookbook_version_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,16 +15,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::CookbookVersion do
   describe "when first created" do
     before do
-      @cookbook_version = Chef::CookbookVersion.new("tatft", '/tmp/blah')
+      @cookbook_version = Chef::CookbookVersion.new("tatft", "/tmp/blah")
     end
 
     it "has a name" do
-      expect(@cookbook_version.name).to eq('tatft')
+      expect(@cookbook_version.name).to eq("tatft")
     end
 
     it "has no attribute files" do
@@ -80,26 +80,26 @@ describe Chef::CookbookVersion do
     before do
       @cookbook = Hash.new { |hash, key| hash[key] = [] }
 
-      @cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft')
+      @cookbook_root = File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "tatft")
 
       # Dunno if the paths here are representitive of what is set by CookbookLoader...
-      @cookbook[:attribute_filenames]   = Dir[File.join(@cookbook_root, 'attributes', '**', '*.rb')]
-      @cookbook[:definition_filenames]  = Dir[File.join(@cookbook_root, 'definitions', '**', '*.rb')]
-      @cookbook[:file_filenames]        = Dir[File.join(@cookbook_root, 'files', '**', '*.tgz')]
-      @cookbook[:recipe_filenames]      = Dir[File.join(@cookbook_root, 'recipes', '**', '*.rb')]
-      @cookbook[:template_filenames]    = Dir[File.join(@cookbook_root, 'templates', '**', '*.erb')]
-      @cookbook[:library_filenames]     = Dir[File.join(@cookbook_root, 'libraries', '**', '*.rb')]
-      @cookbook[:resource_filenames]    = Dir[File.join(@cookbook_root, 'resources', '**', '*.rb')]
-      @cookbook[:provider_filenames]    = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
-      @cookbook[:root_filenames]        = Array(File.join(@cookbook_root, 'README.rdoc'))
-      @cookbook[:metadata_filenames]    = Array(File.join(@cookbook_root, 'metadata.json'))
+      @cookbook[:attribute_filenames]   = Dir[File.join(@cookbook_root, "attributes", "**", "*.rb")]
+      @cookbook[:definition_filenames]  = Dir[File.join(@cookbook_root, "definitions", "**", "*.rb")]
+      @cookbook[:file_filenames]        = Dir[File.join(@cookbook_root, "files", "**", "*.tgz")]
+      @cookbook[:recipe_filenames]      = Dir[File.join(@cookbook_root, "recipes", "**", "*.rb")]
+      @cookbook[:template_filenames]    = Dir[File.join(@cookbook_root, "templates", "**", "*.erb")]
+      @cookbook[:library_filenames]     = Dir[File.join(@cookbook_root, "libraries", "**", "*.rb")]
+      @cookbook[:resource_filenames]    = Dir[File.join(@cookbook_root, "resources", "**", "*.rb")]
+      @cookbook[:provider_filenames]    = Dir[File.join(@cookbook_root, "providers", "**", "*.rb")]
+      @cookbook[:root_filenames]        = Array(File.join(@cookbook_root, "README.rdoc"))
+      @cookbook[:metadata_filenames]    = Array(File.join(@cookbook_root, "metadata.json"))
     end
 
     describe "and a cookbook with the same name" do
       before do
         # Currently the cookbook loader finds all the files then tells CookbookVersion
         # where they are.
-        @cookbook_version = Chef::CookbookVersion.new('tatft', @cookbook_root)
+        @cookbook_version = Chef::CookbookVersion.new("tatft", @cookbook_root)
 
         @cookbook_version.attribute_filenames  = @cookbook[:attribute_filenames]
         @cookbook_version.definition_filenames = @cookbook[:definition_filenames]
@@ -154,25 +154,25 @@ describe Chef::CookbookVersion do
 
   end
 
-  describe 'with a cookbook directory named cookbook2 that has unscoped files' do
+  describe "with a cookbook directory named cookbook2 that has unscoped files" do
     before do
       @cookbook = Hash.new { |hash, key| hash[key] = [] }
 
-      @cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'cookbook2')
+      @cookbook_root = File.join(CHEF_SPEC_DATA, "cb_version_cookbooks", "cookbook2")
 
       # Dunno if the paths here are representitive of what is set by CookbookLoader...
-      @cookbook[:attribute_filenames]   = Dir[File.join(@cookbook_root, 'attributes', '**', '*.rb')]
-      @cookbook[:definition_filenames]  = Dir[File.join(@cookbook_root, 'definitions', '**', '*.rb')]
-      @cookbook[:file_filenames]        = Dir[File.join(@cookbook_root, 'files', '**', '*.*')]
-      @cookbook[:recipe_filenames]      = Dir[File.join(@cookbook_root, 'recipes', '**', '*.rb')]
-      @cookbook[:template_filenames]    = Dir[File.join(@cookbook_root, 'templates', '**', '*.*')]
-      @cookbook[:library_filenames]     = Dir[File.join(@cookbook_root, 'libraries', '**', '*.rb')]
-      @cookbook[:resource_filenames]    = Dir[File.join(@cookbook_root, 'resources', '**', '*.rb')]
-      @cookbook[:provider_filenames]    = Dir[File.join(@cookbook_root, 'providers', '**', '*.rb')]
-      @cookbook[:root_filenames]        = Array(File.join(@cookbook_root, 'README.rdoc'))
-      @cookbook[:metadata_filenames]    = Array(File.join(@cookbook_root, 'metadata.json'))
-
-      @cookbook_version = Chef::CookbookVersion.new('cookbook2', @cookbook_root)
+      @cookbook[:attribute_filenames]   = Dir[File.join(@cookbook_root, "attributes", "**", "*.rb")]
+      @cookbook[:definition_filenames]  = Dir[File.join(@cookbook_root, "definitions", "**", "*.rb")]
+      @cookbook[:file_filenames]        = Dir[File.join(@cookbook_root, "files", "**", "*.*")]
+      @cookbook[:recipe_filenames]      = Dir[File.join(@cookbook_root, "recipes", "**", "*.rb")]
+      @cookbook[:template_filenames]    = Dir[File.join(@cookbook_root, "templates", "**", "*.*")]
+      @cookbook[:library_filenames]     = Dir[File.join(@cookbook_root, "libraries", "**", "*.rb")]
+      @cookbook[:resource_filenames]    = Dir[File.join(@cookbook_root, "resources", "**", "*.rb")]
+      @cookbook[:provider_filenames]    = Dir[File.join(@cookbook_root, "providers", "**", "*.rb")]
+      @cookbook[:root_filenames]        = Array(File.join(@cookbook_root, "README.rdoc"))
+      @cookbook[:metadata_filenames]    = Array(File.join(@cookbook_root, "metadata.json"))
+
+      @cookbook_version = Chef::CookbookVersion.new("cookbook2", @cookbook_root)
       @cookbook_version.attribute_filenames  = @cookbook[:attribute_filenames]
       @cookbook_version.definition_filenames = @cookbook[:definition_filenames]
       @cookbook_version.recipe_filenames     = @cookbook[:recipe_filenames]
@@ -233,7 +233,6 @@ describe Chef::CookbookVersion do
 
   end
 
-
   describe "<=>" do
 
     it "should sort based on the version number" do
@@ -249,11 +248,11 @@ describe Chef::CookbookVersion do
                   ["1.2", "1.3.0"],
                   ["1.2", "1.3"],
                   ["1.2", "2.1.1"],
-                  ["1.2", "2.1"]
+                  ["1.2", "2.1"],
                  ]
       examples.each do |smaller, larger|
-        sm = Chef::CookbookVersion.new("foo", '/tmp/blah')
-        lg = Chef::CookbookVersion.new("foo", '/tmp/blah')
+        sm = Chef::CookbookVersion.new("foo", "/tmp/blah")
+        lg = Chef::CookbookVersion.new("foo", "/tmp/blah")
         sm.version = smaller
         lg.version = larger
         expect(sm).to be < lg
@@ -263,29 +262,28 @@ describe Chef::CookbookVersion do
     end
 
     it "should equate versions 1.2 and 1.2.0" do
-      a = Chef::CookbookVersion.new("foo", '/tmp/blah')
-      b = Chef::CookbookVersion.new("foo", '/tmp/blah')
+      a = Chef::CookbookVersion.new("foo", "/tmp/blah")
+      b = Chef::CookbookVersion.new("foo", "/tmp/blah")
       a.version = "1.2"
       b.version = "1.2.0"
       expect(a).to eq(b)
     end
 
-
     it "should not allow you to sort cookbooks with different names" do
-      apt = Chef::CookbookVersion.new "apt", '/tmp/blah'
+      apt = Chef::CookbookVersion.new "apt", "/tmp/blah"
       apt.version = "1.0"
-      god = Chef::CookbookVersion.new "god", '/tmp/blah'
+      god = Chef::CookbookVersion.new "god", "/tmp/blah"
       god.version = "2.0"
-      expect {apt <=> god}.to raise_error(Chef::Exceptions::CookbookVersionNameMismatch)
+      expect { apt <=> god }.to raise_error(Chef::Exceptions::CookbookVersionNameMismatch)
     end
   end
 
   describe "when you set a version" do
     before do
-      @cbv = Chef::CookbookVersion.new("version validation", '/tmp/blah')
+      @cbv = Chef::CookbookVersion.new("version validation", "/tmp/blah")
     end
     it "should accept valid cookbook versions" do
-      good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25)
+      good_versions = %w{1.2 1.2.3 1000.80.50000 0.300.25}
       good_versions.each do |v|
         @cbv.version = v
       end
@@ -296,7 +294,7 @@ describe Chef::CookbookVersion do
                       "1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"]
       the_error = Chef::Exceptions::InvalidCookbookVersion
       bad_versions.each do |v|
-        expect {@cbv.version = v}.to raise_error(the_error)
+        expect { @cbv.version = v }.to raise_error(the_error)
       end
     end
 
@@ -304,27 +302,7 @@ describe Chef::CookbookVersion do
 
   describe "when deprecation warnings are errors" do
 
-    subject(:cbv) { Chef::CookbookVersion.new("version validation", '/tmp/blah') }
-
-    describe "HTTP Resource behaviors", pending: "will be deprected when CookbookManifest API is stablized" do
-
-      it "errors on #save_url" do
-        expect { cbv.save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
-      end
-
-      it "errors on #force_save_url" do
-        expect { cbv.force_save_url }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
-      end
-
-      it "errors on #to_hash" do
-        expect { cbv.to_hash }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
-      end
-
-      it "errors on #to_json" do
-        expect { cbv.to_json }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
-      end
-
-    end
+    subject(:cbv) { Chef::CookbookVersion.new("version validation", "/tmp/blah") }
 
     it "errors on #status and #status=" do
       expect { cbv.status = :wat }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
@@ -335,7 +313,7 @@ describe Chef::CookbookVersion do
 
   describe "deprecated features" do
 
-    subject(:cbv) { Chef::CookbookVersion.new("tatft", '/tmp/blah').tap { |c| c.version = "1.2.3" } }
+    subject(:cbv) { Chef::CookbookVersion.new("tatft", "/tmp/blah").tap { |c| c.version = "1.2.3" } }
 
     before do
       Chef::Config[:treat_deprecation_warnings_as_errors] = false
@@ -355,9 +333,8 @@ describe Chef::CookbookVersion do
       expect(cbv.status).to eq(:ready)
     end
 
-
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
-      let(:jsonable) { Chef::CookbookVersion.new("tatft", '/tmp/blah') }
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
+      let(:jsonable) { Chef::CookbookVersion.new("tatft", "/tmp/blah") }
     end
 
   end
diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb
index e020576..e31ce7d 100644
--- a/spec/unit/daemon_spec.rb
+++ b/spec/unit/daemon_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Daemon do
   before do
@@ -74,7 +74,7 @@ describe Chef::Daemon do
 
     before do
       allow(Chef::Application).to receive(:fatal!).and_return(true)
-      Chef::Config[:user] = 'aj'
+      Chef::Config[:user] = "aj"
       allow(Dir).to receive(:chdir)
     end
 
@@ -86,7 +86,7 @@ describe Chef::Daemon do
     describe "when the user and group options are supplied" do
 
       before do
-        Chef::Config[:group] = 'staff'
+        Chef::Config[:group] = "staff"
       end
 
       it "should log an appropriate info message" do
diff --git a/spec/unit/data_bag_item_spec.rb b/spec/unit/data_bag_item_spec.rb
index 4348252..ac4cf31 100644
--- a/spec/unit/data_bag_item_spec.rb
+++ b/spec/unit/data_bag_item_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/data_bag_item'
+require "spec_helper"
+require "chef/data_bag_item"
 
 describe Chef::DataBagItem do
   let(:data_bag_item) { Chef::DataBagItem.new }
@@ -169,13 +169,12 @@ describe Chef::DataBagItem do
   describe "when deserializing from JSON" do
     let(:data_bag_item) {
       data_bag_item = Chef::DataBagItem.new
-      data_bag_item.data_bag('mars_volta')
+      data_bag_item.data_bag("mars_volta")
       data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will } }
       data_bag_item
     }
 
-    let(:deserial) { Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(data_bag_item)) }
-
+    let(:deserial) { Chef::DataBagItem.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(data_bag_item))) }
 
     it "should deserialize to a Chef::DataBagItem object" do
       expect(deserial).to be_a_kind_of(Chef::DataBagItem)
@@ -193,19 +192,19 @@ describe Chef::DataBagItem do
       expect(deserial["snooze"]).to eq({ "finally" => "world_will" })
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { data_bag_item }
     end
   end
 
   describe "when converting to a string" do
     it "converts to a string in the form data_bag_item[ID]" do
-      data_bag_item['id'] = "heart of darkness"
-      expect(data_bag_item.to_s).to eq('data_bag_item[heart of darkness]')
+      data_bag_item["id"] = "heart of darkness"
+      expect(data_bag_item.to_s).to eq("data_bag_item[heart of darkness]")
     end
 
     it "inspects as data_bag_item[BAG, ID, RAW_DATA]" do
-      raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"}
+      raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
       data_bag_item.raw_data = raw_data
       data_bag_item.data_bag("books")
 
@@ -214,29 +213,29 @@ describe Chef::DataBagItem do
   end
 
   describe "save" do
-    let(:server) { instance_double(Chef::REST) }
+    let(:server) { instance_double(Chef::ServerAPI) }
 
     let(:data_bag_item) {
       data_bag_item = Chef::DataBagItem.new
-      data_bag_item['id'] = "heart of darkness"
-      data_bag_item.raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"}
+      data_bag_item["id"] = "heart of darkness"
+      data_bag_item.raw_data = { "id" => "heart_of_darkness", "author" => "Conrad" }
       data_bag_item.data_bag("books")
       data_bag_item
     }
 
     before do
-      expect(Chef::REST).to receive(:new).and_return(server)
+      expect(Chef::ServerAPI).to receive(:new).and_return(server)
     end
 
     it "should update the item when it already exists" do
-      expect(server).to receive(:put_rest).with("data/books/heart_of_darkness", data_bag_item)
+      expect(server).to receive(:put).with("data/books/heart_of_darkness", data_bag_item)
       data_bag_item.save
     end
 
     it "should create if the item is not found" do
       exception = double("404 error", :code => "404")
-      expect(server).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
-      expect(server).to receive(:post_rest).with("data/books", data_bag_item)
+      expect(server).to receive(:put).and_raise(Net::HTTPServerException.new("foo", exception))
+      expect(server).to receive(:post).with("data/books", data_bag_item)
       data_bag_item.save
     end
 
@@ -249,8 +248,8 @@ describe Chef::DataBagItem do
       end
 
       it "should not save" do
-        expect(server).not_to receive(:put_rest)
-        expect(server).not_to receive(:post_rest)
+        expect(server).not_to receive(:put)
+        expect(server).not_to receive(:post)
         data_bag_item.data_bag("books")
         data_bag_item.save
       end
@@ -259,18 +258,18 @@ describe Chef::DataBagItem do
   end
 
   describe "destroy" do
-    let(:server) { instance_double(Chef::REST) }
+    let(:server) { instance_double(Chef::ServerAPI) }
 
     let(:data_bag_item) {
       data_bag_item = Chef::DataBagItem.new
-      data_bag_item.data_bag('a_baggy_bag')
+      data_bag_item.data_bag("a_baggy_bag")
       data_bag_item.raw_data = { "id" => "some_id" }
       data_bag_item
     }
 
     it "should set default parameters" do
-      expect(Chef::REST).to receive(:new).and_return(server)
-      expect(server).to receive(:delete_rest).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id")
+      expect(Chef::ServerAPI).to receive(:new).and_return(server)
+      expect(server).to receive(:delete).with("data/a_baggy_bag/data_bag_item_a_baggy_bag_some_id")
 
       data_bag_item.destroy
     end
@@ -278,26 +277,26 @@ describe Chef::DataBagItem do
 
   describe "when loading" do
     before do
-      data_bag_item.raw_data = {"id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2}}
+      data_bag_item.raw_data = { "id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2} }
       data_bag_item.data_bag("users")
     end
 
     describe "from an API call" do
-      let(:http_client) { double("Chef::REST") }
+      let(:http_client) { double("Chef::ServerAPI") }
 
       before do
-        allow(Chef::REST).to receive(:new).and_return(http_client)
+        allow(Chef::ServerAPI).to receive(:new).and_return(http_client)
       end
 
       it "converts raw data to a data bag item" do
-        expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item.to_hash)
+        expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item.to_hash)
         item = Chef::DataBagItem.load(:users, "charlie")
         expect(item).to be_a_kind_of(Chef::DataBagItem)
         expect(item).to eq(data_bag_item)
       end
 
       it "does not convert when a DataBagItem is returned from the API call" do
-        expect(http_client).to receive(:get_rest).with("data/users/charlie").and_return(data_bag_item)
+        expect(http_client).to receive(:get).with("data/users/charlie").and_return(data_bag_item)
         item = Chef::DataBagItem.load(:users, "charlie")
         expect(item).to be_a_kind_of(Chef::DataBagItem)
         expect(item).to equal(data_bag_item)
@@ -314,8 +313,8 @@ describe Chef::DataBagItem do
       end
 
       it "converts the raw data to a data bag item" do
-        expect(Chef::DataBag).to receive(:load).with('users').and_return({'charlie' => data_bag_item.to_hash})
-        item = Chef::DataBagItem.load('users', 'charlie')
+        expect(Chef::DataBag).to receive(:load).with("users").and_return({ "charlie" => data_bag_item.to_hash })
+        item = Chef::DataBagItem.load("users", "charlie")
         expect(item).to be_a_kind_of(Chef::DataBagItem)
         expect(item).to eq(data_bag_item)
       end
diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb
index f6db1e2..92da4ca 100644
--- a/spec/unit/data_bag_spec.rb
+++ b/spec/unit/data_bag_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/data_bag'
+require "spec_helper"
+require "chef/data_bag"
 
 describe Chef::DataBag do
   before(:each) do
     @data_bag = Chef::DataBag.new
-    allow(Chef::Platform)::to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
   end
 
   describe "initialize" do
@@ -58,8 +58,8 @@ describe Chef::DataBag do
 
   describe "deserialize" do
     before(:each) do
-      @data_bag.name('mars_volta')
-      @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data_bag))
+      @data_bag.name("mars_volta")
+      @deserial = Chef::DataBag.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@data_bag)))
     end
 
     it "should deserialize to a Chef::DataBag object" do
@@ -73,7 +73,7 @@ describe Chef::DataBag do
         expect(@deserial.send(t.to_sym)).to eq(@data_bag.send(t.to_sym))
       end
 
-      include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+      include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
         let(:jsonable) { @data_bag }
       end
     end
@@ -82,19 +82,19 @@ describe Chef::DataBag do
 
   describe "when saving" do
     before do
-      @data_bag.name('piggly_wiggly')
-      @rest = double("Chef::REST")
-      allow(Chef::REST).to receive(:new).and_return(@rest)
+      @data_bag.name("piggly_wiggly")
+      @rest = double("Chef::ServerAPI")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
     end
 
     it "should silently proceed when the data bag already exists" do
       exception = double("409 error", :code => "409")
-      expect(@rest).to receive(:post_rest).and_raise(Net::HTTPServerException.new("foo", exception))
+      expect(@rest).to receive(:post).and_raise(Net::HTTPServerException.new("foo", exception))
       @data_bag.save
     end
 
     it "should create the data bag" do
-      expect(@rest).to receive(:post_rest).with("data", @data_bag)
+      expect(@rest).to receive(:post).with("data", @data_bag)
       @data_bag.save
     end
 
@@ -106,7 +106,7 @@ describe Chef::DataBag do
         Chef::Config[:why_run] = false
       end
       it "should not save" do
-        expect(@rest).not_to receive(:post_rest)
+        expect(@rest).not_to receive(:post)
         @data_bag.save
       end
     end
@@ -115,21 +115,21 @@ describe Chef::DataBag do
   describe "when loading" do
     describe "from an API call" do
       before do
-        Chef::Config[:chef_server_url] = 'https://myserver.example.com'
-        @http_client = double('Chef::REST')
+        Chef::Config[:chef_server_url] = "https://myserver.example.com"
+        @http_client = double("Chef::ServerAPI")
       end
 
       it "should get the data bag from the server" do
-        expect(Chef::REST).to receive(:new).with('https://myserver.example.com').and_return(@http_client)
-        expect(@http_client).to receive(:get_rest).with('data/foo')
-        Chef::DataBag.load('foo')
+        expect(Chef::ServerAPI).to receive(:new).with("https://myserver.example.com").and_return(@http_client)
+        expect(@http_client).to receive(:get).with("data/foo")
+        Chef::DataBag.load("foo")
       end
 
       it "should return the data bag" do
-        allow(Chef::REST).to receive(:new).and_return(@http_client)
-        expect(@http_client).to receive(:get_rest).with('data/foo').and_return({'bar' => 'https://myserver.example.com/data/foo/bar'})
-        data_bag = Chef::DataBag.load('foo')
-        expect(data_bag).to eq({'bar' => 'https://myserver.example.com/data/foo/bar'})
+        allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+        expect(@http_client).to receive(:get).with("data/foo").and_return({ "bar" => "https://myserver.example.com/data/foo/bar" })
+        data_bag = Chef::DataBag.load("foo")
+        expect(data_bag).to eq({ "bar" => "https://myserver.example.com/data/foo/bar" })
       end
     end
 
@@ -138,7 +138,7 @@ describe Chef::DataBag do
     end
 
     def dir_glob_stub(path, returns = [])
-      expect(Dir).to receive(:glob).with(File.join(path, 'foo/*.json')).and_return(returns)
+      expect(Dir).to receive(:glob).with(File.join(path, "foo/*.json")).and_return(returns)
     end
 
     shared_examples_for "data bag in solo mode" do |data_bag_path|
@@ -157,7 +157,7 @@ describe Chef::DataBag do
           file_dir_stub(path)
           dir_glob_stub(path)
         end
-        Chef::DataBag.load('foo')
+        Chef::DataBag.load("foo")
       end
 
       it "should get the data bag from the data_bag_path by symbolic name" do
@@ -172,57 +172,57 @@ describe Chef::DataBag do
         @paths.each do |path|
           file_dir_stub(path)
           if path == @paths.first
-            dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+            dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
           else
             dir_glob_stub(path)
           end
         end
-        expect(IO).to receive(:read).with(File.join(@paths.first, 'foo/bar.json')).and_return('{"id": "bar", "name": "Bob Bar" }')
-        expect(IO).to receive(:read).with(File.join(@paths.first, 'foo/baz.json')).and_return('{"id": "baz", "name": "John Baz" }')
-        data_bag = Chef::DataBag.load('foo')
-        expect(data_bag).to eq({ 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar' }, 'baz' => { 'id' => 'baz', 'name' => 'John Baz' }})
+        expect(IO).to receive(:read).with(File.join(@paths.first, "foo/bar.json")).and_return('{"id": "bar", "name": "Bob Bar" }')
+        expect(IO).to receive(:read).with(File.join(@paths.first, "foo/baz.json")).and_return('{"id": "baz", "name": "John Baz" }')
+        data_bag = Chef::DataBag.load("foo")
+        expect(data_bag).to eq({ "bar" => { "id" => "bar", "name" => "Bob Bar" }, "baz" => { "id" => "baz", "name" => "John Baz" } })
       end
 
       it "should raise if data bag has items with similar names but different content" do
         @paths.each do |path|
           file_dir_stub(path)
           item_with_different_content = "{\"id\": \"bar\", \"name\": \"Bob Bar\", \"path\": \"#{path}\"}"
-          expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_different_content)
+          expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(item_with_different_content)
           if data_bag_path.is_a?(String)
-            dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+            dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
             item_2_with_different_content = '{"id": "bar", "name": "John Baz"}'
-            expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_2_with_different_content)
+            expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(item_2_with_different_content)
           else
-            dir_glob_stub(path, [File.join(path, 'foo/bar.json')])
+            dir_glob_stub(path, [File.join(path, "foo/bar.json")])
           end
         end
-        expect { Chef::DataBag.load('foo') }.to raise_error(Chef::Exceptions::DuplicateDataBagItem)
+        expect { Chef::DataBag.load("foo") }.to raise_error(Chef::Exceptions::DuplicateDataBagItem)
       end
 
       it "should return data bag if it has items with similar names and the same content" do
         @paths.each do |path|
           file_dir_stub(path)
-          dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+          dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
           item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
-          expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_same_content)
-          expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(item_with_same_content)
+          expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(item_with_same_content)
+          expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(item_with_same_content)
         end
-        data_bag = Chef::DataBag.load('foo')
-        test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+        data_bag = Chef::DataBag.load("foo")
+        test_data_bag = { "bar" => { "id" => "bar", "name" => "Bob Bar" } }
         expect(data_bag).to eq(test_data_bag)
       end
 
       it "should merge data bag items if there are no conflicts" do
         @paths.each_with_index do |path, index|
           file_dir_stub(path)
-          dir_glob_stub(path, [File.join(path, 'foo/bar.json'), File.join(path, 'foo/baz.json')])
+          dir_glob_stub(path, [File.join(path, "foo/bar.json"), File.join(path, "foo/baz.json")])
           test_item_with_same_content = '{"id": "bar", "name": "Bob Bar"}'
-          expect(IO).to receive(:read).with(File.join(path, 'foo/bar.json')).and_return(test_item_with_same_content)
+          expect(IO).to receive(:read).with(File.join(path, "foo/bar.json")).and_return(test_item_with_same_content)
           test_uniq_item = "{\"id\": \"baz_#{index}\", \"name\": \"John Baz\", \"path\": \"#{path}\"}"
-          expect(IO).to receive(:read).with(File.join(path, 'foo/baz.json')).and_return(test_uniq_item)
+          expect(IO).to receive(:read).with(File.join(path, "foo/baz.json")).and_return(test_uniq_item)
         end
-        data_bag = Chef::DataBag.load('foo')
-        test_data_bag = { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar'} }
+        data_bag = Chef::DataBag.load("foo")
+        test_data_bag = { "bar" => { "id" => "bar", "name" => "Bob Bar" } }
         @paths.each_with_index do |path, index|
           test_data_bag["baz_#{index}"] = { "id" => "baz_#{index}", "name" => "John Baz", "path" => path }
         end
@@ -232,17 +232,17 @@ describe Chef::DataBag do
       it "should return the data bag list" do
         @paths.each do |path|
           file_dir_stub(path)
-          expect(Dir).to receive(:glob).and_return([File.join(path, 'foo'), File.join(path, 'bar')])
+          expect(Dir).to receive(:glob).and_return([File.join(path, "foo"), File.join(path, "bar")])
         end
         data_bag_list = Chef::DataBag.list
-        expect(data_bag_list).to eq({ 'bar' => 'bar', 'foo' => 'foo' })
+        expect(data_bag_list).to eq({ "bar" => "bar", "foo" => "foo" })
       end
 
-      it 'should raise an error if the configured data_bag_path is invalid' do
+      it "should raise an error if the configured data_bag_path is invalid" do
         file_dir_stub(@paths.first, false)
 
         expect {
-          Chef::DataBag.load('foo')
+          Chef::DataBag.load("foo")
         }.to raise_error Chef::Exceptions::InvalidDataBagPath, "Data bag path '/var/chef/data_bags' is invalid"
       end
 
diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb
index f824cb7..af8e348 100644
--- a/spec/unit/deprecation_spec.rb
+++ b/spec/unit/deprecation_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/deprecation/warnings'
+require "spec_helper"
+require "chef/deprecation/warnings"
 
 describe Chef::Deprecation do
 
   # Support code for Chef::Deprecation
 
   def self.class_from_string(str)
-    str.split('::').inject(Object) do |mod, class_name|
+    str.split("::").inject(Object) do |mod, class_name|
       mod.const_get(class_name)
     end
   end
@@ -59,40 +59,92 @@ describe Chef::Deprecation do
     end
   end
 
-  context 'when Chef::Config[:treat_deprecation_warnings_as_errors] is off' do
+  context "when Chef::Config[:treat_deprecation_warnings_as_errors] is off" do
     before do
       Chef::Config[:treat_deprecation_warnings_as_errors] = false
     end
 
-    context 'deprecation warning messages' do
-      before(:each) do
-        @warning_output = [ ]
-        allow(Chef::Log).to receive(:warn) { |msg| @warning_output << msg }
-      end
+    context "deprecation warning messages" do
+      RSpec::Matchers.define_negated_matcher :a_non_empty_array, :be_empty
 
-      it 'should be enabled for deprecated methods' do
+      it "should be enabled for deprecated methods" do
+        expect(Chef::Log).to receive(:warn).with(a_non_empty_array)
         TestClass.new.deprecated_method(10)
-        expect(@warning_output).not_to be_empty
       end
 
-      it 'should contain stack trace' do
+      it "should contain stack trace" do
+        expect(Chef::Log).to receive(:warn).with(a_string_including(".rb"))
         TestClass.new.deprecated_method(10)
-        expect(@warning_output.join("").include?(".rb")).to be_truthy
       end
     end
 
-    it 'deprecated methods should still be called' do
+    it "deprecated methods should still be called" do
       test_instance = TestClass.new
       test_instance.deprecated_method(10)
       expect(test_instance.get_value).to eq(10)
     end
   end
 
-  it 'should raise when deprecation warnings are treated as errors' do
+  it "should raise when deprecation warnings are treated as errors" do
     # rspec should set this
     expect(Chef::Config[:treat_deprecation_warnings_as_errors]).to be true
     test_instance = TestClass.new
     expect { test_instance.deprecated_method(10) }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
   end
 
+  context "When a class has deprecated_attr, _reader and _writer" do
+    before(:context) do
+      class DeprecatedAttrTest
+        extend Chef::Mixin::Deprecation
+        def initialize
+          @a = @r = @w = 1
+        end
+        deprecated_attr :a, "a"
+        deprecated_attr_reader :r, "r"
+        deprecated_attr_writer :w, "w"
+      end
+    end
+
+    it "The deprecated_attr emits warnings" do
+      test = DeprecatedAttrTest.new
+      expect { test.a = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+      expect { test.a }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+    end
+
+    it "The deprecated_attr_writer emits warnings, and does not create a reader" do
+      test = DeprecatedAttrTest.new
+      expect { test.w = 10 }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+      expect { test.w }.to raise_error(NoMethodError)
+    end
+
+    it "The deprecated_attr_reader emits warnings, and does not create a writer" do
+      test = DeprecatedAttrTest.new
+      expect { test.r = 10 }.to raise_error(NoMethodError)
+      expect { test.r }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
+    end
+
+    context "With deprecation warnings not throwing exceptions" do
+      before do
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      end
+
+      it "The deprecated_attr can be written to and read from" do
+        test = DeprecatedAttrTest.new
+        test.a = 10
+        expect(test.a).to eq 10
+      end
+
+      it "The deprecated_attr_reader can be read from" do
+        test = DeprecatedAttrTest.new
+        expect(test.r).to eq 1
+      end
+
+      it "The deprecated_attr_writer can be written to" do
+        test = DeprecatedAttrTest.new
+        test.w = 10
+        expect(test.instance_eval { @w }).to eq 10
+      end
+    end
+  end
+
 end
diff --git a/spec/unit/digester_spec.rb b/spec/unit/digester_spec.rb
index 51bcfbd..2684ac8 100644
--- a/spec/unit/digester_spec.rb
+++ b/spec/unit/digester_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Digester do
   before(:each) do
@@ -40,11 +40,10 @@ describe Chef::Digester do
 
     it "generates a checksum from a non-file IO object" do
       io = StringIO.new("riseofthemachines\nriseofthechefs\n")
-      expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb'
+      expected_md5 = "0e157ac1e2dd73191b76067fb6b4bceb"
       expect(@cache.generate_md5_checksum(io)).to eq(expected_md5)
     end
 
   end
 
 end
-
diff --git a/spec/unit/dsl/audit_spec.rb b/spec/unit/dsl/audit_spec.rb
index 28b28e0..a8227f6 100644
--- a/spec/unit/dsl/audit_spec.rb
+++ b/spec/unit/dsl/audit_spec.rb
@@ -1,6 +1,6 @@
 
-require 'spec_helper'
-require 'chef/dsl/audit'
+require "spec_helper"
+require "chef/dsl/audit"
 
 class AuditDSLTester < Chef::Recipe
   include Chef::DSL::Audit
@@ -17,15 +17,15 @@ describe Chef::DSL::Audit do
   let(:cookbook_collection) { {} }
 
   it "raises an error when a block of audits is not provided" do
-    expect{ auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided)
+    expect { auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided)
   end
 
   it "raises an error when no audit name is given" do
-    expect{ auditor.control_group do end }.to raise_error(Chef::Exceptions::AuditNameMissing)
+    expect { auditor.control_group do end }.to raise_error(Chef::Exceptions::AuditNameMissing)
   end
 
   context "audits already populated" do
-    let(:audits) { {"unique" => {} } }
+    let(:audits) { { "unique" => {} } }
 
     it "raises an error if the audit name is a duplicate" do
       expect { auditor.control_group "unique" do end }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
diff --git a/spec/unit/dsl/data_query_spec.rb b/spec/unit/dsl/data_query_spec.rb
index b93ae1f..55c6e5f 100644
--- a/spec/unit/dsl/data_query_spec.rb
+++ b/spec/unit/dsl/data_query_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/dsl/data_query'
+require "spec_helper"
+require "chef/dsl/data_query"
 
 class DataQueryDSLTester
   include Chef::DSL::DataQuery
@@ -35,23 +35,23 @@ describe Chef::DSL::DataQuery do
   describe "::data_bag" do
     it "lists the items in a data bag" do
       allow(Chef::DataBag).to receive(:load)
-      .with("bag_name")
-      .and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
-      expect( language.data_bag("bag_name").sort ).to eql %w(item_1 item_2)
+        .with("bag_name")
+        .and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2")
+      expect( language.data_bag("bag_name").sort ).to eql %w{item_1 item_2}
     end
   end
 
   shared_examples_for "a data bag item" do
     it "validates the name of the data bag you're trying to load an item from" do
-      expect{ language.send(method_name, " %%^& ", "item_name") }.to raise_error(Chef::Exceptions::InvalidDataBagName)
+      expect { language.send(method_name, " %%^& ", "item_name") }.to raise_error(Chef::Exceptions::InvalidDataBagName)
     end
 
     it "validates the id of the data bag item you're trying to load" do
-      expect{ language.send(method_name, "bag_name", " 987 (*&()") }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
+      expect { language.send(method_name, "bag_name", " 987 (*&()") }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
     end
 
     it "validates that the id of the data bag item is not nil" do
-      expect{ language.send(method_name, "bag_name", nil) }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
+      expect { language.send(method_name, "bag_name", nil) }.to raise_error(Chef::Exceptions::InvalidDataBagItemID)
     end
   end
 
@@ -65,8 +65,8 @@ describe Chef::DSL::DataQuery do
       "greeting" => "hello",
       "nested" => {
         "a1" => [1, 2, 3],
-        "a2" => { "b1" => true }
-      }
+        "a2" => { "b1" => true },
+      },
     }}
 
     let(:item) do
diff --git a/spec/unit/dsl/platform_introspection_spec.rb b/spec/unit/dsl/platform_introspection_spec.rb
index e41560c..fd1f9b2 100644
--- a/spec/unit/dsl/platform_introspection_spec.rb
+++ b/spec/unit/dsl/platform_introspection_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/dsl/platform_introspection'
+require "spec_helper"
+require "chef/dsl/platform_introspection"
 
 class LanguageTester
   attr_reader :node
@@ -39,16 +39,16 @@ end
 describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do
   before do
     platform_hash = {
-      :openbsd => {:default => 'free, functional, secure'},
-      [:redhat, :centos, :fedora, :scientific] => {:default => '"stable"'},
-      :ubuntu => {'10.04' => 'using upstart more', :default => 'using init more'},
-      :default => 'bork da bork'
+      :openbsd => { :default => "free, functional, secure" },
+      [:redhat, :centos, :fedora, :scientific] => { :default => '"stable"' },
+      :ubuntu => { "10.04" => "using upstart more", :default => "using init more" },
+      :default => "bork da bork",
     }
     @platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(platform_hash)
   end
 
   it "returns the default value when the platform doesn't match" do
-    expect(@platform_specific_value.value_for_node(:platform => :dos)).to eq('bork da bork')
+    expect(@platform_specific_value.value_for_node(:platform => :dos)).to eq("bork da bork")
   end
 
   it "returns a value for a platform set as a group" do
@@ -60,25 +60,25 @@ describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do
   end
 
   it "returns a value for a specific platform version" do
-    node = {:platform => 'ubuntu', :platform_version => '10.04'}
-    expect(@platform_specific_value.value_for_node(node)).to eq('using upstart more')
+    node = { :platform => "ubuntu", :platform_version => "10.04" }
+    expect(@platform_specific_value.value_for_node(node)).to eq("using upstart more")
   end
 
   it "returns a platform-default value if the platform version doesn't match an explicit one" do
-    node = {:platform => 'ubuntu', :platform_version => '9.10' }
-    expect(@platform_specific_value.value_for_node(node)).to eq('using init more')
+    node = { :platform => "ubuntu", :platform_version => "9.10" }
+    expect(@platform_specific_value.value_for_node(node)).to eq("using init more")
   end
 
   it "returns nil if there is no default and no platforms match" do
     # this matches the behavior in the original implementation.
     # whether or not it's correct is another matter.
     platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new({})
-    expect(platform_specific_value.value_for_node(:platform => 'foo')).to be_nil
+    expect(platform_specific_value.value_for_node(:platform => "foo")).to be_nil
   end
 
   it "raises an argument error if the platform hash is not correctly structured" do
-    bad_hash = {:ubuntu => :foo} # should be :ubuntu => {:default => 'foo'}
-    expect {Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash)}.to raise_error(ArgumentError)
+    bad_hash = { :ubuntu => :foo } # should be :ubuntu => {:default => 'foo'}
+    expect { Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash) }.to raise_error(ArgumentError)
   end
 
 end
@@ -91,17 +91,16 @@ describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do
       [:rhel, "fedora"] => "redhatty value",
       "suse" => @array_values,
       :gentoo => "gentoo value",
-      :default => "default value"
+      :default => "default value",
     }
 
     @platform_family_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new(@platform_family_hash)
   end
 
   it "returns the default value when the platform family doesn't match" do
-    expect(@platform_family_value.value_for_node(:platform_family => :os2)).to eq('default value')
+    expect(@platform_family_value.value_for_node(:platform_family => :os2)).to eq("default value")
   end
 
-
   it "returns a value for the platform family when it was set as a string but fetched as a symbol" do
     expect(@platform_family_value.value_for_node(:platform_family => :debian)).to eq("debian value")
   end
@@ -124,7 +123,7 @@ describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do
 
   it "returns nil if there is no default and no platforms match" do
     platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new({})
-    expect(platform_specific_value.value_for_node(:platform_family => 'foo')).to be_nil
+    expect(platform_specific_value.value_for_node(:platform_family => "foo")).to be_nil
   end
 
 end
diff --git a/spec/unit/dsl/reboot_pending_spec.rb b/spec/unit/dsl/reboot_pending_spec.rb
index 0f22887..66f8b76 100644
--- a/spec/unit/dsl/reboot_pending_spec.rb
+++ b/spec/unit/dsl/reboot_pending_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,46 +30,52 @@ describe Chef::DSL::RebootPending do
 
       context "platform is windows" do
         before do
-          allow(recipe).to receive(:platform?).with('windows').and_return(true)
+          allow(recipe).to receive(:platform?).with("windows").and_return(true)
           allow(recipe).to receive(:registry_key_exists?).and_return(false)
           allow(recipe).to receive(:registry_value_exists?).and_return(false)
         end
-  
+
         it 'should return true if "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations" exists' do
-          allow(recipe).to receive(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }).and_return(true)
+          allow(recipe).to receive(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => "PendingFileRenameOperations" }).and_return(true)
           expect(recipe.reboot_pending?).to be_truthy
         end
-  
+
         it 'should return true if "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" exists' do
           allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired').and_return(true)
           expect(recipe.reboot_pending?).to be_truthy
         end
-  
+
         it 'should return true if key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired" exists' do
-          allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired').and_return(true)
+          allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending').and_return(true)
           expect(recipe.reboot_pending?).to be_truthy
         end
-  
-        it 'should return true if value "HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile" contains specific data' do
-          allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(true)
-          allow(recipe).to receive(:registry_get_values).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(
-                [{:name => "Flags", :type => :dword, :data => 3}])
-          expect(recipe.reboot_pending?).to be_truthy
+
+        context "version is server 2003" do
+          before do
+            allow(Chef::Platform).to receive(:windows_server_2003?).and_return(true)
+          end
+
+          it 'should return true if value "HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile" contains specific data on 2k3' do
+            allow(recipe).to receive(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(true)
+            allow(recipe).to receive(:registry_get_values).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(
+                  [{ :name => "Flags", :type => :dword, :data => 3 }])
+            expect(recipe.reboot_pending?).to be_truthy
+          end
         end
       end
-  
+
       context "platform is ubuntu" do
         before do
-          allow(recipe).to receive(:platform?).with('ubuntu').and_return(true)
+          allow(recipe).to receive(:platform?).with("ubuntu").and_return(true)
         end
-  
-        it 'should return true if /var/run/reboot-required exists' do
-          allow(File).to receive(:exists?).with('/var/run/reboot-required').and_return(true)
+
+        it "should return true if /var/run/reboot-required exists" do
+          allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(true)
           expect(recipe.reboot_pending?).to be_truthy
         end
-  
-        it 'should return false if /var/run/reboot-required does not exist' do
-          allow(File).to receive(:exists?).with('/var/run/reboot-required').and_return(false)
+
+        it "should return false if /var/run/reboot-required does not exist" do
+          allow(File).to receive(:exists?).with("/var/run/reboot-required").and_return(false)
           expect(recipe.reboot_pending?).to be_falsey
         end
       end
@@ -79,7 +85,7 @@ describe Chef::DSL::RebootPending do
     describe "in a recipe" do
       it "responds to reboot_pending?" do
         # Chef::Recipe.new(cookbook_name, recipe_name, run_context(node, cookbook_collection, events))
-        recipe = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, nil))
+        recipe = Chef::Recipe.new(nil, nil, Chef::RunContext.new(Chef::Node.new, {}, nil))
         expect(recipe).to respond_to(:reboot_pending?)
       end
     end # describe in a recipe
diff --git a/spec/unit/dsl/recipe_spec.rb b/spec/unit/dsl/recipe_spec.rb
index dfaad0b..cd01079 100644
--- a/spec/unit/dsl/recipe_spec.rb
+++ b/spec/unit/dsl/recipe_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/dsl/recipe'
-
+require "spec_helper"
+require "chef/dsl/recipe"
 
 RecipeDSLExampleClass = Struct.new(:cookbook_name, :recipe_name)
 class RecipeDSLExampleClass
@@ -79,4 +78,3 @@ describe Chef::DSL::Recipe do
   end
 
 end
-
diff --git a/spec/unit/dsl/regsitry_helper_spec.rb b/spec/unit/dsl/regsitry_helper_spec.rb
index 6508a12..d6c2257 100644
--- a/spec/unit/dsl/regsitry_helper_spec.rb
+++ b/spec/unit/dsl/regsitry_helper_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,32 +24,29 @@ describe Chef::Resource::RegistryKey do
   before (:all) do
     events = Chef::EventDispatch::Dispatcher.new
     node = Chef::Node.new
-    ohai = Ohai::System.new
-    ohai.all_plugins
-    node.consume_external_attrs(ohai.data,{})
+    node.consume_external_attrs(OHAI_SYSTEM.data, {})
     run_context = Chef::RunContext.new(node, {}, events)
     @resource = Chef::Resource::new("foo", run_context)
   end
 
   context "tests registry dsl" do
     it "resource can access registry_helper method registry_key_exists" do
-      expect(@resource.respond_to?('registry_key_exists?')).to eq(true)
+      expect(@resource.respond_to?("registry_key_exists?")).to eq(true)
     end
     it "resource can access registry_helper method registry_get_values" do
-      expect(@resource.respond_to?('registry_get_values')).to eq(true)
+      expect(@resource.respond_to?("registry_get_values")).to eq(true)
     end
     it "resource can access registry_helper method registry_has_subkey" do
-      expect(@resource.respond_to?('registry_has_subkeys?')).to eq(true)
+      expect(@resource.respond_to?("registry_has_subkeys?")).to eq(true)
     end
     it "resource can access registry_helper method registry_get_subkeys" do
-      expect(@resource.respond_to?('registry_get_subkeys')).to eq(true)
+      expect(@resource.respond_to?("registry_get_subkeys")).to eq(true)
     end
     it "resource can access registry_helper method registry_value_exists" do
-      expect(@resource.respond_to?('registry_value_exists?')).to eq(true)
+      expect(@resource.respond_to?("registry_value_exists?")).to eq(true)
     end
     it "resource can access registry_helper method data_value_exists" do
-      expect(@resource.respond_to?('registry_data_exists?')).to eq(true)
+      expect(@resource.respond_to?("registry_data_exists?")).to eq(true)
     end
   end
 end
-
diff --git a/spec/unit/dsl/resources_spec.rb b/spec/unit/dsl/resources_spec.rb
new file mode 100644
index 0000000..53cd6fc
--- /dev/null
+++ b/spec/unit/dsl/resources_spec.rb
@@ -0,0 +1,85 @@
+#
+# Author:: Noah Kantrowitz (<noah at coderanger.net>)
+# Copyright:: Copyright 2015-2016, Noah Kantrowitz
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/dsl/resources"
+
+describe Chef::DSL::Resources do
+  let(:declared_resources) { [] }
+  let(:test_class) do
+    r = declared_resources
+    Class.new do
+      include Chef::DSL::Resources
+      define_method(:declare_resource) do |dsl_name, name, _created_at, &_block|
+        r << [dsl_name, name]
+      end
+    end
+  end
+  subject { declared_resources }
+  after do
+    # Always clean up after ourselves.
+    described_class.remove_resource_dsl(:test_resource)
+  end
+
+  context "with a resource added" do
+    before do
+      Chef::DSL::Resources.add_resource_dsl(:test_resource)
+      test_class.new.instance_eval do
+        test_resource "test_name" do
+        end
+      end
+    end
+    it { is_expected.to eq [[:test_resource, "test_name"]] }
+  end
+
+  context "with no resource added" do
+    subject do
+      test_class.new.instance_eval do
+        test_resource "test_name" do
+        end
+      end
+    end
+
+    it { expect { subject }.to raise_error NoMethodError }
+  end
+
+  context "with a resource added and removed" do
+    before do
+      Chef::DSL::Resources.add_resource_dsl(:test_resource)
+      Chef::DSL::Resources.remove_resource_dsl(:test_resource)
+    end
+    subject do
+      test_class.new.instance_eval do
+        test_resource "test_name" do
+        end
+      end
+    end
+
+    it { expect { subject }.to raise_error NoMethodError }
+  end
+
+  context "with a nameless resource" do
+    before do
+      Chef::DSL::Resources.add_resource_dsl(:test_resource)
+      test_class.new.instance_eval do
+        test_resource {}
+      end
+    end
+    it { is_expected.to eq [[:test_resource, nil]] }
+  end
+end
diff --git a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
index 1e2b2a8..685c2e7 100644
--- a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
+++ b/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2010-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/encrypted_data_bag_item/check_encrypted'
+require "spec_helper"
+require "chef/encrypted_data_bag_item/check_encrypted"
 
 class CheckEncryptedTester
   include Chef::EncryptedDataBagItem::CheckEncrypted
@@ -32,7 +32,7 @@ describe Chef::EncryptedDataBagItem::CheckEncrypted do
   end
 
   it "detects the item is not encrypted when the data only contains an id" do
-    expect(tester.encrypted?({id: "foo"})).to eq(false)
+    expect(tester.encrypted?({ id: "foo" })).to eq(false)
   end
 
   context "when the item is encrypted" do
@@ -44,8 +44,8 @@ describe Chef::EncryptedDataBagItem::CheckEncrypted do
         "greeting" => "hello",
         "nested" => {
             "a1" => [1, 2, 3],
-            "a2" => { "b1" => true }
-        }
+            "a2" => { "b1" => true },
+        },
     }}
 
     let(:version) { 1 }
diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb
index 0a43067..1471368 100644
--- a/spec/unit/encrypted_data_bag_item_spec.rb
+++ b/spec/unit/encrypted_data_bag_item_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/encrypted_data_bag_item'
+require "spec_helper"
+require "chef/encrypted_data_bag_item"
 
 module Version0Encryptor
   def self.encrypt_value(plaintext_data, key)
@@ -32,10 +32,10 @@ module Version0Encryptor
   end
 end
 
-describe Chef::EncryptedDataBagItem::Encryptor  do
+describe Chef::EncryptedDataBagItem::Encryptor do
 
   subject(:encryptor) { described_class.new(plaintext_data, key) }
-  let(:plaintext_data) { {"foo" => "bar"} }
+  let(:plaintext_data) { { "foo" => "bar" } }
   let(:key) { "passwd" }
 
   it "encrypts to format version 1 by default" do
@@ -67,7 +67,7 @@ describe Chef::EncryptedDataBagItem::Encryptor  do
       expect(final_data["encrypted_data"]).to eq encryptor.encrypted_data
       expect(final_data["iv"]).to eq Base64.encode64(encryptor.iv)
       expect(final_data["version"]).to eq 1
-      expect(final_data["cipher"]).to eq"aes-256-cbc"
+      expect(final_data["cipher"]).to eq "aes-256-cbc"
     end
   end
 
@@ -149,10 +149,10 @@ end
 describe Chef::EncryptedDataBagItem::Decryptor do
 
   subject(:decryptor) { described_class.for(encrypted_value, decryption_key) }
-  let(:plaintext_data) { {"foo" => "bar"} }
+  let(:plaintext_data) { { "foo" => "bar" } }
   let(:encryption_key) { "passwd" }
   let(:decryption_key) { encryption_key }
-  let(:json_wrapped_data) {  Chef::JSONCompat.to_json({"json_wrapper" => plaintext_data}) }
+  let(:json_wrapped_data) { Chef::JSONCompat.to_json({ "json_wrapper" => plaintext_data }) }
 
   shared_examples "decryption examples" do
     it "decrypts the encrypted value" do
@@ -290,7 +290,7 @@ describe Chef::EncryptedDataBagItem::Decryptor do
 
   end
 
-  context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value" do
+  context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value", :not_supported_under_fips do
     let(:encrypted_value) do
       Version0Encryptor.encrypt_value(plaintext_data, encryption_key)
     end
@@ -323,7 +323,7 @@ describe Chef::EncryptedDataBagItem do
   let(:plaintext_data) {{
       "id" => "item_name",
       "greeting" => "hello",
-      "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }}
+      "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true } },
   }}
   let(:secret) { "abc123SECRET" }
   let(:encoded_data) { subject.encrypt_data_bag_item(plaintext_data, secret) }
diff --git a/spec/unit/environment_spec.rb b/spec/unit/environment_spec.rb
index ee3b8b2..f4026c7 100644
--- a/spec/unit/environment_spec.rb
+++ b/spec/unit/environment_spec.rb
@@ -3,7 +3,7 @@
 # Author:: Seth Falcon (<seth at ospcode.com>)
 # Author:: John Keiser (<jkeiser at ospcode.com>)
 # Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright 2010-2011 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/environment'
+require "spec_helper"
+require "chef/environment"
 
 describe Chef::Environment do
   before(:each) do
@@ -73,12 +73,12 @@ describe Chef::Environment do
 
   describe "default attributes" do
     it "should let you set the attributes hash explicitly" do
-      expect(@environment.default_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+      expect(@environment.default_attributes({ :one => "two" })).to eq({ :one => "two" })
     end
 
     it "should let you return the attributes hash" do
-      @environment.default_attributes({ :one => 'two' })
-      expect(@environment.default_attributes).to eq({ :one => 'two' })
+      @environment.default_attributes({ :one => "two" })
+      expect(@environment.default_attributes).to eq({ :one => "two" })
     end
 
     it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -88,12 +88,12 @@ describe Chef::Environment do
 
   describe "override attributes" do
     it "should let you set the attributes hash explicitly" do
-      expect(@environment.override_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+      expect(@environment.override_attributes({ :one => "two" })).to eq({ :one => "two" })
     end
 
     it "should let you return the attributes hash" do
-      @environment.override_attributes({ :one => 'two' })
-      expect(@environment.override_attributes).to eq({ :one => 'two' })
+      @environment.override_attributes({ :one => "two" })
+      expect(@environment.override_attributes).to eq({ :one => "two" })
     end
 
     it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -106,7 +106,7 @@ describe Chef::Environment do
       @cookbook_versions = {
         "apt"     => "= 1.0.0",
         "god"     => "= 2.0.0",
-        "apache2" => "= 4.2.0"
+        "apache2" => "= 4.2.0",
       }
     end
 
@@ -167,7 +167,7 @@ describe Chef::Environment do
     before(:each) do
       @environment.name("spec")
       @environment.description("Where we run the spec tests")
-      @environment.cookbook_versions({:apt => "= 1.2.3"})
+      @environment.cookbook_versions({ :apt => "= 1.2.3" })
       @hash = @environment.to_hash
     end
 
@@ -190,7 +190,7 @@ describe Chef::Environment do
     before(:each) do
       @environment.name("spec")
       @environment.description("Where we run the spec tests")
-      @environment.cookbook_versions({:apt => "= 1.2.3"})
+      @environment.cookbook_versions({ :apt => "= 1.2.3" })
       @json = @environment.to_json
     end
 
@@ -208,7 +208,7 @@ describe Chef::Environment do
       expect(@json).to match(/"chef_type":"environment"/)
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { @environment }
     end
   end
@@ -221,12 +221,12 @@ describe Chef::Environment do
         "cookbook_versions" => {
           "apt" => "= 1.2.3",
           "god" => ">= 4.2.0",
-          "apache2" => "= 2.0.0"
+          "apache2" => "= 2.0.0",
         },
         "json_class" => "Chef::Environment",
-        "chef_type" => "environment"
+        "chef_type" => "environment",
       }
-      @environment = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@data))
+      @environment = Chef::Environment.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@data)))
     end
 
     it "should return a Chef::Environment" do
@@ -245,7 +245,7 @@ describe Chef::Environment do
       @cookbook_versions = {
         "apt"     => "= 1.0.0",
         "god"     => "= 2.0.0",
-        "apache2" => "= 4.2.0"
+        "apache2" => "= 4.2.0",
       }
     end
 
@@ -317,7 +317,7 @@ describe Chef::Environment do
 
     it "validates the name given in the params" do
       expect(@environment.update_from_params(:name => "@$%^&*()")).to be_falsey
-      expect(@environment.invalid_fields[:name]).to eq(%q|Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/|)
+      expect(@environment.invalid_fields[:name]).to eq(%q{Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/})
     end
 
     it "updates the description from parameters[:description]" do
@@ -329,13 +329,13 @@ describe Chef::Environment do
       # NOTE: I'm only choosing this (admittedly weird) structure for the hash b/c the better more obvious
       # one, i.e, {:cookbook_version_constraints => {COOKBOOK_NAME => CONSTRAINT}} is difficult to implement
       # the way merb does params
-      params = {:name=>"superbowl", :cookbook_version => {"0" => "apache2 ~> 1.0.0", "1" => "nginx < 2.0.0"}}
+      params = { :name => "superbowl", :cookbook_version => { "0" => "apache2 ~> 1.0.0", "1" => "nginx < 2.0.0" } }
       @environment.update_from_params(params)
-      expect(@environment.cookbook_versions).to eq({"apache2" => "~> 1.0.0", "nginx" => "< 2.0.0"})
+      expect(@environment.cookbook_versions).to eq({ "apache2" => "~> 1.0.0", "nginx" => "< 2.0.0" })
     end
 
     it "validates the cookbook constraints" do
-      params = {:cookbook_version => {"0" => "apache2 >>> 1.0.0"}}
+      params = { :cookbook_version => { "0" => "apache2 >>> 1.0.0" } }
       expect(@environment.update_from_params(params)).to be_falsey
       err_msg = @environment.invalid_fields[:cookbook_version]["0"]
       expect(err_msg).to eq("apache2 >>> 1.0.0 is not a valid cookbook constraint")
@@ -353,20 +353,20 @@ describe Chef::Environment do
 
     it "updates default attributes from a JSON string in params[:attributes]" do
       @environment.update_from_params(:name => "fuuu", :default_attributes => %q|{"fuuu":"RAGE"}|)
-      expect(@environment.default_attributes).to eq({"fuuu" => "RAGE"})
+      expect(@environment.default_attributes).to eq({ "fuuu" => "RAGE" })
     end
 
     it "updates override attributes from a JSON string in params[:attributes]" do
       @environment.update_from_params(:name => "fuuu", :override_attributes => %q|{"foo":"override"}|)
-      expect(@environment.override_attributes).to eq({"foo" => "override"})
+      expect(@environment.override_attributes).to eq({ "foo" => "override" })
     end
 
   end
 
   describe "api model" do
     before(:each) do
-      @rest = double("Chef::REST")
-      allow(Chef::REST).to receive(:new).and_return(@rest)
+      @rest = double("Chef::ServerAPI")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
       @query = double("Chef::Search::Query")
       allow(Chef::Search::Query).to receive(:new).and_return(@query)
     end
@@ -382,7 +382,7 @@ describe Chef::Environment do
       end
 
       it "should return a hash of environment names and urls" do
-        expect(@rest).to receive(:get_rest).and_return({ "one" => "http://foo" })
+        expect(@rest).to receive(:get).and_return({ "one" => "http://foo" })
         r = Chef::Environment.list
         expect(r["one"]).to eq("http://foo")
       end
@@ -393,7 +393,7 @@ describe Chef::Environment do
     describe "in solo mode" do
       before do
         Chef::Config[:solo] = true
-        Chef::Config[:environment_path] = '/var/chef/environments'
+        Chef::Config[:environment_path] = "/var/chef/environments"
       end
 
       after do
@@ -402,17 +402,17 @@ describe Chef::Environment do
 
       it "should get the environment from the environment_path" do
         expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true)
-        expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true)
-        role_dsl="name \"foo\"\ndescription \"desc\"\n"
-        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl)
-        Chef::Environment.load('foo')
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).exactly(2).times.and_return(true)
+        expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(true)
+        role_dsl = "name \"foo\"\ndescription \"desc\"\n"
+        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(role_dsl)
+        Chef::Environment.load("foo")
       end
 
       it "should return a Chef::Environment object from JSON" do
         expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(true)
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(true)
         environment_hash = {
           "name" => "foo",
           "default_attributes" => {
@@ -422,46 +422,46 @@ describe Chef::Environment do
           },
           "json_class" => "Chef::Environment",
           "description" => "desc",
-          "chef_type" => "environment"
+          "chef_type" => "environment",
         }
-        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(Chef::JSONCompat.to_json(environment_hash))
-        environment = Chef::Environment.load('foo')
+        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(Chef::JSONCompat.to_json(environment_hash))
+        environment = Chef::Environment.load("foo")
 
         expect(environment).to be_a_kind_of(Chef::Environment)
-        expect(environment.name).to eq(environment_hash['name'])
-        expect(environment.description).to eq(environment_hash['description'])
-        expect(environment.default_attributes).to eq(environment_hash['default_attributes'])
+        expect(environment.name).to eq(environment_hash["name"])
+        expect(environment.description).to eq(environment_hash["description"])
+        expect(environment.default_attributes).to eq(environment_hash["default_attributes"])
       end
 
       it "should return a Chef::Environment object from Ruby DSL" do
         expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true)
-        expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true)
-        role_dsl="name \"foo\"\ndescription \"desc\"\n"
-        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl)
-        environment = Chef::Environment.load('foo')
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).exactly(2).times.and_return(true)
+        expect(File).to receive(:readable?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(true)
+        role_dsl = "name \"foo\"\ndescription \"desc\"\n"
+        expect(IO).to receive(:read).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(role_dsl)
+        environment = Chef::Environment.load("foo")
 
         expect(environment).to be_a_kind_of(Chef::Environment)
-        expect(environment.name).to eq('foo')
-        expect(environment.description).to eq('desc')
+        expect(environment.name).to eq("foo")
+        expect(environment.description).to eq("desc")
       end
 
-      it 'should raise an error if the configured environment_path is invalid' do
+      it "should raise an error if the configured environment_path is invalid" do
         expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(false)
 
         expect {
-          Chef::Environment.load('foo')
+          Chef::Environment.load("foo")
         }.to raise_error Chef::Exceptions::InvalidEnvironmentPath, "Environment path '/var/chef/environments' is invalid"
       end
 
-      it 'should raise an error if the file does not exist' do
+      it "should raise an error if the file does not exist" do
         expect(File).to receive(:directory?).with(Chef::Config[:environment_path]).and_return(true)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false)
-        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(false)
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.json")).and_return(false)
+        expect(File).to receive(:exists?).with(File.join(Chef::Config[:environment_path], "foo.rb")).and_return(false)
 
         expect {
-          Chef::Environment.load('foo')
+          Chef::Environment.load("foo")
         }.to raise_error Chef::Exceptions::EnvironmentNotFound, "Environment 'foo' could not be loaded from disk"
       end
     end
diff --git a/spec/unit/event_dispatch/dispatcher_spec.rb b/spec/unit/event_dispatch/dispatcher_spec.rb
new file mode 100644
index 0000000..2360b26
--- /dev/null
+++ b/spec/unit/event_dispatch/dispatcher_spec.rb
@@ -0,0 +1,122 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/event_dispatch/dispatcher"
+
+describe Chef::EventDispatch::Dispatcher do
+
+  subject(:dispatcher) { Chef::EventDispatch::Dispatcher.new }
+
+  let(:event_sink) { instance_double("Chef::EventDispatch::Base") }
+
+  it "has no subscribers by default" do
+    expect(dispatcher.subscribers).to be_empty
+  end
+
+  context "when an event sink is registered" do
+
+    before do
+      dispatcher.register(event_sink)
+    end
+
+    it "it has the event sink as a subscriber" do
+      expect(dispatcher.subscribers.size).to eq(1)
+      expect(dispatcher.subscribers.first).to eq(event_sink)
+    end
+
+    it "forwards events to the subscribed event sink" do
+      # the events all have different arity and such so we just hit a few different events:
+
+      expect(event_sink).to receive(:run_start).with("12.4.0")
+      dispatcher.run_start("12.4.0")
+
+      cookbook_version = double("cookbook_version")
+      expect(event_sink).to receive(:synchronized_cookbook).with("apache2", cookbook_version)
+      dispatcher.synchronized_cookbook("apache2", cookbook_version)
+
+      exception = StandardError.new("foo")
+      expect(event_sink).to receive(:recipe_file_load_failed).with("/path/to/file.rb", exception)
+      dispatcher.recipe_file_load_failed("/path/to/file.rb", exception)
+    end
+
+    context "when an event sink has fewer arguments for an event" do
+      # Can't use a double because they don't report arity correctly.
+      let(:event_sink) do
+        Class.new(Chef::EventDispatch::Base) do
+          attr_reader :synchronized_cookbook_args
+          def synchronized_cookbook(cookbook_name)
+            @synchronized_cookbook_args = [cookbook_name]
+          end
+        end.new
+      end
+
+      it "trims the arugment list" do
+        cookbook_version = double("cookbook_version")
+        dispatcher.synchronized_cookbook("apache2", cookbook_version)
+        expect(event_sink.synchronized_cookbook_args).to eq ["apache2"]
+      end
+    end
+  end
+
+  context "when two event sinks have different arguments for an event" do
+    let(:event_sink_1) do
+      Class.new(Chef::EventDispatch::Base) do
+        attr_reader :synchronized_cookbook_args
+        def synchronized_cookbook(cookbook_name)
+          @synchronized_cookbook_args = [cookbook_name]
+        end
+      end.new
+    end
+    let(:event_sink_2) do
+      Class.new(Chef::EventDispatch::Base) do
+        attr_reader :synchronized_cookbook_args
+        def synchronized_cookbook(cookbook_name, cookbook)
+          @synchronized_cookbook_args = [cookbook_name, cookbook]
+        end
+      end.new
+    end
+
+    context "and the one with fewer arguments comes first" do
+      before do
+        dispatcher.register(event_sink_1)
+        dispatcher.register(event_sink_2)
+      end
+      it "trims the arugment list" do
+        cookbook_version = double("cookbook_version")
+        dispatcher.synchronized_cookbook("apache2", cookbook_version)
+        expect(event_sink_1.synchronized_cookbook_args).to eq ["apache2"]
+        expect(event_sink_2.synchronized_cookbook_args).to eq ["apache2", cookbook_version]
+      end
+    end
+
+    context "and the one with fewer arguments comes last" do
+      before do
+        dispatcher.register(event_sink_2)
+        dispatcher.register(event_sink_1)
+      end
+      it "trims the arugment list" do
+        cookbook_version = double("cookbook_version")
+        dispatcher.synchronized_cookbook("apache2", cookbook_version)
+        expect(event_sink_1.synchronized_cookbook_args).to eq ["apache2"]
+        expect(event_sink_2.synchronized_cookbook_args).to eq ["apache2", cookbook_version]
+      end
+    end
+  end
+end
diff --git a/spec/unit/event_dispatch/dsl_spec.rb b/spec/unit/event_dispatch/dsl_spec.rb
new file mode 100644
index 0000000..979b067
--- /dev/null
+++ b/spec/unit/event_dispatch/dsl_spec.rb
@@ -0,0 +1,83 @@
+#
+# Author:: Ranjib Dey (<ranjib at linux.com>)
+#
+# Copyright:: Copyright 2015-2016, Ranjib Dey
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require "spec_helper"
+require "chef/event_dispatch/dsl"
+
+describe Chef::EventDispatch::DSL do
+  let(:events) do
+    Chef::EventDispatch::Dispatcher.new
+  end
+
+  let(:run_context) do
+    Chef::RunContext.new(Chef::Node.new, nil, events)
+  end
+
+  before do
+    Chef.set_run_context(run_context)
+  end
+
+  subject { described_class.new("test") }
+
+  it "set handler name" do
+    subject.on(:run_started) {}
+    expect(events.subscribers.first.name).to eq("test")
+  end
+
+  it "raise error when invalid event type is supplied" do
+    expect do
+      subject.on(:foo_bar) {}
+    end.to raise_error(Chef::Exceptions::InvalidEventType)
+  end
+
+  it "register user hooks against valid event type" do
+    subject.on(:run_failed) { "testhook" }
+    expect(events.subscribers.first.run_failed).to eq("testhook")
+  end
+
+  it "preserve state across event hooks" do
+    calls = []
+    Chef.event_handler do
+      on :resource_updated do
+        calls << :updated
+      end
+      on :resource_action_start do
+        calls << :started
+      end
+    end
+    resource = Chef::Resource::RubyBlock.new("foo", run_context)
+    resource.block {}
+    resource.run_action(:run)
+    expect(calls).to eq([:started, :updated])
+  end
+
+  it "preserve instance variables across handler callbacks" do
+    Chef.event_handler do
+      on :resource_action_start do
+        @ivar = [1]
+      end
+      on :resource_updated do
+        @ivar << 2
+      end
+    end
+    resource = Chef::Resource::RubyBlock.new("foo", run_context)
+    resource.block {}
+    resource.run_action(:run)
+    expect(events.subscribers.first.instance_variable_get(:@ivar)).to eq([1, 2])
+  end
+end
diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb
index d35ecc8..940edfe 100644
--- a/spec/unit/exceptions_spec.rb
+++ b/spec/unit/exceptions_spec.rb
@@ -1,9 +1,9 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
+# Author:: Christopher Walters (<cw at chef.io>)
 # Author:: Kyle Goodwin (<kgoodwin at primerevenue.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Thomas Bishop
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Exceptions do
   exception_to_super_class = {
@@ -67,16 +67,16 @@ describe Chef::Exceptions do
     Chef::Exceptions::InvalidEnvironmentPath => ArgumentError,
     Chef::Exceptions::EnvironmentNotFound => RuntimeError,
     Chef::Exceptions::InvalidVersionConstraint => ArgumentError,
-    Chef::Exceptions::IllegalVersionConstraint => NotImplementedError
+    Chef::Exceptions::IllegalVersionConstraint => NotImplementedError,
   }
 
   exception_to_super_class.each do |exception, expected_super_class|
     it "should have an exception class of #{exception} which inherits from #{expected_super_class}" do
-      expect{ raise exception }.to raise_error(expected_super_class)
+      expect { raise exception }.to raise_error(expected_super_class)
     end
 
     if exception.methods.include?(:to_json)
-      include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+      include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
         let(:jsonable) { exception }
       end
     end
@@ -95,7 +95,7 @@ describe Chef::Exceptions do
     end
 
     context "initialized with nothing" do
-      let(:e) { Chef::Exceptions::RunFailedWrappingError.new  }
+      let(:e) { Chef::Exceptions::RunFailedWrappingError.new }
       let(:num_errors) { 0 }
       let(:backtrace) { [] }
 
@@ -103,7 +103,7 @@ describe Chef::Exceptions do
     end
 
     context "initialized with nil" do
-      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(nil, nil)  }
+      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(nil, nil) }
       let(:num_errors) { 0 }
       let(:backtrace) { [] }
 
@@ -111,17 +111,17 @@ describe Chef::Exceptions do
     end
 
     context "initialized with 1 error and nil" do
-      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), nil)  }
+      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), nil) }
       let(:num_errors) { 1 }
-      let(:backtrace) { ["1) RuntimeError -  foo", ""] }
+      let(:backtrace) { ["1) RuntimeError -  foo"] }
 
       include_examples "RunFailedWrappingError expectations"
     end
 
     context "initialized with 2 errors" do
-      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), RuntimeError.new("bar"))  }
+      let(:e) { Chef::Exceptions::RunFailedWrappingError.new(RuntimeError.new("foo"), RuntimeError.new("bar")) }
       let(:num_errors) { 2 }
-      let(:backtrace) { ["1) RuntimeError -  foo", "", "2) RuntimeError -  bar", ""] }
+      let(:backtrace) { ["1) RuntimeError -  foo", "", "2) RuntimeError -  bar"] }
 
       include_examples "RunFailedWrappingError expectations"
     end
diff --git a/spec/unit/file_access_control_spec.rb b/spec/unit/file_access_control_spec.rb
index 2c68792..4357a91 100644
--- a/spec/unit/file_access_control_spec.rb
+++ b/spec/unit/file_access_control_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::FileAccessControl do
   describe "Unix" do
@@ -27,14 +27,14 @@ describe Chef::FileAccessControl do
         # platform specific module is mixed in
         @node = Chef::Node.new
         load File.join(File.dirname(__FILE__), "..", "..", "lib", "chef", "file_access_control.rb")
-        @resource = Chef::Resource::File.new('/tmp/a_file.txt')
-        @resource.owner('toor')
-        @resource.group('wheel')
-        @resource.mode('0400')
+        @resource = Chef::Resource::File.new("/tmp/a_file.txt")
+        @resource.owner("toor")
+        @resource.group("wheel")
+        @resource.mode("0400")
 
         @events = Chef::EventDispatch::Dispatcher.new
         @run_context = Chef::RunContext.new(@node, {}, @events)
-        @current_resource = Chef::Resource::File.new('/tmp/different_file.txt')
+        @current_resource = Chef::Resource::File.new("/tmp/different_file.txt")
         @provider_requirements = Chef::Provider::ResourceRequirements.new(@resource, @run_context)
         @provider = double("File provider", :requirements => @provider_requirements, :manage_symlink_access? => false)
 
@@ -42,7 +42,7 @@ describe Chef::FileAccessControl do
       end
     end
 
-    describe 'class methods' do
+    describe "class methods" do
       it 'responds to #writable?' do
         expect(Chef::FileAccessControl).to respond_to(:writable?)
       end
@@ -53,7 +53,7 @@ describe Chef::FileAccessControl do
     end
 
     it "has a file to manage" do
-      expect(@fac.file).to eq('/tmp/different_file.txt')
+      expect(@fac.file).to eq("/tmp/different_file.txt")
     end
 
     it "is not modified yet" do
@@ -61,12 +61,12 @@ describe Chef::FileAccessControl do
     end
 
     it "determines the uid of the owner specified by the resource" do
-      expect(Etc).to receive(:getpwnam).with('toor').and_return(OpenStruct.new(:uid => 2342))
+      expect(Etc).to receive(:getpwnam).with("toor").and_return(OpenStruct.new(:uid => 2342))
       expect(@fac.target_uid).to eq(2342)
     end
 
     it "raises a Chef::Exceptions::UserIDNotFound error when Etc can't find the user's name" do
-      expect(Etc).to receive(:getpwnam).with('toor').and_raise(ArgumentError)
+      expect(Etc).to receive(:getpwnam).with("toor").and_raise(ArgumentError)
       expect { @fac.target_uid ; @provider_requirements.run(:create) }.to raise_error(Chef::Exceptions::UserIDNotFound, "cannot determine user id for 'toor', does the user exist on this system?")
     end
 
@@ -98,16 +98,16 @@ describe Chef::FileAccessControl do
       # complement (i.e., it wraps around the maximum size of C unsigned int) of these
       # uids. So we have to get ruby and negative uids to smoke the peace pipe
       # with each other.
-      @resource.owner('nobody')
-      expect(Etc).to receive(:getpwnam).with('nobody').and_return(OpenStruct.new(:uid => (4294967294)))
+      @resource.owner("nobody")
+      expect(Etc).to receive(:getpwnam).with("nobody").and_return(OpenStruct.new(:uid => (4294967294)))
       expect(@fac.target_uid).to eq(-2)
     end
 
     it "does not wrap uids to their negative complements beyond -9" do
       # More: when OSX userIDs are created by ActiveDirectory sync, it tends to use huge numbers
       #  which had been incorrectly wrapped.  It does not look like the OSX IDs go below -2
-      @resource.owner('bigdude')
-      expect(Etc).to receive(:getpwnam).with('bigdude').and_return(OpenStruct.new(:uid => (4294967286)))
+      @resource.owner("bigdude")
+      expect(Etc).to receive(:getpwnam).with("bigdude").and_return(OpenStruct.new(:uid => (4294967286)))
       expect(@fac.target_uid).to eq(4294967286)
     end
 
@@ -133,7 +133,7 @@ describe Chef::FileAccessControl do
 
     it "sets the file's owner as specified in the resource when the current owner is incorrect" do
       @resource.owner(2342)
-      expect(File).to receive(:chown).with(2342, nil, '/tmp/different_file.txt')
+      expect(File).to receive(:chown).with(2342, nil, "/tmp/different_file.txt")
       @fac.set_owner
       expect(@fac).to be_modified
     end
@@ -153,7 +153,7 @@ describe Chef::FileAccessControl do
     end
 
     it "determines the gid of the group specified by the resource" do
-      expect(Etc).to receive(:getgrnam).with('wheel').and_return(OpenStruct.new(:gid => 2342))
+      expect(Etc).to receive(:getgrnam).with("wheel").and_return(OpenStruct.new(:gid => 2342))
       expect(@fac.target_gid).to eq(2342)
     end
 
@@ -163,18 +163,18 @@ describe Chef::FileAccessControl do
     end
 
     it "raises a Chef::Exceptions::GroupIDNotFound error when Etc can't find the user's name" do
-      expect(Etc).to receive(:getgrnam).with('wheel').and_raise(ArgumentError)
+      expect(Etc).to receive(:getgrnam).with("wheel").and_raise(ArgumentError)
       expect { @fac.target_gid; @provider_requirements.run(:create) }.to raise_error(Chef::Exceptions::GroupIDNotFound, "cannot determine group id for 'wheel', does the group exist on this system?")
     end
 
     it "does not attempt to resolve a gid when none is supplied" do
-      resource = Chef::Resource::File.new('crab')
+      resource = Chef::Resource::File.new("crab")
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
       expect(fac.target_gid).to be_nil
     end
 
     it "does not want to update the group when no target group is specified" do
-      resource = Chef::Resource::File.new('crab')
+      resource = Chef::Resource::File.new("crab")
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
       expect(fac.should_update_group?).to be_falsey
     end
@@ -197,7 +197,7 @@ describe Chef::FileAccessControl do
     end
 
     it "includes updating the group in the list of changes" do
-      resource = Chef::Resource::File.new('crab')
+      resource = Chef::Resource::File.new("crab")
       resource.group(2342)
       @current_resource.group(815)
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
@@ -208,7 +208,7 @@ describe Chef::FileAccessControl do
       @resource.group(2342)
       @current_resource.group(815)
 
-      expect(File).to receive(:chown).with(nil, 2342, '/tmp/different_file.txt')
+      expect(File).to receive(:chown).with(nil, 2342, "/tmp/different_file.txt")
       @fac.set_group
       expect(@fac).to be_modified
     end
@@ -230,7 +230,7 @@ describe Chef::FileAccessControl do
     end
 
     it "uses the supplied mode as octal when it's a string" do
-      @resource.mode('444')
+      @resource.mode("444")
       expect(@fac.target_mode).to eq(292) # octal 444 => decimal 292
     end
 
@@ -240,13 +240,13 @@ describe Chef::FileAccessControl do
     end
 
     it "does not try to determine the mode when none is given" do
-      resource = Chef::Resource::File.new('blahblah')
+      resource = Chef::Resource::File.new("blahblah")
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
       expect(fac.target_mode).to be_nil
     end
 
     it "doesn't want to update the mode when no target mode is given" do
-      resource = Chef::Resource::File.new('blahblah')
+      resource = Chef::Resource::File.new("blahblah")
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
       expect(fac.should_update_mode?).to be_falsey
     end
@@ -264,7 +264,7 @@ describe Chef::FileAccessControl do
     end
 
     it "includes changing the mode in the list of desired changes" do
-      resource = Chef::Resource::File.new('blahblah')
+      resource = Chef::Resource::File.new("blahblah")
       resource.mode("0750")
       @current_resource.mode("0444")
       fac = Chef::FileAccessControl.new(@current_resource, resource, @provider)
@@ -275,7 +275,7 @@ describe Chef::FileAccessControl do
       # stat returns modes like 0100644 (octal) => 33188 (decimal)
       #@fac.stub(:stat).and_return(OpenStruct.new(:mode => 33188))
       @current_resource.mode("0644")
-      expect(File).to receive(:chmod).with(256, '/tmp/different_file.txt')
+      expect(File).to receive(:chmod).with(256, "/tmp/different_file.txt")
       @fac.set_mode
       expect(@fac).to be_modified
     end
@@ -298,9 +298,9 @@ describe Chef::FileAccessControl do
       @resource.mode(0400)
       @resource.owner(0)
       @resource.group(0)
-      expect(File).to receive(:chmod).with(0400, '/tmp/different_file.txt')
-      expect(File).to receive(:chown).with(0, nil, '/tmp/different_file.txt')
-      expect(File).to receive(:chown).with(nil, 0, '/tmp/different_file.txt')
+      expect(File).to receive(:chmod).with(0400, "/tmp/different_file.txt")
+      expect(File).to receive(:chown).with(0, nil, "/tmp/different_file.txt")
+      expect(File).to receive(:chown).with(nil, 0, "/tmp/different_file.txt")
       @fac.set_all
       expect(@fac).to be_modified
     end
diff --git a/spec/unit/file_cache_spec.rb b/spec/unit/file_cache_spec.rb
index a24c3d3..388b0e7 100644
--- a/spec/unit/file_cache_spec.rb
+++ b/spec/unit/file_cache_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::FileCache do
   before do
@@ -32,11 +32,11 @@ describe Chef::FileCache do
   describe "when the relative path to the cache file doesn't exist" do
     it "creates intermediate directories as needed" do
       Chef::FileCache.store("whiz/bang", "I found a poop")
-      expect(File).to exist(File.join(@file_cache_path, 'whiz'))
+      expect(File).to exist(File.join(@file_cache_path, "whiz"))
     end
 
     it "creates the cached file at the correct relative path" do
-      expect(File).to receive(:open).with(File.join(@file_cache_path, 'whiz', 'bang'), "w",416).and_yield(@io)
+      expect(File).to receive(:open).with(File.join(@file_cache_path, "whiz", "bang"), "w", 416).and_yield(@io)
       Chef::FileCache.store("whiz/bang", "borkborkbork")
     end
 
@@ -56,35 +56,35 @@ describe Chef::FileCache do
 
   describe "when loading cached files" do
     it "finds and reads the cached file" do
-      FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
-      File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") }
-      expect(Chef::FileCache.load('whiz/bang')).to eq('borkborkbork')
+      FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+      File.open(File.join(@file_cache_path, "whiz", "bang"), "w") { |f| f.print("borkborkbork") }
+      expect(Chef::FileCache.load("whiz/bang")).to eq("borkborkbork")
     end
 
     it "should raise a Chef::Exceptions::FileNotFound if the file doesn't exist" do
-      expect { Chef::FileCache.load('whiz/bang') }.to raise_error(Chef::Exceptions::FileNotFound)
+      expect { Chef::FileCache.load("whiz/bang") }.to raise_error(Chef::Exceptions::FileNotFound)
     end
   end
 
   describe "when deleting cached files" do
     before(:each) do
-      FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
-      File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") }
+      FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+      File.open(File.join(@file_cache_path, "whiz", "bang"), "w") { |f| f.print("borkborkbork") }
     end
 
     it "unlinks the file" do
       Chef::FileCache.delete("whiz/bang")
-      expect(File).not_to exist(File.join(@file_cache_path, 'whiz', 'bang'))
+      expect(File).not_to exist(File.join(@file_cache_path, "whiz", "bang"))
     end
 
   end
 
   describe "when listing files in the cache" do
     before(:each) do
-      FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
-      FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang'))
-      FileUtils.mkdir_p(File.join(@file_cache_path, 'snappy'))
-      FileUtils.touch(File.join(@file_cache_path, 'snappy', 'patter'))
+      FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
+      FileUtils.touch(File.join(@file_cache_path, "whiz", "bang"))
+      FileUtils.mkdir_p(File.join(@file_cache_path, "snappy"))
+      FileUtils.touch(File.join(@file_cache_path, "snappy", "patter"))
     end
 
     it "should return the relative paths" do
@@ -92,18 +92,18 @@ describe Chef::FileCache do
     end
 
     it "searches for cached files by globbing" do
-      expect(Chef::FileCache.find('snappy/**/*')).to eq(%w{snappy/patter})
+      expect(Chef::FileCache.find("snappy/**/*")).to eq(%w{snappy/patter})
     end
 
   end
 
   describe "when checking for the existence of a file" do
     before do
-      FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz'))
+      FileUtils.mkdir_p(File.join(@file_cache_path, "whiz"))
     end
 
     it "has a key if the corresponding cache file exists" do
-      FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang'))
+      FileUtils.touch(File.join(@file_cache_path, "whiz", "bang"))
       expect(Chef::FileCache).to have_key("whiz/bang")
     end
 
diff --git a/spec/unit/file_content_management/deploy/cp_spec.rb b/spec/unit/file_content_management/deploy/cp_spec.rb
index 5c6583e..cbdb4f1 100644
--- a/spec/unit/file_content_management/deploy/cp_spec.rb
+++ b/spec/unit/file_content_management/deploy/cp_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::FileContentManagement::Deploy::Cp do
 
@@ -42,5 +42,3 @@ describe Chef::FileContentManagement::Deploy::Cp do
 
   end
 end
-
-
diff --git a/spec/unit/file_content_management/deploy/mv_unix_spec.rb b/spec/unit/file_content_management/deploy/mv_unix_spec.rb
index 4511f91..569fd89 100644
--- a/spec/unit/file_content_management/deploy/mv_unix_spec.rb
+++ b/spec/unit/file_content_management/deploy/mv_unix_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::FileContentManagement::Deploy::MvUnix do
 
@@ -99,5 +99,3 @@ describe Chef::FileContentManagement::Deploy::MvUnix do
 
   end
 end
-
-
diff --git a/spec/unit/file_content_management/deploy/mv_windows_spec.rb b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
index c52001c..30a62c4 100644
--- a/spec/unit/file_content_management/deploy/mv_windows_spec.rb
+++ b/spec/unit/file_content_management/deploy/mv_windows_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 unless Chef::Platform.windows?
   class Chef
@@ -31,7 +31,7 @@ unless Chef::Platform.windows?
   end
 end
 
-require 'chef/file_content_management/deploy/mv_windows'
+require "chef/file_content_management/deploy/mv_windows"
 
 describe Chef::FileContentManagement::Deploy::MvWindows do
 
@@ -72,7 +72,7 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
       end
 
       it "errors out with a WindowsNotAdmin error" do
-        expect { content_deployer.deploy(staging_file_path, target_file_path)}.to raise_error(Chef::Exceptions::WindowsNotAdmin)
+        expect { content_deployer.deploy(staging_file_path, target_file_path) }.to raise_error(Chef::Exceptions::WindowsNotAdmin)
       end
 
     end
@@ -92,7 +92,6 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
         double "security descriptor for target file"
       end
 
-
       before do
         allow(target_file_security_object).to receive(:security_descriptor).and_return(target_file_security_descriptor)
 
@@ -115,6 +114,62 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
 
       end
 
+      context "and the target file has null dacl and sacl" do
+
+        before do
+          allow(target_file_security_descriptor).to receive(:dacl_present?).and_return(true)
+          allow(target_file_security_descriptor).to receive(:dacl).and_return(nil)
+          allow(target_file_security_descriptor).to receive(:dacl_inherits?).and_return(false)
+
+          allow(target_file_security_descriptor).to receive(:sacl_present?).and_return(true)
+          allow(target_file_security_descriptor).to receive(:sacl).and_return(nil)
+          allow(target_file_security_descriptor).to receive(:sacl_inherits?).and_return(false)
+
+          expect(updated_target_security_object).to receive(:set_dacl).with(nil, false)
+          expect(updated_target_security_object).to receive(:set_sacl).with(nil, false)
+        end
+
+        it "fixes up permissions and moves the file into place" do
+          content_deployer.deploy(staging_file_path, target_file_path)
+        end
+
+      end
+
+      context "and the target has an empty dacl and sacl" do
+        let(:original_target_file_dacl) { [] }
+        let(:original_target_file_sacl) { [] }
+
+        let(:empty_dacl) { double("Windows ACL with no dacl ACEs") }
+        let(:empty_sacl) { double("Windows ACL with no sacl ACEs") }
+
+        before do
+          allow(target_file_security_descriptor).to receive(:dacl_present?).and_return(true)
+          allow(target_file_security_descriptor).to receive(:dacl_inherits?).and_return(false)
+
+          allow(target_file_security_descriptor).to receive(:dacl).and_return(original_target_file_dacl)
+          expect(Chef::ReservedNames::Win32::Security::ACL).
+            to receive(:create).
+            with([]).
+            and_return(empty_dacl)
+
+          allow(target_file_security_descriptor).to receive(:sacl_present?).and_return(true)
+          allow(target_file_security_descriptor).to receive(:sacl_inherits?).and_return(false)
+
+          allow(target_file_security_descriptor).to receive(:sacl).and_return(original_target_file_sacl)
+          expect(Chef::ReservedNames::Win32::Security::ACL).
+            to receive(:create).
+            with([]).
+            and_return(empty_sacl)
+
+          expect(updated_target_security_object).to receive(:set_dacl).with(empty_dacl, false)
+          expect(updated_target_security_object).to receive(:set_sacl).with(empty_sacl, false)
+        end
+
+        it "fixes up permissions and moves the file into place" do
+          content_deployer.deploy(staging_file_path, target_file_path)
+        end
+      end
+
       context "and the target has a dacl and sacl" do
         let(:inherited_dacl_ace) { double("Windows dacl ace (inherited)", :inherited? => true) }
         let(:not_inherited_dacl_ace) { double("Windows dacl ace (not inherited)", :inherited? => false) }
@@ -175,5 +230,3 @@ describe Chef::FileContentManagement::Deploy::MvWindows do
 
   end
 end
-
-
diff --git a/spec/unit/formatters/base_spec.rb b/spec/unit/formatters/base_spec.rb
index 6a843ea..30c7757 100644
--- a/spec/unit/formatters/base_spec.rb
+++ b/spec/unit/formatters/base_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
 #
-# Copyright:: Copyright (c) 2012 Chef Software, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Formatters::Base do
-  let(:out) { double("out") }
-  let(:err) { double("err") }
+  let(:out) { StringIO.new }
+  let(:err) { StringIO.new }
   let(:formatter) { Chef::Formatters::Base.new(out, err) }
 
   it "starts with an indentation of zero" do
@@ -43,6 +43,29 @@ describe Chef::Formatters::Base do
     formatter.indent_by(-2)
     expect(formatter.output.indent).to eql(0)
   end
-end
 
+  it "humanizes EOFError exceptions for #registration_failed" do
+    formatter.registration_failed("foo.example.com", EOFError.new, double("Chef::Config"))
+    expect(out.string).to match(/Received an EOF on transport socket/)
+  end
+
+  it "humanizes EOFError exceptions for #node_load_failed" do
+    formatter.node_load_failed("foo.example.com", EOFError.new, double("Chef::Config"))
+    expect(out.string).to match(/Received an EOF on transport socket/)
+  end
+
+  it "humanizes EOFError exceptions for #run_list_expand_failed" do
+    formatter.run_list_expand_failed(double("Chef::Node"), EOFError.new)
+    expect(out.string).to match(/Received an EOF on transport socket/)
+  end
+
+  it "humanizes EOFError exceptions for #cookbook_resolution_failed" do
+    formatter.run_list_expand_failed(double("Expanded Run List"), EOFError.new)
+    expect(out.string).to match(/Received an EOF on transport socket/)
+  end
 
+  it "humanizes EOFError exceptions for #cookbook_sync_failed" do
+    formatter.cookbook_sync_failed("foo.example.com", EOFError.new)
+    expect(out.string).to match(/Received an EOF on transport socket/)
+  end
+end
diff --git a/spec/unit/formatters/doc_spec.rb b/spec/unit/formatters/doc_spec.rb
new file mode 100644
index 0000000..e9bff07
--- /dev/null
+++ b/spec/unit/formatters/doc_spec.rb
@@ -0,0 +1,78 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Formatters::Base do
+
+  let(:out) { StringIO.new }
+  let(:err) { StringIO.new }
+
+  subject(:formatter) { Chef::Formatters::Doc.new(out, err) }
+
+  it "prints a policyfile's name and revision ID" do
+    minimal_policyfile = {
+      "revision_id" => "613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073",
+      "name" => "jenkins",
+      "run_list" => [
+        "recipe[apt::default]",
+        "recipe[java::default]",
+        "recipe[jenkins::master]",
+        "recipe[policyfile_demo::default]",
+      ],
+      "cookbook_locks" => {},
+    }
+
+    formatter.policyfile_loaded(minimal_policyfile)
+    expect(out.string).to include("Using policy 'jenkins' at revision '613f803bdd035d574df7fa6da525b38df45a74ca82b38b79655efed8a189e073'")
+  end
+
+  it "prints cookbook name and version" do
+    cookbook_version = double(name: "apache2", version: "1.2.3")
+    formatter.synchronized_cookbook("apache2", cookbook_version)
+    expect(out.string).to include("- apache2 (1.2.3")
+  end
+
+  it "prints only seconds when elapsed time is less than 60 seconds" do
+    @now = Time.now
+    allow(Time).to receive(:now).and_return(@now, @now + 10.0)
+    formatter.run_completed(nil)
+    expect(formatter.elapsed_time).to eql(10.0)
+    expect(formatter.pretty_elapsed_time).to include("10 seconds")
+    expect(formatter.pretty_elapsed_time).not_to include("minutes")
+    expect(formatter.pretty_elapsed_time).not_to include("hours")
+  end
+
+  it "prints minutes and seconds when elapsed time is more than 60 seconds" do
+    @now = Time.now
+    allow(Time).to receive(:now).and_return(@now, @now + 610.0)
+    formatter.run_completed(nil)
+    expect(formatter.elapsed_time).to eql(610.0)
+    expect(formatter.pretty_elapsed_time).to include("10 minutes 10 seconds")
+    expect(formatter.pretty_elapsed_time).not_to include("hours")
+  end
+
+  it "prints hours, minutes and seconds when elapsed time is more than 3600 seconds" do
+    @now = Time.now
+    allow(Time).to receive(:now).and_return(@now, @now + 36610.0)
+    formatter.run_completed(nil)
+    expect(formatter.elapsed_time).to eql(36610.0)
+    expect(formatter.pretty_elapsed_time).to include("10 hours 10 minutes 10 seconds")
+  end
+end
diff --git a/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
new file mode 100644
index 0000000..97fa92c
--- /dev/null
+++ b/spec/unit/formatters/error_inspectors/api_error_formatting_spec.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/formatters/error_inspectors/api_error_formatting"
+
+describe Chef::Formatters::APIErrorFormatting do
+  let(:class_instance) { (Class.new { include Chef::Formatters::APIErrorFormatting }).new }
+  let(:error_description) { instance_double(Chef::Formatters::ErrorDescription) }
+  let(:response) { double("response") }
+  before do
+    allow(response).to receive(:body)
+  end
+
+  context "when describe_406_error is called" do
+    context "when response['x-ops-server-api-version'] exists" do
+      let(:min_version) { "2" }
+      let(:max_version) { "5" }
+      let(:request_version) { "30" }
+      let(:return_hash) {
+        {
+          "min_version" => min_version,
+          "max_version" => max_version,
+          "request_version" => request_version,
+        }
+      }
+
+      before do
+        # mock out the header
+        allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash))
+      end
+
+      it "prints an error about client and server API version incompatibility with a min API version" do
+        expect(error_description).to receive(:section).with("Incompatible server API version:", /a min API version of #{min_version}/)
+        class_instance.describe_406_error(error_description, response)
+      end
+
+      it "prints an error about client and server API version incompatibility with a max API version" do
+        expect(error_description).to receive(:section).with("Incompatible server API version:", /a max API version of #{max_version}/)
+        class_instance.describe_406_error(error_description, response)
+      end
+
+      it "prints an error describing the request API version" do
+        expect(error_description).to receive(:section).with("Incompatible server API version:", /a request with an API version of #{request_version}/)
+        class_instance.describe_406_error(error_description, response)
+      end
+    end
+
+    context "when response.body['error'] != 'invalid-x-ops-server-api-version'" do
+
+      before do
+        allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(nil)
+      end
+
+      it "forwards the error_description to describe_http_error" do
+        expect(class_instance).to receive(:describe_http_error).with(error_description)
+        class_instance.describe_406_error(error_description, response)
+      end
+    end
+  end
+end
diff --git a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
index ac19e91..2c1da73 100644
--- a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-BAD_RECIPE=<<-E
+BAD_RECIPE = <<-E
 #
 # Cookbook Name:: syntax-err
 # Recipe:: default
 #
-# Copyright 2012, YOUR_COMPANY_NAME
+# Copyright 2012-2016, YOUR_COMPANY_NAME
 #
 # All rights reserved - Do Not Redistribute
 #
@@ -37,69 +37,148 @@ end
 E
 
 describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
-  before do
-    @node_name = "test-node.example.com"
-    @description = Chef::Formatters::ErrorDescription.new("Error Evaluating File:")
-    @exception = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File")
 
-    @outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR)
-    #@outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR)
-  end
+  let(:node_name) { "test-node.example.com" }
 
-  describe "when scrubbing backtraces" do
-    it "shows backtrace lines from cookbook files" do
-      # Error inspector originally used file_cache_path which is incorrect on
-      # chef-solo. Using cookbook_path should do the right thing for client and
-      # solo.
-      allow(Chef::Config).to receive(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ])
-      @trace = [
-        "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
-        "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
-        "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'"
-      ]
-      @exception.set_backtrace(@trace)
-      @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
-      @inspector = described_class.new(@path, @exception)
+  let(:description) { Chef::Formatters::ErrorDescription.new("Error Evaluating File:") }
 
-      @expected_filtered_trace = [
-        "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
-        "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
-      ]
-      expect(@inspector.filtered_bt).to eq(@expected_filtered_trace)
-    end
+  let(:exception) do
+    e = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File")
+    e.set_backtrace(trace)
+    e
   end
 
-  describe "when explaining an error in the compile phase" do
-    before do
-      allow(Chef::Config).to receive(:cookbook_path).and_return([ "/var/chef/cache/cookbooks" ])
-      recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
-      expect(IO).to receive(:readlines).with("/var/chef/cache/cookbooks/syntax-err/recipes/default.rb").and_return(recipe_lines)
-      @trace = [
-        "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
-        "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
-        "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display
-      ]
-      @exception.set_backtrace(@trace)
-      @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
-      @inspector = described_class.new(@path, @exception)
-      @inspector.add_explanation(@description)
+  # Change to $stdout to print error messages for manual inspection
+  let(:stdout) { StringIO.new }
+
+  let(:outputter) { Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR) }
+
+  subject(:inspector) { described_class.new(path_to_failed_file, exception) }
+
+  describe "finding the code responsible for the error" do
+
+    context "when the stacktrace includes cookbook files" do
+
+      let(:trace) do
+        [
+          "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+          "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+          "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'",
+        ]
+      end
+
+      let(:expected_filtered_trace) do
+        [
+          "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'",
+          "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'",
+        ]
+      end
+
+      let(:path_to_failed_file) { "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb" }
+
+      before do
+        # Error inspector originally used file_cache_path which is incorrect on
+        # chef-solo. Using cookbook_path should do the right thing for client and
+        # solo.
+        allow(Chef::Config).to receive(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ])
+      end
+
+      describe "when scrubbing backtraces" do
+        it "shows backtrace lines from cookbook files" do
+          expect(inspector.filtered_bt).to eq(expected_filtered_trace)
+        end
+      end
+
+      describe "when explaining an error in the compile phase" do
+        before do
+          recipe_lines = BAD_RECIPE.split("\n").map { |l| l << "\n" }
+          expect(IO).to receive(:readlines).with(path_to_failed_file).and_return(recipe_lines)
+          inspector.add_explanation(description)
+        end
+
+        it "reports the error was not located within cookbooks" do
+          expect(inspector.found_error_in_cookbooks?).to be(true)
+        end
+
+        it "finds the line number of the error from the stacktrace" do
+          expect(inspector.culprit_line).to eq(14)
+        end
+
+        it "prints a pretty message" do
+          description.display(outputter)
+        end
+      end
     end
 
-    it "finds the line number of the error from the stacktrace" do
-      expect(@inspector.culprit_line).to eq(14)
+    context "when the error is a RuntimeError about frozen object" do
+      let(:exception) do
+        e = RuntimeError.new("can't modify frozen Array")
+        e.set_backtrace(trace)
+        e
+      end
+
+      let(:path_to_failed_file) { "/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb" }
+
+      let(:trace) do
+        [
+          "/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb:2:in `block in from_file'",
+          "/tmp/kitchen/cache/cookbooks/foo/recipes/default.rb:1:in `from_file'",
+        ]
+      end
+
+      describe "when explaining a runtime error in the compile phase" do
+        it "correctly detects RuntimeError for frozen objects" do
+          expect(inspector.exception_message_modifying_frozen?).to be(true)
+        end
+
+        # could also test for description.section to be called, but would have
+        # to adjust every other test to begin using a test double for description
+      end
     end
 
-    it "prints a pretty message" do
-      @description.display(@outputter)
+    context "when the error does not contain any lines from cookbooks" do
+
+      let(:trace) do
+        [
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
+          "/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
+        ]
+      end
+
+      let(:exception) do
+        e = Chef::Exceptions::RecipeNotFound.new("recipe nope:nope not found")
+        e.set_backtrace(trace)
+        e
+      end
+
+      let(:path_to_failed_file) { nil }
+
+      it "gives a full, non-filtered trace" do
+        expect(inspector.filtered_bt).to eq(trace)
+      end
+
+      it "does not error when displaying the error" do
+        expect { description.display(outputter) }.to_not raise_error
+      end
+
+      it "reports the error was not located within cookbooks" do
+        expect(inspector.found_error_in_cookbooks?).to be(false)
+      end
+
     end
   end
 
   describe "when explaining an error on windows" do
-    before do
-      allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
-      recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
-      expect(IO).to receive(:readlines).at_least(1).times.with(/:\/opscode\/chef\/var\/cache\/cookbooks\/foo\/recipes\/default.rb/).and_return(recipe_lines)
-      @trace = [
+
+    let(:trace_with_upcase_drive) do
+      [
         "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
         "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
         "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
@@ -120,83 +199,67 @@ describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do
         "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
         "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
         "C:/opscode/chef/bin/chef-client:19:in `load'",
-        "C:/opscode/chef/bin/chef-client:19:in `<main>'"
+        "C:/opscode/chef/bin/chef-client:19:in `<main>'",
       ]
-      @exception.set_backtrace(@trace)
-      @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
-      @inspector = described_class.new(@path, @exception)
-      @inspector.add_explanation(@description)
     end
 
+    let(:trace) { trace_with_upcase_drive }
 
-    describe "and examining the stack trace for a recipe" do
-      it "find the culprit recipe name when the drive letter is upper case" do
-        expect(@inspector.culprit_file).to eq("C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+    let(:path_to_failed_file) { "/var/cache/cookbooks/foo/recipes/default.rb" }
+
+    before do
+      allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
+      recipe_lines = BAD_RECIPE.split("\n").map { |l| l << "\n" }
+      expect(IO).to receive(:readlines).at_least(1).times.with(full_path_to_failed_file).and_return(recipe_lines)
+      inspector.add_explanation(description)
+    end
+
+    context "when the drive letter in the path is uppercase" do
+
+      let(:full_path_to_failed_file) { "C:/opscode/chef#{path_to_failed_file}" }
+
+      it "reports the error was not located within cookbooks" do
+        expect(inspector.found_error_in_cookbooks?).to be(true)
       end
 
-      it "find the culprit recipe name when the drive letter is lower case" do
-        @trace.each { |line| line.gsub!(/^C:/, "c:") }
-        @exception.set_backtrace(@trace)
-        @inspector = described_class.new(@path, @exception)
-        @inspector.add_explanation(@description)
-        expect(@inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+      it "finds the culprit recipe name" do
+        expect(inspector.culprit_file).to eq("C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
       end
-    end
 
-    it "finds the line number of the error from the stack trace" do
-      expect(@inspector.culprit_line).to eq(14)
-    end
+      it "finds the line number of the error from the stack trace" do
+        expect(inspector.culprit_line).to eq(14)
+      end
 
-    it "prints a pretty message" do
-      @description.display(@outputter)
+      it "prints a pretty message" do
+        description.display(outputter)
+      end
     end
-  end
 
-  describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do
-    before do
-      allow(Chef::Config).to receive(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ])
-      recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" }
-      expect(IO).to receive(:readlines).with("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb").and_return(recipe_lines)
-      @trace = [
-        "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'",
-        "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `<top (required)>'",
-        "c:/opscode/chef/bin/chef-client:19:in `load'",
-        "c:/opscode/chef/bin/chef-client:19:in `<main>'"
-      ]
-      @exception.set_backtrace(@trace)
-      @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb"
-      @inspector = described_class.new(@path, @exception)
-      @inspector.add_explanation(@description)
-    end
+    context "when the drive letter in the path is lowercase" do
 
-    it "finds the culprit recipe name from the stacktrace" do
-      expect(@inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
-    end
+      let(:trace) do
+        trace_with_upcase_drive.map { |line| line.gsub(/^C:/, "c:") }
+      end
 
-    it "finds the line number of the error from the stack trace" do
-      expect(@inspector.culprit_line).to eq(14)
-    end
+      let(:full_path_to_failed_file) { "c:/opscode/chef#{path_to_failed_file}" }
+
+      it "reports the error was not located within cookbooks" do
+        expect(inspector.found_error_in_cookbooks?).to be(true)
+      end
+
+      it "finds the culprit recipe name from the stacktrace" do
+        expect(inspector.culprit_file).to eq("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb")
+      end
 
-    it "prints a pretty message" do
-      @description.display(@outputter)
+      it "finds the line number of the error from the stack trace" do
+        expect(inspector.culprit_line).to eq(14)
+      end
+
+      it "prints a pretty message" do
+        description.display(outputter)
+      end
     end
+
   end
 
 end
diff --git a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
index 7e4d89f..0764338 100644
--- a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
 
@@ -32,7 +32,7 @@ describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
   describe "when explaining a 403 error" do
     before do
 
-      @response_body = %Q({"error": [{"message": "gtfo"}])
+      @response_body = %q({"error": [{"message": "gtfo"}])
       @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden")
       allow(@response).to receive(:body).and_return(@response_body)
       @exception = Net::HTTPServerException.new("(exception) forbidden", @response)
@@ -124,6 +124,3 @@ describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do
 
   end
 end
-
-
-
diff --git a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
index 775a183..02846af 100644
--- a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Formatters::ErrorInspectors::CookbookSyncErrorInspector do
   before do
diff --git a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
index d2bbffa..93aac41 100644
--- a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 # spec_helper loads the shared examples already.
 #require 'support/shared/unit/api_error_inspector_spec'
 
-
 describe Chef::Formatters::ErrorInspectors::NodeLoadErrorInspector do
   it_behaves_like "an api error inspector"
 end
diff --git a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
index 4c21dad..cea9388 100644
--- a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 # spec_helper loads the shared examples already.
 #require 'support/shared/unit/api_error_inspector_spec'
 
-
 describe Chef::Formatters::ErrorInspectors::RegistrationErrorInspector do
   it_behaves_like "an api error inspector"
 end
diff --git a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
index a42d234..072dcfe 100644
--- a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
   include Chef::DSL::Recipe
@@ -95,7 +95,7 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
 
         @error = begin
                    @context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno")
-                 rescue  Chef::Mixin::Template::TemplateError => e
+                 rescue Chef::Mixin::Template::TemplateError => e
                    e
                  end
 
@@ -108,7 +108,6 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
         expect(@stdout.string).to include(@error.source_listing)
       end
 
-
     end
 
     describe "recipe_snippet" do
@@ -126,6 +125,13 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
         expect(@inspector.recipe_snippet).to match(/^# In C:\/Users\/btm/)
       end
 
+      it "parses a Windows path" do
+        source_line = "C:\\Windows\\Temp\\packer\\cookbooks\\fake_file.rb:2: undefined local variable or method `non_existent' for main:Object (NameError)"
+        @resource.source_line = source_line
+        @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception)
+        expect(@inspector.recipe_snippet).to match(/^# In C:\\Windows\\Temp\\packer\\/)
+      end
+
       it "parses a unix path" do
         source_line = "/home/btm/src/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existent' for main:Object (NameError)"
         @resource.source_line = source_line
@@ -182,5 +188,4 @@ describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do
 
   end
 
-
 end
diff --git a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
index 1cd9759..3e988c5 100644
--- a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
+++ b/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
   before do
@@ -39,7 +39,6 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
 
       @exception = Chef::Exceptions::MissingRole.new(@run_list_expansion)
 
-
       @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
       @inspector.add_explanation(@description)
     end
@@ -78,8 +77,8 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
 
       @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception)
       allow(@inspector).to receive(:config).and_return(:node_name => "unit-test.example.com",
-                                           :client_key => "/etc/chef/client.pem",
-                                           :chef_server_url => "http://chef.example.com")
+                                                       :client_key => "/etc/chef/client.pem",
+                                                       :chef_server_url => "http://chef.example.com")
 
       @inspector.add_explanation(@description)
     end
@@ -90,4 +89,3 @@ describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do
   end
 
 end
-
diff --git a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
index 4cf3ba8..e76e69d 100644
--- a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
+++ b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::GuardInterpreter::ResourceGuardInterpreter do
   let(:node) do
@@ -24,6 +24,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
 
     node.default["kernel"] = Hash.new
     node.default["kernel"][:machine] = :x86_64.to_s
+    node.automatic[:os] = "windows"
     node
   end
 
@@ -51,7 +52,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
 
     it "raises an exception if guard_interpreter is set to a resource not derived from Chef::Resource::Script" do
       parent_resource.guard_interpreter(:file)
-      expect { guard_interpreter }.to raise_error(ArgumentError, 'Specified guard interpreter class Chef::Resource::File must be a kind of Chef::Resource::Execute resource')
+      expect { guard_interpreter }.to raise_error(ArgumentError, "Specified guard interpreter class Chef::Resource::File must be a kind of Chef::Resource::Execute resource")
     end
 
     context "when the resource cannot be found for the platform" do
@@ -61,7 +62,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
 
       it "raises an exception" do
         parent_resource.guard_interpreter(:foobar)
-        expect { guard_interpreter }.to raise_error(ArgumentError, 'Specified guard_interpreter resource foobar unknown for this platform')
+        expect { guard_interpreter }.to raise_error(ArgumentError, "Specified guard_interpreter resource foobar unknown for this platform")
       end
     end
 
@@ -83,6 +84,14 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
       expect(guard_interpreter.evaluate).to eq(true)
     end
 
+    it "does not corrupt the run_context of the node" do
+      node_run_context_before_guard_execution = parent_resource.run_context
+      expect(node_run_context_before_guard_execution.object_id).to eq(parent_resource.node.run_context.object_id)
+      guard_interpreter.evaluate
+      node_run_context_after_guard_execution = parent_resource.run_context
+      expect(node_run_context_after_guard_execution.object_id).to eq(parent_resource.node.run_context.object_id)
+    end
+
     describe "script command opts switch" do
       let(:command_opts) { {} }
       let(:guard_interpreter) { Chef::GuardInterpreter::ResourceGuardInterpreter.new(parent_resource, "exit 0", command_opts) }
@@ -109,7 +118,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
           end
 
           it "merges to :code" do
-            expect(command_opts).to receive(:merge).with({:code => "exit 0"}).and_call_original
+            expect(command_opts).to receive(:merge).with({ :code => "exit 0" }).and_call_original
             expect(guard_interpreter.evaluate).to eq(true)
           end
         end
@@ -122,7 +131,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
           end
 
           it "merges to :code" do
-            expect(command_opts).to receive(:merge).with({:command => "exit 0"}).and_call_original
+            expect(command_opts).to receive(:merge).with({ :command => "exit 0" }).and_call_original
             expect(guard_interpreter.evaluate).to eq(true)
           end
         end
@@ -136,7 +145,7 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
         end
 
         it "merges to :command" do
-          expect(command_opts).to receive(:merge).with({:command => "exit 0"}).and_call_original
+          expect(command_opts).to receive(:merge).with({ :command => "exit 0" }).and_call_original
           expect(guard_interpreter.evaluate).to eq(true)
         end
       end
@@ -144,4 +153,3 @@ describe Chef::GuardInterpreter::ResourceGuardInterpreter do
     end
   end
 end
-
diff --git a/spec/unit/guard_interpreter_spec.rb b/spec/unit/guard_interpreter_spec.rb
index a7fe064..1bfc831 100644
--- a/spec/unit/guard_interpreter_spec.rb
+++ b/spec/unit/guard_interpreter_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Steven Danna (steve at chef.io)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::GuardInterpreter do
   describe "#for_resource" do
-    let (:resource) { Chef::Resource.new("foo")}
+    let (:resource) { Chef::Resource.new("foo") }
 
     it "returns a DefaultGuardInterpreter if the resource has guard_interpreter set to :default" do
       resource.guard_interpreter :default
diff --git a/spec/unit/handler/json_file_spec.rb b/spec/unit/handler/json_file_spec.rb
index f6c14a1..4be4486 100644
--- a/spec/unit/handler/json_file_spec.rb
+++ b/spec/unit/handler/json_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Handler::JsonFile do
   before(:each) do
-    @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => '/tmp/foobarbazqux')
+    @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => "/tmp/foobarbazqux")
   end
 
   it "accepts arbitrary config options" do
@@ -28,8 +28,8 @@ describe Chef::Handler::JsonFile do
   end
 
   it "creates the directory where the reports will be saved" do
-    expect(FileUtils).to receive(:mkdir_p).with('/tmp/foobarbazqux')
-    expect(File).to receive(:chmod).with(00700, '/tmp/foobarbazqux')
+    expect(FileUtils).to receive(:mkdir_p).with("/tmp/foobarbazqux")
+    expect(File).to receive(:chmod).with(00700, "/tmp/foobarbazqux")
     @handler.build_report_dir
   end
 
@@ -49,15 +49,14 @@ describe Chef::Handler::JsonFile do
       allow(File).to receive(:open).and_yield(@file_mock)
     end
 
-
     it "saves run status data to a file as JSON" do
       expect(@handler).to receive(:build_report_dir)
       @handler.run_report_unsafe(@run_status)
-      reported_data = Chef::JSONCompat.from_json(@file_mock.string)
-      expect(reported_data['exception']).to eq("Exception: Boy howdy!")
-      expect(reported_data['start_time']).to eq(@expected_time.to_s)
-      expect(reported_data['end_time']).to eq((@expected_time + 5).to_s)
-      expect(reported_data['elapsed_time']).to eq(5)
+      reported_data = Chef::JSONCompat.parse(@file_mock.string)
+      expect(reported_data["exception"]).to eq("Exception: Boy howdy!")
+      expect(reported_data["start_time"]).to eq(@expected_time.to_s)
+      expect(reported_data["end_time"]).to eq((@expected_time + 5).to_s)
+      expect(reported_data["elapsed_time"]).to eq(5)
     end
 
   end
diff --git a/spec/unit/handler_spec.rb b/spec/unit/handler_spec.rb
index e7f6740..65c3ddc 100644
--- a/spec/unit/handler_spec.rb
+++ b/spec/unit/handler_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Handler do
   before(:each) do
@@ -36,7 +36,7 @@ describe Chef::Handler do
       @exception.set_backtrace(@backtrace)
       @run_status.exception = @exception
       @run_context = Chef::RunContext.new(@node, {}, @events)
-      @all_resources = [Chef::Resource::Cat.new('lolz'), Chef::Resource::ZenMaster.new('tzu')]
+      @all_resources = [Chef::Resource::Cat.new("lolz"), Chef::Resource::ZenMaster.new("tzu")]
       @all_resources.first.updated = true
       @run_context.resource_collection.all_resources.replace(@all_resources)
       @run_status.run_context = @run_context
@@ -100,7 +100,7 @@ describe Chef::Handler do
         $report_ran = true
         raise Exception, "I died the deth"
       end
-      expect {@handler.run_report_safely(@run_status)}.not_to raise_error
+      expect { @handler.run_report_safely(@run_status) }.not_to raise_error
       expect($report_ran).to be_truthy
     end
     it "does not fail if the report handler does not raise an exception" do
@@ -108,7 +108,7 @@ describe Chef::Handler do
       def @handler.report
         $report_ran = true
       end
-      expect {@handler.run_report_safely(@run_status)}.not_to raise_error
+      expect { @handler.run_report_safely(@run_status) }.not_to raise_error
       expect($report_ran).to be_truthy
     end
   end
@@ -117,7 +117,7 @@ describe Chef::Handler do
   describe "when running a report handler" do
     before do
       @run_context = Chef::RunContext.new(@node, {}, @events)
-      @all_resources = [Chef::Resource::Cat.new('foo'), Chef::Resource::ZenMaster.new('moo')]
+      @all_resources = [Chef::Resource::Cat.new("foo"), Chef::Resource::ZenMaster.new("moo")]
       @all_resources.first.updated = true
       @run_context.resource_collection.all_resources.replace(@all_resources)
       @run_status.run_context = @run_context
diff --git a/spec/unit/http/authenticator_spec.rb b/spec/unit/http/authenticator_spec.rb
new file mode 100644
index 0000000..7fd2bdc
--- /dev/null
+++ b/spec/unit/http/authenticator_spec.rb
@@ -0,0 +1,80 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/http/authenticator"
+
+describe Chef::HTTP::Authenticator do
+  let(:class_instance) { Chef::HTTP::Authenticator.new }
+  let(:method) { double("method") }
+  let(:url) { double("url") }
+  let(:headers) { Hash.new }
+  let(:data) { double("data") }
+
+  before do
+    allow(class_instance).to receive(:authentication_headers).and_return({})
+  end
+
+  context "when handle_request is called" do
+    shared_examples_for "merging the server API version into the headers" do
+      it "merges the default version of X-Ops-Server-API-Version into the headers" do
+        # headers returned
+        expect(class_instance.handle_request(method, url, headers, data)[2]).
+          to include({ "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION })
+      end
+
+      context "when api_version is set to something other than the default" do
+        let(:class_instance) { Chef::HTTP::Authenticator.new({ :api_version => "-10" }) }
+
+        it "merges the requested version of X-Ops-Server-API-Version into the headers" do
+          expect(class_instance.handle_request(method, url, headers, data)[2]).
+            to include({ "X-Ops-Server-API-Version" => "-10" })
+        end
+      end
+    end
+
+    context "when !sign_requests?" do
+      before do
+        allow(class_instance).to receive(:sign_requests?).and_return(false)
+      end
+
+      it_behaves_like "merging the server API version into the headers"
+
+      it "authentication_headers is not called" do
+        expect(class_instance).to_not receive(:authentication_headers)
+        class_instance.handle_request(method, url, headers, data)
+      end
+
+    end
+
+    context "when sign_requests?" do
+      before do
+        allow(class_instance).to receive(:sign_requests?).and_return(true)
+      end
+
+      it_behaves_like "merging the server API version into the headers"
+
+      it "calls authentication_headers with the proper input" do
+        expect(class_instance).to receive(:authentication_headers).with(
+          method, url, data,
+          { "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION }).and_return({})
+        class_instance.handle_request(method, url, headers, data)
+      end
+    end
+  end
+end
diff --git a/spec/unit/http/basic_client_spec.rb b/spec/unit/http/basic_client_spec.rb
index 32b32a5..4abdb52 100644
--- a/spec/unit/http/basic_client_spec.rb
+++ b/spec/unit/http/basic_client_spec.rb
@@ -15,8 +15,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/http/basic_client'
+require "spec_helper"
+require "chef/http/basic_client"
 
 describe "HTTP Connection" do
 
@@ -89,7 +89,7 @@ describe "HTTP Connection" do
           {
             "https_proxy" => "https://proxy.mycorp.com:8080",
             "https_proxy_user" => "jane_username",
-            "https_proxy_pass" => "opensesame"
+            "https_proxy_pass" => "opensesame",
           }
         end
 
@@ -109,5 +109,21 @@ describe "HTTP Connection" do
       end
 
     end
+
+    context "when an empty proxy is set by the environment" do
+      let(:env) do
+        {
+          "https_proxy" => ""
+        }
+      end
+
+      before do
+        allow(subject).to receive(:env).and_return(env)
+      end
+
+      it "to not fail with URI parse exception" do
+        expect { subject.proxy_uri }.to_not raise_error
+      end
+    end
   end
 end
diff --git a/spec/unit/http/http_request_spec.rb b/spec/unit/http/http_request_spec.rb
index 3bba201..29562de 100644
--- a/spec/unit/http/http_request_spec.rb
+++ b/spec/unit/http/http_request_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Klaas Jan Wierenga (<k.j.wierenga at gmail.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,40 +16,40 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::HTTP::HTTPRequest do
 
   context "with HTTP url scheme" do
 
     it "should not include port 80 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com')
+      expect(request.headers["Host"]).to eql("dummy.com")
     end
 
     it "should not include explicit port 80 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:80'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:80"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com')
+      expect(request.headers["Host"]).to eql("dummy.com")
     end
 
     it "should include explicit port 8000 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com:8000')
+      expect(request.headers["Host"]).to eql("dummy.com:8000")
     end
 
     it "should include explicit 443 port in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:443'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:443"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com:443')
+      expect(request.headers["Host"]).to eql("dummy.com:443")
     end
 
     it "should pass on explicit Host header unchanged" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '', { 'Host' => 'yourhost.com:8888' })
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "", { "Host" => "yourhost.com:8888" })
 
-      expect(request.headers['Host']).to eql('yourhost.com:8888')
+      expect(request.headers["Host"]).to eql("yourhost.com:8888")
     end
 
   end
@@ -57,35 +57,35 @@ describe Chef::HTTP::HTTPRequest do
   context "with HTTPS url scheme" do
 
     it "should not include port 443 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com')
+      expect(request.headers["Host"]).to eql("dummy.com")
     end
 
     it "should include explicit port 80 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:80'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:80"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com:80')
+      expect(request.headers["Host"]).to eql("dummy.com:80")
     end
 
     it "should include explicit port 8000 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:8000'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:8000"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com:8000')
+      expect(request.headers["Host"]).to eql("dummy.com:8000")
     end
 
     it "should not include explicit port 443 in Host header" do
-      request = Chef::HTTP::HTTPRequest.new(:GET, URI('https://dummy.com:443'), '')
+      request = Chef::HTTP::HTTPRequest.new(:GET, URI("https://dummy.com:443"), "")
 
-      expect(request.headers['Host']).to eql('dummy.com')
+      expect(request.headers["Host"]).to eql("dummy.com")
     end
 
   end
 
   it "should pass on explicit Host header unchanged" do
-    request = Chef::HTTP::HTTPRequest.new(:GET, URI('http://dummy.com:8000'), '', { 'Host' => 'myhost.com:80' })
+    request = Chef::HTTP::HTTPRequest.new(:GET, URI("http://dummy.com:8000"), "", { "Host" => "myhost.com:80" })
 
-    expect(request.headers['Host']).to eql('myhost.com:80')
+    expect(request.headers["Host"]).to eql("myhost.com:80")
   end
 
 end
diff --git a/spec/unit/http/json_input_spec.rb b/spec/unit/http/json_input_spec.rb
index fbf8f22..a76c8d1 100644
--- a/spec/unit/http/json_input_spec.rb
+++ b/spec/unit/http/json_input_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/http/json_input'
+require "spec_helper"
+require "chef/http/json_input"
 
 describe Chef::HTTP::JSONInput do
 
@@ -66,7 +66,7 @@ describe Chef::HTTP::JSONInput do
   context "when the request should be serialized" do
 
     let(:http_method) { :put }
-    let(:data) { {foo: "bar"} }
+    let(:data) { { foo: "bar" } }
     let(:expected_data) { %q[{"foo":"bar"}] }
 
     context "and the request has a ruby object as the body and no explicit content-type" do
@@ -111,7 +111,7 @@ describe Chef::HTTP::JSONInput do
       expect(handle_request).to eq([http_method, url, headers, data])
 
       # not normalized
-      expect(headers).to eq({"content-type" => "application/x-binary"})
+      expect(headers).to eq({ "content-type" => "application/x-binary" })
     end
 
     it "does not serialize the body to json when content type is given in capitalized form" do
@@ -120,7 +120,7 @@ describe Chef::HTTP::JSONInput do
       expect(handle_request).to eq([http_method, url, headers, data])
 
       # not normalized
-      expect(headers).to eq({"Content-Type" => "application/x-binary"})
+      expect(headers).to eq({ "Content-Type" => "application/x-binary" })
     end
 
   end
diff --git a/spec/unit/http/simple_spec.rb b/spec/unit/http/simple_spec.rb
index c8fb52e..0170266 100644
--- a/spec/unit/http/simple_spec.rb
+++ b/spec/unit/http/simple_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::HTTP::Simple do
   it "should have content length validation middleware after compressor middleware" do
diff --git a/spec/unit/http/socketless_chef_zero_client_spec.rb b/spec/unit/http/socketless_chef_zero_client_spec.rb
index 963cc9e..637e562 100644
--- a/spec/unit/http/socketless_chef_zero_client_spec.rb
+++ b/spec/unit/http/socketless_chef_zero_client_spec.rb
@@ -1,6 +1,6 @@
 #--
 # Author:: Daniel DeLeo (<dan at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'chef/http/socketless_chef_zero_client'
+require "chef/http/socketless_chef_zero_client"
 
 describe Chef::HTTP::SocketlessChefZeroClient do
 
@@ -110,7 +110,7 @@ describe Chef::HTTP::SocketlessChefZeroClient do
       end
 
       it "does not fail when calling read_body with a block" do
-        expect(net_http_response.read_body {|chunk| chunk }).to eq("bunch o' JSON")
+        expect(net_http_response.read_body { |chunk| chunk }).to eq("bunch o' JSON")
       end
 
     end
@@ -149,7 +149,6 @@ describe Chef::HTTP::SocketlessChefZeroClient do
       }
     end
 
-
     let(:response_code) { 200 }
     let(:response_headers) { { "Content-Type" => "Application/JSON" } }
     let(:response_body) { [ "bunch o' JSON" ] }
diff --git a/spec/unit/http/ssl_policies_spec.rb b/spec/unit/http/ssl_policies_spec.rb
index 5ebebf3..df6dee1 100644
--- a/spec/unit/http/ssl_policies_spec.rb
+++ b/spec/unit/http/ssl_policies_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/http/ssl_policies'
+require "spec_helper"
+require "chef/http/ssl_policies"
 
 describe "HTTP SSL Policy" do
 
@@ -54,7 +54,7 @@ describe "HTTP SSL Policy" do
 
       it "raises a ConfigurationError if :ssl_ca_path is set to a path that doesn't exist" do
         Chef::Config[:ssl_ca_path] = "/dev/null/nothing_here"
-        expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+        expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
       end
 
       it "should set the CA path if that is set in the configuration" do
@@ -64,12 +64,12 @@ describe "HTTP SSL Policy" do
 
       it "raises a ConfigurationError if :ssl_ca_file is set to a file that does not exist" do
         Chef::Config[:ssl_ca_file] = "/dev/null/nothing_here"
-        expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+        expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
       end
 
       it "should set the CA file if that is set in the configuration" do
-        Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + '/ssl/5e707473.0'
-        expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + '/ssl/5e707473.0')
+        Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + "/ssl/5e707473.0"
+        expect(http_client.ca_file).to eq(CHEF_SPEC_DATA + "/ssl/5e707473.0")
       end
     end
 
@@ -85,31 +85,31 @@ describe "HTTP SSL Policy" do
     end
 
     describe "when configured with a client certificate" do
-      before {@url = URI.parse("https://chef.example.com:4443/")}
+      before { @url = URI.parse("https://chef.example.com:4443/") }
 
       it "raises ConfigurationError if the certificate file doesn't exist" do
         Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
-        Chef::Config[:ssl_client_key]  = CHEF_SPEC_DATA + '/ssl/chef-rspec.key'
-        expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+        Chef::Config[:ssl_client_key]  = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
+        expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
       end
 
       it "raises ConfigurationError if the certificate file doesn't exist" do
-        Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert'
+        Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
         Chef::Config[:ssl_client_key]  = "/dev/null/nothing_here"
-        expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+        expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
       end
 
       it "raises a ConfigurationError if one of :ssl_client_cert and :ssl_client_key is set but not both" do
         Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here"
         Chef::Config[:ssl_client_key]  = nil
-        expect {http_client}.to raise_error(Chef::Exceptions::ConfigurationError)
+        expect { http_client }.to raise_error(Chef::Exceptions::ConfigurationError)
       end
 
       it "configures the HTTP client's cert and private key" do
-        Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert'
-        Chef::Config[:ssl_client_key]  = CHEF_SPEC_DATA + '/ssl/chef-rspec.key'
-        expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.cert')).to_s)
-        expect(http_client.key.to_s).to  eq(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.key'))
+        Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + "/ssl/chef-rspec.cert"
+        Chef::Config[:ssl_client_key]  = CHEF_SPEC_DATA + "/ssl/chef-rspec.key"
+        expect(http_client.cert.to_s).to eq(OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.cert")).to_s)
+        expect(http_client.key.to_s).to eq(OpenSSL::PKey::RSA.new(IO.read(CHEF_SPEC_DATA + "/ssl/chef-rspec.key")).to_s)
       end
     end
 
@@ -167,4 +167,3 @@ describe "HTTP SSL Policy" do
 
   end
 end
-
diff --git a/spec/unit/http/validate_content_length_spec.rb b/spec/unit/http/validate_content_length_spec.rb
index 79bd539..c054529 100644
--- a/spec/unit/http/validate_content_length_spec.rb
+++ b/spec/unit/http/validate_content_length_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'stringio'
+require "spec_helper"
+require "stringio"
 
 describe Chef::HTTP::ValidateContentLength do
   class TestClient < Chef::HTTP
@@ -29,7 +29,7 @@ describe Chef::HTTP::ValidateContentLength do
   let(:headers) { {} }
   let(:data) { false }
 
-  let(:request) { }
+  let(:request) {}
   let(:return_value) { "200" }
 
   # Test Variables
@@ -44,7 +44,7 @@ describe Chef::HTTP::ValidateContentLength do
   }
 
   let(:response) {
-    m = double('HttpResponse', :body => response_body)
+    m = double("HttpResponse", :body => response_body)
     allow(m).to receive(:[]) do |key|
       response_headers[key]
     end
@@ -105,7 +105,7 @@ describe Chef::HTTP::ValidateContentLength do
   end
 
   describe "without Content-Length header" do
-    let(:response_headers) { { } }
+    let(:response_headers) { {} }
 
     [ "direct", "streaming" ].each do |req_type|
       describe "when running #{req_type} request" do
@@ -157,7 +157,7 @@ describe Chef::HTTP::ValidateContentLength do
     let(:response_headers) {
       {
         "content-length" => content_length_value,
-        "transfer-encoding" => "chunked"
+        "transfer-encoding" => "chunked",
       }
     }
 
@@ -180,7 +180,7 @@ describe Chef::HTTP::ValidateContentLength do
     end
 
     it "should reset internal counter" do
-        expect(middleware.instance_variable_get(:@content_length_counter)).to be_nil
+      expect(middleware.instance_variable_get(:@content_length_counter)).to be_nil
     end
 
     it "should validate correctly second time" do
diff --git a/spec/unit/http_spec.rb b/spec/unit/http_spec.rb
index 4d851df..12c3bfc 100644
--- a/spec/unit/http_spec.rb
+++ b/spec/unit/http_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
+# Copyright:: Copyright 2014-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/http'
-require 'chef/http/basic_client'
-require 'chef/http/socketless_chef_zero_client'
+require "chef/http"
+require "chef/http/basic_client"
+require "chef/http/socketless_chef_zero_client"
 
 class Chef::HTTP
   public :create_url
@@ -43,26 +43,26 @@ describe Chef::HTTP do
 
   describe "create_url" do
 
-    it 'should return a correctly formatted url 1/3 CHEF-5261' do
-      http = Chef::HTTP.new('http://www.getchef.com')
-      expect(http.create_url('api/endpoint')).to eql(URI.parse('http://www.getchef.com/api/endpoint'))
+    it "should return a correctly formatted url 1/3 CHEF-5261" do
+      http = Chef::HTTP.new("http://www.getchef.com")
+      expect(http.create_url("api/endpoint")).to eql(URI.parse("http://www.getchef.com/api/endpoint"))
     end
 
-    it 'should return a correctly formatted url 2/3 CHEF-5261' do
-      http = Chef::HTTP.new('http://www.getchef.com/')
-      expect(http.create_url('/organization/org/api/endpoint/')).to eql(URI.parse('http://www.getchef.com/organization/org/api/endpoint/'))
+    it "should return a correctly formatted url 2/3 CHEF-5261" do
+      http = Chef::HTTP.new("http://www.getchef.com/")
+      expect(http.create_url("/organization/org/api/endpoint/")).to eql(URI.parse("http://www.getchef.com/organization/org/api/endpoint/"))
     end
 
-    it 'should return a correctly formatted url 3/3 CHEF-5261' do
-      http = Chef::HTTP.new('http://www.getchef.com/organization/org///')
-      expect(http.create_url('///api/endpoint?url=http://foo.bar')).to eql(URI.parse('http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar'))
+    it "should return a correctly formatted url 3/3 CHEF-5261" do
+      http = Chef::HTTP.new("http://www.getchef.com/organization/org///")
+      expect(http.create_url("///api/endpoint?url=http://foo.bar")).to eql(URI.parse("http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar"))
     end
 
     # As per: https://github.com/opscode/chef/issues/2500
-    it 'should treat scheme part of the URI in a case-insensitive manner' do
+    it "should treat scheme part of the URI in a case-insensitive manner" do
       http = Chef::HTTP.allocate # Calling Chef::HTTP::new sets @url, don't want that.
-      expect { http.create_url('HTTP://www1.chef.io/') }.not_to raise_error
-      expect(http.create_url('HTTP://www2.chef.io/')).to eql(URI.parse('http://www2.chef.io/'))
+      expect { http.create_url("HTTP://www1.chef.io/") }.not_to raise_error
+      expect(http.create_url("HTTP://www2.chef.io/")).to eql(URI.parse("http://www2.chef.io/"))
     end
 
   end # create_url
@@ -89,4 +89,106 @@ describe Chef::HTTP do
 
   end # head
 
+  describe "retrying connection errors" do
+
+    let(:uri) { "https://chef.example/organizations/default/" }
+
+    subject(:http) { Chef::HTTP.new(uri) }
+
+    # http#http_client gets stubbed later, so eager create
+    let!(:low_level_client) { http.http_client(URI(uri)) }
+
+    let(:http_ok_response) do
+      Net::HTTPOK.new("1.1", 200, "OK").tap do |r|
+        allow(r).to receive(:read_body).and_return("")
+      end
+    end
+
+    before do
+      allow(http).to receive(:http_client).with(URI(uri)).and_return(low_level_client)
+    end
+
+    shared_examples_for "retriable_request_errors" do
+
+      before do
+        expect(low_level_client).to receive(:request).exactly(5).times.and_raise(exception)
+        expect(http).to receive(:sleep).exactly(5).times.and_return(1)
+        expect(low_level_client).to receive(:request).and_return([low_level_client, http_ok_response])
+      end
+
+      it "retries the request 5 times" do
+        http.get("/")
+      end
+
+    end
+
+    shared_examples_for "errors_that_are_not_retried" do
+
+      before do
+        expect(low_level_client).to receive(:request).exactly(1).times.and_raise(exception)
+        expect(http).to_not receive(:sleep)
+      end
+
+      it "raises the error without retrying or sleeping" do
+        # We modify the strings to give addtional context, but the exception class should be the same
+        expect { http.get("/") }.to raise_error(exception.class)
+      end
+    end
+
+    context "when ECONNRESET is raised" do
+
+      let(:exception) { Errno::ECONNRESET.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when SocketError is raised" do
+
+      let(:exception) { SocketError.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when ETIMEDOUT is raised" do
+
+      let(:exception) { Errno::ETIMEDOUT.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when ECONNREFUSED is raised" do
+
+      let(:exception) { Errno::ECONNREFUSED.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when Timeout::Error is raised" do
+
+      let(:exception) { Timeout::Error.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when OpenSSL::SSL::SSLError is raised" do
+
+      let(:exception) { OpenSSL::SSL::SSLError.new("example error") }
+
+      include_examples "retriable_request_errors"
+
+    end
+
+    context "when OpenSSL::SSL::SSLError is raised for certificate validation failure" do
+
+      let(:exception) { OpenSSL::SSL::SSLError.new("ssl_connect returned=1 errno=0 state=sslv3 read server certificate b: certificate verify failed") }
+
+      include_examples "errors_that_are_not_retried"
+
+    end
+  end
 end
diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb
index 7482ba8..4da29fe 100644
--- a/spec/unit/json_compat_spec.rb
+++ b/spec/unit/json_compat_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Juanje Ojeda (<juanje.ojeda at gmail.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,21 @@
 # limitations under the License.
 #
 
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/json_compat'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/json_compat"
 
 describe Chef::JSONCompat do
+  before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
 
   describe "#from_json with JSON containing an existing class" do
     let(:json) { '{"json_class": "Chef::Role"}' }
 
+    it "emits a deprecation warning" do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = true
+      expect { Chef::JSONCompat.from_json(json) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+        /Auto inflation of JSON data is deprecated. Please use Chef::Role#from_hash/
+    end
+
     it "returns an instance of the class instead of a Hash" do
       expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role
     end
@@ -46,19 +53,19 @@ describe Chef::JSONCompat do
   end
 
   describe 'with JSON containing "Chef::Sandbox" as a json_class value' do
-    require 'chef/sandbox' # Only needed for this test
+    require "chef/sandbox" # Only needed for this test
 
     let(:json) { '{"json_class": "Chef::Sandbox", "arbitrary": "data"}' }
 
     it "returns a Hash, because Chef::Sandbox is a dummy class" do
-      expect(Chef::JSONCompat.from_json(json)).to eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"})
+      expect(Chef::JSONCompat.from_json(json)).to eq({ "json_class" => "Chef::Sandbox", "arbitrary" => "data" })
     end
   end
 
   describe "when pretty printing an object that defines #to_json" do
     class Foo
       def to_json(*a)
-        Chef::JSONCompat.to_json({'foo' => 1234, 'bar' => {'baz' => 5678}}, *a)
+        Chef::JSONCompat.to_json({ "foo" => 1234, "bar" => { "baz" => 5678 } }, *a)
       end
     end
 
@@ -67,15 +74,13 @@ describe Chef::JSONCompat do
       expect(Chef::JSONCompat.to_json_pretty(f)).to eql("{\n  \"foo\": 1234,\n  \"bar\": {\n    \"baz\": 5678\n  }\n}\n")
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { Foo.new }
     end
   end
 
-  # On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
-  # https://github.com/chef/chef/issues/3101
   describe "with the file with 252 or less nested entries" do
-    let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
+    let(:json) { IO.read(File.join(CHEF_SPEC_DATA, "nested.json")) }
     let(:hash) { Chef::JSONCompat.from_json(json) }
 
     describe "when the 252 json file is loaded" do
@@ -84,7 +89,10 @@ describe Chef::JSONCompat do
       end
 
       it "should has 'test' as a 252 nested value" do
-        expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['ke [...]
+        v = 252.times.inject(hash) do |memo, _|
+          memo["key"]
+        end
+        expect(v).to eq("test")
       end
     end
   end
diff --git a/spec/unit/key_spec.rb b/spec/unit/key_spec.rb
new file mode 100644
index 0000000..ef8d39b
--- /dev/null
+++ b/spec/unit/key_spec.rb
@@ -0,0 +1,631 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+require "chef/key"
+
+describe Chef::Key do
+  # whether user or client irrelevent to these tests
+  let(:key) { Chef::Key.new("original_actor", "user") }
+  let(:public_key_string) do
+    <<EOS
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----
+EOS
+  end
+
+  shared_examples_for "fields with username type validation" do
+    context "when invalid input is passed" do
+      # It is not feasible to check all invalid characters.  Here are a few
+      # that we probably care about.
+      it "should raise an ArgumentError" do
+        # capital letters
+        expect { key.send(field, "Bar") }.to raise_error(ArgumentError)
+        # slashes
+        expect { key.send(field, "foo/bar") }.to raise_error(ArgumentError)
+        # ?
+        expect { key.send(field, "foo?") }.to raise_error(ArgumentError)
+        # &
+        expect { key.send(field, "foo&") }.to raise_error(ArgumentError)
+        # spaces
+        expect { key.send(field, "foo ") }.to raise_error(ArgumentError)
+      end
+    end
+  end
+
+  shared_examples_for "string fields that are settable" do
+    context "when it is set with valid input" do
+      it "should set the field" do
+        key.send(field, valid_input)
+        expect(key.send(field)).to eq(valid_input)
+      end
+    end
+
+    context "when you feed it anything but a string" do
+      it "should raise an ArgumentError" do
+        expect { key.send(field, Hash.new) }.to raise_error(ArgumentError)
+      end
+    end
+  end
+
+  describe "when a new Chef::Key object is initialized with invalid input" do
+    it "should raise an InvalidKeyArgument" do
+      expect { Chef::Key.new("original_actor", "not_a_user_or_client") }.to raise_error(Chef::Exceptions::InvalidKeyArgument)
+    end
+  end
+
+  describe "when a new Chef::Key object is initialized with valid input" do
+    it "should be a Chef::Key" do
+      expect(key).to be_a_kind_of(Chef::Key)
+    end
+
+    it "should properly set the actor" do
+      expect(key.actor).to eq("original_actor")
+    end
+  end
+
+  describe "when actor field is set" do
+    it_should_behave_like "string fields that are settable" do
+      let(:field) { :actor }
+      let(:valid_input) { "new_field_value" }
+    end
+
+    it_should_behave_like "fields with username type validation" do
+      let(:field) { :actor }
+    end
+  end
+
+  describe "when the name field is set" do
+    it_should_behave_like "string fields that are settable" do
+      let(:field) { :name }
+      let(:valid_input) { "new_field_value" }
+    end
+  end
+
+  describe "when the private_key field is set" do
+    it_should_behave_like "string fields that are settable" do
+      let(:field) { :private_key }
+      let(:valid_input) { "new_field_value" }
+    end
+  end
+
+  describe "when the public_key field is set" do
+    it_should_behave_like "string fields that are settable" do
+      let(:field) { :public_key }
+      let(:valid_input) { "new_field_value" }
+    end
+
+    context "when create_key is true" do
+      before do
+        key.create_key true
+      end
+
+      it "should raise an InvalidKeyAttribute" do
+        expect { key.public_key public_key_string }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+      end
+    end
+  end
+
+  describe "when the create_key field is set" do
+    context "when it is set to true" do
+      it "should set the field" do
+        key.create_key(true)
+        expect(key.create_key).to eq(true)
+      end
+    end
+
+    context "when it is set to false" do
+      it "should set the field" do
+        key.create_key(false)
+        expect(key.create_key).to eq(false)
+      end
+    end
+
+    context "when anything but a TrueClass or FalseClass is passed" do
+      it "should raise an ArgumentError" do
+        expect { key.create_key "not_a_boolean" }.to raise_error(ArgumentError)
+      end
+    end
+
+    context "when public_key is defined" do
+      before do
+        key.public_key public_key_string
+      end
+
+      it "should raise an InvalidKeyAttribute" do
+        expect { key.create_key true }.to raise_error(Chef::Exceptions::InvalidKeyAttribute)
+      end
+    end
+  end
+
+  describe "when the expiration_date field is set" do
+    context "when a valid date is passed" do
+      it_should_behave_like "string fields that are settable" do
+        let(:field) { :public_key }
+        let(:valid_input) { "2020-12-24T21:00:00Z" }
+      end
+    end
+
+    context "when infinity is passed" do
+      it_should_behave_like "string fields that are settable" do
+        let(:field) { :public_key }
+        let(:valid_input) { "infinity" }
+      end
+    end
+
+    context "when an invalid date is passed" do
+      it "should raise an ArgumentError" do
+        expect { key.expiration_date "invalid_date" }.to raise_error(ArgumentError)
+        # wrong years
+        expect { key.expiration_date "20-12-24T21:00:00Z" }.to raise_error(ArgumentError)
+      end
+
+      context "when it is a valid UTC date missing a Z" do
+        it "should raise an ArgumentError" do
+          expect { key.expiration_date "2020-12-24T21:00:00" }.to raise_error(ArgumentError)
+        end
+      end
+    end
+  end # when the expiration_date field is set
+
+  describe "when serializing to JSON" do
+    shared_examples_for "common json operations" do
+      it "should serializes as a JSON object" do
+        expect(json).to match(/^\{.+\}$/)
+      end
+
+      it "should include the actor value under the key relative to the actor_field_name passed" do
+        expect(json).to include(%Q{"#{new_key.actor_field_name}":"original_actor"})
+      end
+
+      it "should include the name field when present" do
+        new_key.name("monkeypants")
+        expect(new_key.to_json).to include(%q{"name":"monkeypants"})
+      end
+
+      it "should not include the name if not present" do
+        expect(json).to_not include("name")
+      end
+
+      it "should include the public_key field when present" do
+        new_key.public_key "this_public_key"
+        expect(new_key.to_json).to include(%q{"public_key":"this_public_key"})
+      end
+
+      it "should not include the public_key if not present" do
+        expect(json).to_not include("public_key")
+      end
+
+      it "should include the private_key field when present" do
+        new_key.private_key "this_public_key"
+        expect(new_key.to_json).to include(%q{"private_key":"this_public_key"})
+      end
+
+      it "should not include the private_key if not present" do
+        expect(json).to_not include("private_key")
+      end
+
+      it "should include the expiration_date field when present" do
+        new_key.expiration_date "2020-12-24T21:00:00Z"
+        expect(new_key.to_json).to include(%q{"expiration_date":"2020-12-24T21:00:00Z"})
+      end
+
+      it "should not include the expiration_date if not present" do
+        expect(json).to_not include("expiration_date")
+      end
+
+      it "should include the create_key field when present" do
+        new_key.create_key true
+        expect(new_key.to_json).to include(%q{"create_key":true})
+      end
+
+      it "should not include the create_key if not present" do
+        expect(json).to_not include("create_key")
+      end
+    end
+
+    context "when key is for a user" do
+      it_should_behave_like "common json operations" do
+        let(:new_key) { Chef::Key.new("original_actor", "user") }
+        let(:json) do
+          new_key.to_json
+        end
+      end
+    end
+
+    context "when key is for a client" do
+      it_should_behave_like "common json operations" do
+        let(:new_key) { Chef::Key.new("original_actor", "client") }
+        let(:json) do
+          new_key.to_json
+        end
+      end
+    end
+
+  end # when serializing to JSON
+
+  describe "when deserializing from JSON" do
+    shared_examples_for "a deserializable object" do
+      it "deserializes to a Chef::Key object" do
+        expect(key).to be_a_kind_of(Chef::Key)
+      end
+
+      it "preserves the actor" do
+        expect(key.actor).to eq("turtle")
+      end
+
+      it "preserves the name" do
+        expect(key.name).to eq("key_name")
+      end
+
+      it "includes the public key if present" do
+        expect(key.public_key).to eq(public_key_string)
+      end
+
+      it "includes the expiration_date if present" do
+        expect(key.expiration_date).to eq("infinity")
+      end
+
+      it "includes the private_key if present" do
+        expect(key.private_key).to eq("some_private_key")
+      end
+
+      it "includes the create_key if present" do
+        expect(key_with_create_key_field.create_key).to eq(true)
+      end
+    end
+
+    context "when deserializing a key for a user" do
+      it_should_behave_like "a deserializable object" do
+        let(:key) do
+          o = { "user" => "turtle",
+                "name" => "key_name",
+                "public_key" => public_key_string,
+                "private_key" => "some_private_key",
+                "expiration_date" => "infinity" }
+          Chef::Key.from_json(o.to_json)
+        end
+        let(:key_with_create_key_field) do
+          o = { "user" => "turtle",
+                "create_key" => true }
+          Chef::Key.from_json(o.to_json)
+        end
+      end
+    end
+
+    context "when deserializing a key for a client" do
+      it_should_behave_like "a deserializable object" do
+        let(:key) do
+          o = { "client" => "turtle",
+                "name" => "key_name",
+                "public_key" => public_key_string,
+                "private_key" => "some_private_key",
+                "expiration_date" => "infinity" }
+          Chef::Key.from_json(o.to_json)
+        end
+        let(:key_with_create_key_field) do
+          o = { "client" => "turtle",
+                "create_key" => true }
+          Chef::Key.from_json(o.to_json)
+        end
+      end
+    end
+  end # when deserializing from JSON
+
+  describe "API Interactions" do
+    let(:rest) do
+      Chef::Config[:chef_server_root] = "http://www.example.com"
+      Chef::Config[:chef_server_url] = "http://www.example.com/organizations/test_org"
+      r = double("rest")
+      allow(Chef::ServerAPI).to receive(:new).and_return(r)
+      r
+    end
+
+    let(:user_key) do
+      o = Chef::Key.new("foobar", "user")
+      o
+    end
+
+    let(:client_key) do
+      o = Chef::Key.new("foobar", "client")
+      o
+    end
+
+    describe "list" do
+      context "when listing keys for a user" do
+        let(:response) { [{ "uri" => "http://www.example.com/users/keys/foobar", "name" => "foobar", "expired" => false }] }
+        let(:inflated_response) { { "foobar" => user_key } }
+
+        it "lists all keys" do
+          expect(rest).to receive(:get).with("users/#{user_key.actor}/keys").and_return(response)
+          expect(Chef::Key.list_by_user("foobar")).to eq(response)
+        end
+
+        it "inflate all keys" do
+          allow(Chef::Key).to receive(:load_by_user).with(user_key.actor, "foobar").and_return(user_key)
+          expect(rest).to receive(:get).with("users/#{user_key.actor}/keys").and_return(response)
+          expect(Chef::Key.list_by_user("foobar", true)).to eq(inflated_response)
+        end
+
+      end
+
+      context "when listing keys for a client" do
+        let(:response) { [{ "uri" => "http://www.example.com/users/keys/foobar", "name" => "foobar", "expired" => false }] }
+        let(:inflated_response) { { "foobar" => client_key } }
+
+        it "lists all keys" do
+          expect(rest).to receive(:get).with("clients/#{client_key.actor}/keys").and_return(response)
+          expect(Chef::Key.list_by_client("foobar")).to eq(response)
+        end
+
+        it "inflate all keys" do
+          allow(Chef::Key).to receive(:load_by_client).with(client_key.actor, "foobar").and_return(client_key)
+          expect(rest).to receive(:get).with("clients/#{user_key.actor}/keys").and_return(response)
+          expect(Chef::Key.list_by_client("foobar", true)).to eq(inflated_response)
+        end
+
+      end
+    end
+
+    describe "create" do
+      shared_examples_for "create key" do
+        context "when a field is missing" do
+          it "should raise a MissingKeyAttribute" do
+            expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+          end
+        end
+
+        context "when the name field is missing" do
+          before do
+            key.public_key public_key_string
+            key.expiration_date "2020-12-24T21:00:00Z"
+          end
+
+          it "creates a new key via the API with the fingerprint as the name" do
+            expect(rest).to receive(:post).with(url,
+                                                     { "name" => "12:3e:33:73:0b:f4:ec:72:dc:f0:4c:51:62:27:08:76:96:24:f4:4a",
+                                                       "public_key" => key.public_key,
+                                                       "expiration_date" => key.expiration_date }).and_return({})
+            key.create
+          end
+        end
+
+        context "when every field is populated" do
+          before do
+            key.name "key_name"
+            key.public_key public_key_string
+            key.expiration_date "2020-12-24T21:00:00Z"
+            key.create_key false
+          end
+
+          context "when create_key is false" do
+            it "creates a new key via the API" do
+              expect(rest).to receive(:post).with(url,
+                                                       { "name" => key.name,
+                                                         "public_key" => key.public_key,
+                                                         "expiration_date" => key.expiration_date }).and_return({})
+              key.create
+            end
+          end
+
+          context "when create_key is true and public_key is nil" do
+
+            before do
+              key.delete_public_key
+              key.create_key true
+              $expected_output = {
+                actor_type => "foobar",
+                "name" => key.name,
+                "create_key" => true,
+                "expiration_date" => key.expiration_date,
+              }
+              $expected_input = {
+                "name" => key.name,
+                "create_key" => true,
+                "expiration_date" => key.expiration_date,
+              }
+            end
+
+            it "should create a new key via the API" do
+              expect(rest).to receive(:post).with(url, $expected_input).and_return({})
+              key.create
+            end
+
+            context "when the server returns the private_key via key.create" do
+              before do
+                allow(rest).to receive(:post).with(url, $expected_input).and_return({ "private_key" => "this_private_key" })
+              end
+
+              it "key.create returns the original key plus the private_key" do
+                expect(key.create.to_hash).to eq($expected_output.merge({ "private_key" => "this_private_key" }))
+              end
+            end
+          end
+
+          context "when create_key is false and public_key is nil" do
+            before do
+              key.delete_public_key
+              key.create_key false
+            end
+            it "should raise an InvalidKeyArgument" do
+              expect { key.create }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+            end
+          end
+        end
+      end
+
+      context "when creating a user key" do
+        it_should_behave_like "create key" do
+          let(:url) { "users/#{key.actor}/keys" }
+          let(:key) { user_key }
+          let(:actor_type) { "user" }
+        end
+      end
+
+      context "when creating a client key" do
+        it_should_behave_like "create key" do
+          let(:url) { "clients/#{client_key.actor}/keys" }
+          let(:key) { client_key }
+          let(:actor_type) { "client" }
+        end
+      end
+    end # create
+
+    describe "update" do
+      shared_examples_for "update key" do
+        context "when name is missing and no argument was passed to update" do
+          it "should raise an MissingKeyAttribute" do
+            expect { key.update }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+          end
+        end
+
+        context "when some fields are populated" do
+          before do
+            key.name "key_name"
+            key.expiration_date "2020-12-24T21:00:00Z"
+          end
+
+          it "should update the key via the API" do
+            expect(rest).to receive(:put).with(url, key.to_hash).and_return({})
+            key.update
+          end
+        end
+
+        context "when @name is not nil and a arg is passed to update" do
+          before do
+            key.name "new_name"
+          end
+
+          it "passes @name in the body and the arg in the PUT URL" do
+            expect(rest).to receive(:put).with(update_name_url, key.to_hash).and_return({})
+            key.update("old_name")
+          end
+        end
+
+        context "when the server returns a public_key and create_key is true" do
+          before do
+            key.name "key_name"
+            key.create_key true
+            allow(rest).to receive(:put).with(url, key.to_hash).and_return({
+                                                                                  "key" => "key_name",
+                                                                                  "public_key" => public_key_string,
+                                                                                },)
+
+          end
+
+          it "returns a key with public_key populated" do
+            new_key = key.update
+            expect(new_key.public_key).to eq(public_key_string)
+          end
+
+          it "returns a key without create_key set" do
+            new_key = key.update
+            expect(new_key.create_key).to be_nil
+          end
+        end
+      end
+
+      context "when updating a user key" do
+        it_should_behave_like "update key" do
+          let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+          let(:update_name_url) { "users/#{key.actor}/keys/old_name" }
+          let(:key) { user_key }
+        end
+      end
+
+      context "when updating a client key" do
+        it_should_behave_like "update key" do
+          let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+          let(:update_name_url) { "clients/#{client_key.actor}/keys/old_name" }
+          let(:key) { client_key }
+        end
+      end
+
+    end #update
+
+    describe "load" do
+      shared_examples_for "load" do
+        it "should load a named key from the API" do
+          expect(rest).to receive(:get).with(url).and_return({ "user" => "foobar", "name" => "test_key_name", "public_key" => public_key_string, "expiration_date" => "infinity" })
+          key = Chef::Key.send(load_method, "foobar", "test_key_name")
+          expect(key.actor).to eq("foobar")
+          expect(key.name).to eq("test_key_name")
+          expect(key.public_key).to eq(public_key_string)
+          expect(key.expiration_date).to eq("infinity")
+        end
+      end
+
+      describe "load_by_user" do
+        it_should_behave_like "load" do
+          let(:load_method) { :load_by_user }
+          let(:url) { "users/foobar/keys/test_key_name" }
+        end
+      end
+
+      describe "load_by_client" do
+        it_should_behave_like "load" do
+          let(:load_method) { :load_by_client }
+          let(:url) { "clients/foobar/keys/test_key_name" }
+        end
+      end
+
+    end #load
+
+    describe "destroy" do
+      shared_examples_for "destroy key" do
+        context "when name is missing" do
+          it "should raise an MissingKeyAttribute" do
+            expect { Chef::Key.new("username", "user").destroy }.to raise_error(Chef::Exceptions::MissingKeyAttribute)
+          end
+        end
+
+        before do
+          key.name "key_name"
+        end
+        context "when name is not missing" do
+          it "should delete the key via the API" do
+            expect(rest).to receive(:delete).with(url).and_return({})
+            key.destroy
+          end
+        end
+      end
+
+      context "when destroying a user key" do
+        it_should_behave_like "destroy key" do
+          let(:url) { "users/#{key.actor}/keys/#{key.name}" }
+          let(:key) { user_key }
+        end
+      end
+
+      context "when destroying a client key" do
+        it_should_behave_like "destroy key" do
+          let(:url) { "clients/#{client_key.actor}/keys/#{key.name}" }
+          let(:key) { client_key }
+        end
+      end
+    end
+  end # API Interactions
+end
diff --git a/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb b/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
index d8f8426..ffc851e 100644
--- a/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
+++ b/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist <lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::Bootstrap::ChefVaultHandler do
 
@@ -27,7 +27,7 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
 
   let(:knife_config) { {} }
 
-  let(:node_name) { "bevell.wat" }
+  let(:client) { Chef::ApiClient.new }
 
   let(:chef_vault_handler) {
     chef_vault_handler = Chef::Knife::Bootstrap::ChefVaultHandler.new(knife_config: knife_config, ui: ui)
@@ -50,67 +50,66 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
     let(:bootstrap_vault_item) { double("ChefVault::Item") }
 
     before do
-      expect(chef_vault_handler).to receive(:wait_for_client).and_return(false)
       expect(chef_vault_handler).to receive(:require_chef_vault!).at_least(:once)
-      expect(bootstrap_vault_item).to receive(:clients).with("name:#{node_name}").at_least(:once)
+      expect(bootstrap_vault_item).to receive(:clients).with(client).at_least(:once)
       expect(bootstrap_vault_item).to receive(:save).at_least(:once)
     end
 
     context "from knife_config[:bootstrap_vault_item]" do
       it "sets a single item as a scalar" do
-        knife_config[:bootstrap_vault_item] = { 'vault' => 'item1' }
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        knife_config[:bootstrap_vault_item] = { "vault" => "item1" }
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets a single item as an array" do
-        knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1' ] }
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        knife_config[:bootstrap_vault_item] = { "vault" => [ "item1" ] }
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two items as an array" do
-        knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1', 'item2' ] }
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        knife_config[:bootstrap_vault_item] = { "vault" => [ "item1", "item2" ] }
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two vaults from different hash keys" do
-        knife_config[:bootstrap_vault_item] = { 'vault' => [ 'item1', 'item2' ], 'vault2' => [ 'item3' ] }
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        knife_config[:bootstrap_vault_item] = { "vault" => [ "item1", "item2" ], "vault2" => [ "item3" ] }
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
     end
 
     context "from knife_config[:bootstrap_vault_json]" do
       it "sets a single item as a scalar" do
         knife_config[:bootstrap_vault_json] = '{ "vault": "item1" }'
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets a single item as an array" do
         knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1" ] }'
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two items as an array" do
         knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1", "item2" ] }'
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two vaults from different hash keys" do
         knife_config[:bootstrap_vault_json] = '{ "vault": [ "item1", "item2" ], "vault2": [ "item3" ] }'
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
     end
 
@@ -124,29 +123,29 @@ describe Chef::Knife::Bootstrap::ChefVaultHandler do
 
       it "sets a single item as a scalar" do
         setup_file_contents('{ "vault": "item1" }')
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets a single item as an array" do
         setup_file_contents('{ "vault": [ "item1" ] }')
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two items as an array" do
         setup_file_contents('{ "vault": [ "item1", "item2" ] }')
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
 
       it "sets two vaults from different hash keys" do
         setup_file_contents('{ "vault": [ "item1", "item2" ], "vault2": [ "item3" ] }')
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item1').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault', 'item2').and_return(bootstrap_vault_item)
-        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with('vault2', 'item3').and_return(bootstrap_vault_item)
-        chef_vault_handler.run(node_name: node_name)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item1").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault", "item2").and_return(bootstrap_vault_item)
+        expect(chef_vault_handler).to receive(:load_chef_bootstrap_vault_item).with("vault2", "item3").and_return(bootstrap_vault_item)
+        chef_vault_handler.run(client)
       end
     end
   end
diff --git a/spec/unit/knife/bootstrap/client_builder_spec.rb b/spec/unit/knife/bootstrap/client_builder_spec.rb
index e6aa307..491d0ca 100644
--- a/spec/unit/knife/bootstrap/client_builder_spec.rb
+++ b/spec/unit/knife/bootstrap/client_builder_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist <lamont at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-
+require "spec_helper"
 
 describe Chef::Knife::Bootstrap::ClientBuilder do
 
@@ -32,7 +31,7 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
 
   let(:node_name) { "bevell.wat" }
 
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
 
   let(:client_builder) {
     client_builder = Chef::Knife::Bootstrap::ClientBuilder.new(knife_config: knife_config, chef_config: chef_config, ui: ui)
@@ -42,7 +41,7 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
   }
 
   context "#sanity_check!" do
-    let(:response_404) { OpenStruct.new(:code => '404') }
+    let(:response_404) { OpenStruct.new(:code => "404") }
     let(:exception_404) { Net::HTTPServerException.new("404 not found", response_404) }
 
     context "in cases where the prompting fails" do
@@ -53,15 +52,15 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
       end
 
       it "exits when the node exists and the user does not want to delete" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
-        expect(ui.stdin).to receive(:readline).and_return('n')
+        expect(rest).to receive(:get).with("nodes/#{node_name}")
+        expect(ui.stdin).to receive(:readline).and_return("n")
         expect { client_builder.run }.to raise_error(SystemExit)
       end
 
       it "exits when the client exists and the user does not want to delete" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
-        expect(rest).to receive(:get_rest).with("clients/#{node_name}")
-        expect(ui.stdin).to receive(:readline).and_return('n')
+        expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+        expect(rest).to receive(:get).with("clients/#{node_name}")
+        expect(ui.stdin).to receive(:readline).and_return("n")
         expect { client_builder.run }.to raise_error(SystemExit)
       end
     end
@@ -74,31 +73,31 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
       end
 
       it "when both the client and node do not exist it succeeds" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
-        expect(rest).to receive(:get_rest).with("clients/#{node_name}").and_raise(exception_404)
+        expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+        expect(rest).to receive(:get).with("clients/#{node_name}").and_raise(exception_404)
         expect { client_builder.run }.not_to raise_error
       end
 
       it "when we are allowed to delete an old node" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
-        expect(ui.stdin).to receive(:readline).and_return('y')
-        expect(rest).to receive(:get_rest).with("clients/#{node_name}").and_raise(exception_404)
+        expect(rest).to receive(:get).with("nodes/#{node_name}")
+        expect(ui.stdin).to receive(:readline).and_return("y")
+        expect(rest).to receive(:get).with("clients/#{node_name}").and_raise(exception_404)
         expect(rest).to receive(:delete).with("nodes/#{node_name}")
         expect { client_builder.run }.not_to raise_error
       end
 
       it "when we are allowed to delete an old client" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}").and_raise(exception_404)
-        expect(rest).to receive(:get_rest).with("clients/#{node_name}")
-        expect(ui.stdin).to receive(:readline).and_return('y')
+        expect(rest).to receive(:get).with("nodes/#{node_name}").and_raise(exception_404)
+        expect(rest).to receive(:get).with("clients/#{node_name}")
+        expect(ui.stdin).to receive(:readline).and_return("y")
         expect(rest).to receive(:delete).with("clients/#{node_name}")
         expect { client_builder.run }.not_to raise_error
       end
 
       it "when we are are allowed to delete both an old client and node" do
-        expect(rest).to receive(:get_rest).with("nodes/#{node_name}")
-        expect(rest).to receive(:get_rest).with("clients/#{node_name}")
-        expect(ui.stdin).to receive(:readline).twice.and_return('y')
+        expect(rest).to receive(:get).with("nodes/#{node_name}")
+        expect(rest).to receive(:get).with("clients/#{node_name}")
+        expect(ui.stdin).to receive(:readline).twice.and_return("y")
         expect(rest).to receive(:delete).with("nodes/#{node_name}")
         expect(rest).to receive(:delete).with("clients/#{node_name}")
         expect { client_builder.run }.not_to raise_error
@@ -107,17 +106,20 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
   end
 
   context "#create_client!" do
+    let(:client) { Chef::ApiClient.new }
+
     before do
       # mock out the rest of #run
       expect(client_builder).to receive(:sanity_check)
       expect(client_builder).to receive(:create_node!)
     end
 
-    it "delegates everything to Chef::ApiClient::Registration" do
+    it "delegates everything to Chef::ApiClient::Registration and sets client" do
       reg_double = double("Chef::ApiClient::Registration")
       expect(Chef::ApiClient::Registration).to receive(:new).with(node_name, client_builder.client_path, http_api: rest).and_return(reg_double)
-      expect(reg_double).to receive(:run)
+      expect(reg_double).to receive(:run).and_return(client)
       client_builder.run
+      expect(client_builder.client).to eq(client)
     end
 
   end
@@ -140,7 +142,7 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
       expect(node).to receive(:save)
     end
 
-    let(:client_rest) { double("Chef::REST (client)") }
+    let(:client_rest) { double("Chef::ServerAPI (client)") }
 
     let(:node) { double("Chef::Node") }
 
@@ -149,6 +151,22 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
       client_builder.run
     end
 
+    it "does not add tags by default" do
+      allow(node).to receive(:run_list).with([])
+      expect(node).to_not receive(:tags)
+      client_builder.run
+    end
+
+    it "adds tags to the node when given" do
+      tag_receiver = []
+
+      knife_config[:tags] = %w{foo bar}
+      allow(node).to receive(:run_list).with([])
+      allow(node).to receive(:tags).and_return(tag_receiver)
+      client_builder.run
+      expect(tag_receiver).to eq %w{foo bar}
+    end
+
     it "builds a node when the run_list is a string" do
       knife_config[:run_list] = "role[base],role[app]"
       expect(node).to receive(:run_list).with(["role[base]", "role[app]"])
@@ -162,8 +180,8 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
     end
 
     it "builds a node with first_boot_attributes if they're given" do
-      knife_config[:first_boot_attributes] = {:baz => :quux}
-      expect(node).to receive(:normal_attrs=).with({:baz=>:quux})
+      knife_config[:first_boot_attributes] = { :baz => :quux }
+      expect(node).to receive(:normal_attrs=).with({ :baz => :quux })
       expect(node).to receive(:run_list).with([])
       client_builder.run
     end
@@ -174,5 +192,16 @@ describe Chef::Knife::Bootstrap::ClientBuilder do
       expect(node).to receive(:run_list).with([])
       client_builder.run
     end
+
+    it "builds a node with policy_name and policy_group when given" do
+      knife_config[:policy_name] = "my-app"
+      knife_config[:policy_group] = "staging"
+
+      expect(node).to receive(:run_list).with([])
+      expect(node).to receive(:policy_name=).with("my-app")
+      expect(node).to receive(:policy_group=).with("staging")
+
+      client_builder.run
+    end
   end
 end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index f1ca510..e8e75e4 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Ian Meyer (<ianmmeyer at gmail.com>)
-# Copyright:: Copyright (c) 2010 Ian Meyer
+# Copyright:: Copyright 2010-2016, Ian Meyer
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::Bootstrap.load_deps
-require 'net/ssh'
+require "net/ssh"
 
 describe Chef::Knife::Bootstrap do
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
   end
   let(:knife) do
     Chef::Log.logger = Logger.new(StringIO.new)
@@ -51,7 +51,7 @@ describe Chef::Knife::Bootstrap do
   context "with --bootstrap-vault-item" do
     let(:bootstrap_cli_options) { [ "--bootstrap-vault-item", "vault1:item1", "--bootstrap-vault-item", "vault1:item2", "--bootstrap-vault-item", "vault2:item1" ] }
     it "sets the knife config cli option correctly" do
-      expect(knife.config[:bootstrap_vault_item]).to eq({"vault1"=>["item1", "item2"], "vault2"=>["item1"]})
+      expect(knife.config[:bootstrap_vault_item]).to eq({ "vault1" => ["item1", "item2"], "vault2" => ["item1"] })
     end
   end
 
@@ -102,7 +102,7 @@ describe Chef::Knife::Bootstrap do
     context "when :bootstrap_template config is set to a template name" do
       let(:bootstrap_template) { "example" }
 
-      let(:builtin_template_path) { File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/chef/knife/bootstrap/templates', "example.erb"))}
+      let(:builtin_template_path) { File.expand_path(File.join(File.dirname(__FILE__), "../../../lib/chef/knife/bootstrap/templates", "example.erb")) }
 
       let(:chef_config_dir_template_path) { "/knife/chef/config/bootstrap/example.erb" }
 
@@ -209,7 +209,7 @@ describe Chef::Knife::Bootstrap do
   ["-d", "--distro", "-t", "--bootstrap-template", "--template-file"].each do |t|
     context "when #{t} option is given in the command line" do
       it "sets the knife :bootstrap_template config" do
-        knife.parse_options([t,"blahblah"])
+        knife.parse_options([t, "blahblah"])
         knife.merge_configs
         expect(knife.bootstrap_template).to eq("blahblah")
       end
@@ -224,7 +224,7 @@ describe Chef::Knife::Bootstrap do
     end
 
     it "should have role[base] in the run_list" do
-      knife.parse_options(["-r","role[base]"])
+      knife.parse_options(["-r", "role[base]"])
       knife.merge_configs
       expect(knife.render_template).to eq('{"run_list":["role[base]"]}')
     end
@@ -235,12 +235,39 @@ describe Chef::Knife::Bootstrap do
       expect(knife.render_template).to eq('{"run_list":["role[base]","recipe[cupcakes]"]}')
     end
 
-    it "should have foo => {bar => baz} in the first_boot" do
-      knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
-      knife.merge_configs
-      expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}')
-      actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template)
-      expect(actual_hash).to eq(expected_hash)
+    context "with bootstrap_attribute options" do
+      let(:jsonfile) {
+        file = Tempfile.new (["node", ".json"])
+        File.open(file.path, "w") { |f| f.puts '{"foo":{"bar":"baz"}}' }
+        file
+      }
+
+      it "should have foo => {bar => baz} in the first_boot from cli" do
+        knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
+        knife.merge_configs
+        expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}')
+        actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template)
+        expect(actual_hash).to eq(expected_hash)
+      end
+
+      it "should have foo => {bar => baz} in the first_boot from file" do
+        knife.parse_options(["--json-attribute-file", jsonfile.path])
+        knife.merge_configs
+        expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}')
+        actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template)
+        expect(actual_hash).to eq(expected_hash)
+        jsonfile.close
+      end
+
+      context "when --json-attributes and --json-attribute-file were both passed" do
+        it "raises a Chef::Exceptions::BootstrapCommandInputError with the proper error message" do
+          knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
+          knife.parse_options(["--json-attribute-file", jsonfile.path])
+          knife.merge_configs
+          expect { knife.run }.to raise_error(Chef::Exceptions::BootstrapCommandInputError)
+          jsonfile.close
+        end
+      end
     end
   end
 
@@ -250,14 +277,14 @@ describe Chef::Knife::Bootstrap do
     it "should create a hint file when told to" do
       knife.parse_options(["--hint", "openstack"])
       knife.merge_configs
-      expect(knife.render_template).to match /\/etc\/chef\/ohai\/hints\/openstack.json/
+      expect(knife.render_template).to match(/\/etc\/chef\/ohai\/hints\/openstack.json/)
     end
 
     it "should populate a hint file with JSON when given a file to read" do
       allow(::File).to receive(:read).and_return('{ "foo" : "bar" }')
       knife.parse_options(["--hint", "openstack=hints/openstack.json"])
       knife.merge_configs
-      expect(knife.render_template).to match /\{\"foo\":\"bar\"\}/
+      expect(knife.render_template).to match(/\{\"foo\":\"bar\"\}/)
     end
   end
 
@@ -270,7 +297,7 @@ describe Chef::Knife::Bootstrap do
       k
     end
 
-    let(:options){ ["--bootstrap-no-proxy", setting, "-s", "foo"] }
+    let(:options) { ["--bootstrap-no-proxy", setting, "-s", "foo"] }
     let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
     let(:rendered_template) do
       knife.render_template
@@ -312,7 +339,7 @@ describe Chef::Knife::Bootstrap do
       let(:options) { ["--node-ssl-verify-mode", "all"] }
 
       it "raises error" do
-        expect{ rendered_template }.to raise_error
+        expect { rendered_template }.to raise_error
       end
     end
 
@@ -358,7 +385,7 @@ describe Chef::Knife::Bootstrap do
   end
 
   describe "when transferring trusted certificates" do
-    let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), '../../data/trusted_certs')) }
+    let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), "../../data/trusted_certs")) }
 
     let(:rendered_template) do
       knife.merge_configs
@@ -395,6 +422,109 @@ describe Chef::Knife::Bootstrap do
     end
   end
 
+  context "when doing fips things" do
+    let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
+    let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), "../../data/trusted_certs")) }
+
+    before do
+      Chef::Config[:knife][:bootstrap_template] = template_file
+    end
+
+    let(:rendered_template) do
+      knife.render_template
+    end
+
+    context "when knife is in fips mode" do
+      before do
+        Chef::Config[:fips] = true
+      end
+
+      it "renders 'fips true'" do
+        Chef::Config[:fips] = true
+        expect(rendered_template).to match("fips")
+      end
+    end
+
+    context "when knife is not in fips mode" do
+      before do
+        # This is required because the chef-fips pipeline does
+        # has a default value of true for fips
+        Chef::Config[:fips] = false
+      end
+
+      it "does not render anything about fips" do
+        expect(rendered_template).not_to match("fips")
+      end
+    end
+  end
+
+  describe "handling policyfile options" do
+
+    context "when only policy_name is given" do
+
+      let(:bootstrap_cli_options) { %w{ --policy-name my-app-server } }
+
+      it "returns an error stating that policy_name and policy_group must be given together" do
+        expect { knife.validate_options! }.to raise_error(SystemExit)
+        expect(stderr.string).to include("ERROR: --policy-name and --policy-group must be specified together")
+      end
+
+    end
+
+    context "when only policy_group is given" do
+
+      let(:bootstrap_cli_options) { %w{ --policy-group staging } }
+
+      it "returns an error stating that policy_name and policy_group must be given together" do
+        expect { knife.validate_options! }.to raise_error(SystemExit)
+        expect(stderr.string).to include("ERROR: --policy-name and --policy-group must be specified together")
+      end
+
+    end
+
+    context "when both policy_name and policy_group are given, but run list is also given" do
+
+      let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging --run-list cookbook } }
+
+      it "returns an error stating that policyfile and run_list are exclusive" do
+        expect { knife.validate_options! }.to raise_error(SystemExit)
+        expect(stderr.string).to include("ERROR: Policyfile options and --run-list are exclusive")
+      end
+
+    end
+
+    context "when policy_name and policy_group are given with no conflicting options" do
+
+      let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging } }
+
+      it "passes options validation" do
+        expect { knife.validate_options! }.to_not raise_error
+      end
+
+      it "passes them into the bootstrap context" do
+        expect(knife.bootstrap_context.first_boot).to have_key(:policy_name)
+        expect(knife.bootstrap_context.first_boot).to have_key(:policy_group)
+      end
+
+    end
+
+    # https://github.com/chef/chef/issues/4131
+    # Arguably a bug in the plugin: it shouldn't be setting this to nil, but it
+    # worked before, so make it work now.
+    context "when a plugin sets the run list option to nil" do
+
+      before do
+        knife.config[:run_list] = nil
+      end
+
+      it "passes options validation" do
+        expect { knife.validate_options! }.to_not raise_error
+      end
+
+    end
+
+  end
+
   describe "when configuring the underlying knife ssh command" do
     context "from the command line" do
       let(:knife_ssh) do
@@ -405,7 +535,7 @@ describe Chef::Knife::Bootstrap do
         Chef::Config[:knife][:ssh_user] = nil
         Chef::Config[:knife][:ssh_port] = nil
         knife.config[:forward_agent] = true
-        knife.config[:identity_file] = "~/.ssh/me.rsa"
+        knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
         allow(knife).to receive(:render_template).and_return("")
         knife.knife_ssh
       end
@@ -415,15 +545,15 @@ describe Chef::Knife::Bootstrap do
       end
 
       it "configures the ssh user" do
-        expect(knife_ssh.config[:ssh_user]).to eq('rooty')
+        expect(knife_ssh.config[:ssh_user]).to eq("rooty")
       end
 
       it "configures the ssh password" do
-        expect(knife_ssh.config[:ssh_password]).to eq('open_sesame')
+        expect(knife_ssh.config[:ssh_password]).to eq("open_sesame")
       end
 
       it "configures the ssh port" do
-        expect(knife_ssh.config[:ssh_port]).to eq('4001')
+        expect(knife_ssh.config[:ssh_port]).to eq("4001")
       end
 
       it "configures the ssh agent forwarding" do
@@ -431,7 +561,7 @@ describe Chef::Knife::Bootstrap do
       end
 
       it "configures the ssh identity file" do
-        expect(knife_ssh.config[:identity_file]).to eq('~/.ssh/me.rsa')
+        expect(knife_ssh.config[:ssh_identity_file]).to eq("~/.ssh/me.rsa")
       end
     end
 
@@ -443,8 +573,8 @@ describe Chef::Knife::Bootstrap do
 
       it "use_sudo_password contains description and long params for help" do
         expect(knife.options).to have_key(:use_sudo_password) \
-          and expect(knife.options[:use_sudo_password][:description].to_s).not_to eq('')\
-          and expect(knife.options[:use_sudo_password][:long].to_s).not_to eq('')
+          and expect(knife.options[:use_sudo_password][:description].to_s).not_to eq("")\
+          and expect(knife.options[:use_sudo_password][:long].to_s).not_to eq("")
       end
 
       it "uses the password from --ssh-password for sudo when --use-sudo-password is set" do
@@ -466,7 +596,7 @@ describe Chef::Knife::Bootstrap do
         Chef::Config[:knife][:ssh_user] = "curiosity"
         Chef::Config[:knife][:ssh_port] = "2430"
         Chef::Config[:knife][:forward_agent] = true
-        Chef::Config[:knife][:identity_file] = "~/.ssh/you.rsa"
+        Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/you.rsa"
         Chef::Config[:knife][:ssh_gateway] = "towel.blinkenlights.nl"
         Chef::Config[:knife][:host_key_verify] = true
         allow(knife).to receive(:render_template).and_return("")
@@ -476,11 +606,11 @@ describe Chef::Knife::Bootstrap do
       end
 
       it "configures the ssh user" do
-        expect(knife_ssh.config[:ssh_user]).to eq('curiosity')
+        expect(knife_ssh.config[:ssh_user]).to eq("curiosity")
       end
 
       it "configures the ssh port" do
-        expect(knife_ssh.config[:ssh_port]).to eq('2430')
+        expect(knife_ssh.config[:ssh_port]).to eq("2430")
       end
 
       it "configures the ssh agent forwarding" do
@@ -488,11 +618,11 @@ describe Chef::Knife::Bootstrap do
       end
 
       it "configures the ssh identity file" do
-        expect(knife_ssh.config[:identity_file]).to eq('~/.ssh/you.rsa')
+        expect(knife_ssh.config[:ssh_identity_file]).to eq("~/.ssh/you.rsa")
       end
 
       it "configures the ssh gateway" do
-        expect(knife_ssh.config[:ssh_gateway]).to eq('towel.blinkenlights.nl')
+        expect(knife_ssh.config[:ssh_gateway]).to eq("towel.blinkenlights.nl")
       end
 
       it "configures the host key verify mode" do
@@ -503,21 +633,21 @@ describe Chef::Knife::Bootstrap do
     describe "when falling back to password auth when host key auth fails" do
       let(:knife_ssh_with_password_auth) do
         knife.name_args = ["foo.example.com"]
-        knife.config[:ssh_user]      = "rooty"
-        knife.config[:identity_file] = "~/.ssh/me.rsa"
+        knife.config[:ssh_user] = "rooty"
+        knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
         allow(knife).to receive(:render_template).and_return("")
         k = knife.knife_ssh
-        allow(k).to receive(:get_password).and_return('typed_in_password')
+        allow(k).to receive(:get_password).and_return("typed_in_password")
         allow(knife).to receive(:knife_ssh).and_return(k)
         knife.knife_ssh_with_password_auth
       end
 
       it "prompts the user for a password " do
-        expect(knife_ssh_with_password_auth.config[:ssh_password]).to eq('typed_in_password')
+        expect(knife_ssh_with_password_auth.config[:ssh_password]).to eq("typed_in_password")
       end
 
       it "configures knife not to use the identity file that didn't work previously" do
-        expect(knife_ssh_with_password_auth.config[:identity_file]).to be_nil
+        expect(knife_ssh_with_password_auth.config[:ssh_identity_file]).to be_nil
       end
     end
   end
@@ -525,19 +655,21 @@ describe Chef::Knife::Bootstrap do
   it "verifies that a server to bootstrap was given as a command line arg" do
     knife.name_args = nil
     expect { knife.run }.to raise_error(SystemExit)
-    expect(stderr.string).to match /ERROR:.+FQDN or ip/
+    expect(stderr.string).to match(/ERROR:.+FQDN or ip/)
   end
 
   describe "when running the bootstrap" do
     let(:knife_ssh) do
       knife.name_args = ["foo.example.com"]
-      knife.config[:ssh_user]      = "rooty"
-      knife.config[:identity_file] = "~/.ssh/me.rsa"
+      knife.config[:chef_node_name] = "foo.example.com"
+      knife.config[:ssh_user] = "rooty"
+      knife.config[:ssh_identity_file] = "~/.ssh/me.rsa"
       allow(knife).to receive(:render_template).and_return("")
       knife_ssh = knife.knife_ssh
       allow(knife).to receive(:knife_ssh).and_return(knife_ssh)
       knife_ssh
     end
+    let(:client) { Chef::ApiClient.new }
 
     context "when running with a configured and present validation key" do
       before do
@@ -545,7 +677,6 @@ describe Chef::Knife::Bootstrap do
         allow(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
       end
 
-
       it "configures the underlying ssh command and then runs it" do
         expect(knife_ssh).to receive(:run)
         knife.run
@@ -571,7 +702,8 @@ describe Chef::Knife::Bootstrap do
         knife.config[:bootstrap_vault_file] = "/not/our/responsibility/to/check/if/this/exists"
         expect(knife_ssh).to receive(:run)
         expect(knife.client_builder).to receive(:run)
-        expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+        expect(knife.client_builder).to receive(:client).and_return(client)
+        expect(knife.chef_vault_handler).to receive(:run).with(client)
         knife.run
       end
 
@@ -579,7 +711,8 @@ describe Chef::Knife::Bootstrap do
         knife.config[:bootstrap_vault_json] = '{ "vault" => "item" }'
         expect(knife_ssh).to receive(:run)
         expect(knife.client_builder).to receive(:run)
-        expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+        expect(knife.client_builder).to receive(:client).and_return(client)
+        expect(knife.chef_vault_handler).to receive(:run).with(client)
         knife.run
       end
 
@@ -587,9 +720,15 @@ describe Chef::Knife::Bootstrap do
         expect(File).to receive(:exist?).with(File.expand_path(Chef::Config[:validation_key])).and_return(true)
         expect(knife_ssh).to receive(:run)
         expect(knife.client_builder).not_to receive(:run)
-        expect(knife.chef_vault_handler).not_to receive(:run).with(node_name: knife.config[:chef_node_name])
+        expect(knife.chef_vault_handler).not_to receive(:run)
         knife.run
       end
+
+      it "raises an exception if the config[:chef_node_name] is not present" do
+        knife.config[:chef_node_name] = nil
+
+        expect { knife.run }.to raise_error(SystemExit)
+      end
     end
 
     context "when the validation key is not present" do
@@ -601,9 +740,16 @@ describe Chef::Knife::Bootstrap do
       it "creates the client (and possibly adds chef-vault items)" do
         expect(knife_ssh).to receive(:run)
         expect(knife.client_builder).to receive(:run)
-        expect(knife.chef_vault_handler).to receive(:run).with(node_name: knife.config[:chef_node_name])
+        expect(knife.client_builder).to receive(:client).and_return(client)
+        expect(knife.chef_vault_handler).to receive(:run).with(client)
         knife.run
       end
+
+      it "raises an exception if the config[:chef_node_name] is not present" do
+        knife.config[:chef_node_name] = nil
+
+        expect { knife.run }.to raise_error(SystemExit)
+      end
     end
 
     context "when the validation_key is nil" do
@@ -624,5 +770,4 @@ describe Chef::Knife::Bootstrap do
   describe "specifying ssl verification" do
 
   end
-
 end
diff --git a/spec/unit/knife/client_bulk_delete_spec.rb b/spec/unit/knife/client_bulk_delete_spec.rb
index 45bb4dd..096fba6 100644
--- a/spec/unit/knife/client_bulk_delete_spec.rb
+++ b/spec/unit/knife/client_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ClientBulkDelete do
   let(:stdout_io) { StringIO.new }
-  let(:stdout) {stdout_io.string}
+  let(:stdout) { stdout_io.string }
   let(:stderr_io) { StringIO.new }
   let(:stderr) { stderr_io.string }
 
@@ -45,7 +45,7 @@ describe Chef::Knife::ClientBulkDelete do
     clients = Hash.new
 
     nonvalidator_client_names.each do |client_name|
-      client = Chef::ApiClient.new()
+      client = Chef::ApiClientV1.new()
       client.name(client_name)
       allow(client).to receive(:destroy).and_return(true)
       clients[client_name] = client
@@ -59,7 +59,7 @@ describe Chef::Knife::ClientBulkDelete do
     clients = Hash.new
 
     validator_client_names.each do |validator_client_name|
-      validator_client = Chef::ApiClient.new()
+      validator_client = Chef::ApiClientV1.new()
       validator_client.name(validator_client_name)
       allow(validator_client).to receive(:validator).and_return(true)
       allow(validator_client).to receive(:destroy).and_return(true)
@@ -69,13 +69,13 @@ describe Chef::Knife::ClientBulkDelete do
     clients
   }
 
-  let(:client_names) { nonvalidator_client_names + validator_client_names}
+  let(:client_names) { nonvalidator_client_names + validator_client_names }
   let(:clients) {
     nonvalidator_clients.merge(validator_clients)
   }
 
   before(:each) do
-    allow(Chef::ApiClient).to receive(:list).and_return(clients)
+    allow(Chef::ApiClientV1).to receive(:list).and_return(clients)
   end
 
   describe "run" do
@@ -89,7 +89,7 @@ describe Chef::Knife::ClientBulkDelete do
 
     describe "with any clients" do
       it "should get the list of the clients" do
-        expect(Chef::ApiClient).to receive(:list)
+        expect(Chef::ApiClientV1).to receive(:list)
         knife.run
       end
 
@@ -128,7 +128,7 @@ describe Chef::Knife::ClientBulkDelete do
       end
 
       describe "with --delete-validators" do
-        let(:option_args) { {:delete_validators => true} }
+        let(:option_args) { { :delete_validators => true } }
 
         it "should mention that validator clients will be deleted" do
           knife.run
diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb
index 10d386b..bd9d4a1 100644
--- a/spec/unit/knife/client_create_spec.rb
+++ b/spec/unit/knife/client_create_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,100 +16,170 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::ClientCreate.load_deps
 
 describe Chef::Knife::ClientCreate do
   let(:stderr) { StringIO.new }
+  let(:stdout) { StringIO.new }
 
   let(:default_client_hash) do
     {
       "name" => "adam",
       "validator" => false,
-      "admin" => false
+      "admin" => false,
     }
   end
 
   let(:client) do
-    c = double("Chef::ApiClient")
-    allow(c).to receive(:save).and_return({"private_key" => ""})
-    allow(c).to receive(:to_s).and_return("client[adam]")
-    c
+    Chef::ApiClientV1.new
   end
 
   let(:knife) do
     k = Chef::Knife::ClientCreate.new
-    k.name_args = [ "adam" ]
-    k.ui.config[:disable_editing] = true
+    k.name_args = []
+    allow(k).to receive(:client).and_return(client)
+    allow(k).to receive(:edit_data).with(client).and_return(client)
     allow(k.ui).to receive(:stderr).and_return(stderr)
-    allow(k.ui).to receive(:stdout).and_return(stderr)
+    allow(k.ui).to receive(:stdout).and_return(stdout)
     k
   end
 
+  before do
+    allow(client).to receive(:to_s).and_return("client[adam]")
+    allow(knife).to receive(:create_client).and_return(client)
+  end
+
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
   end
 
   describe "run" do
-    it "should create and save the ApiClient" do
-      expect(Chef::ApiClient).to receive(:from_hash).and_return(client)
-      expect(client).to receive(:save)
-      knife.run
+    context "when nothing is passed" do
+      # from spec/support/shared/unit/knife_shared.rb
+      it_should_behave_like "mandatory field missing" do
+        let(:name_args) { [] }
+        let(:fieldname) { "client name" }
+      end
     end
 
-    it "should print a message upon creation" do
-      expect(Chef::ApiClient).to receive(:from_hash).and_return(client)
-      expect(client).to receive(:save)
-      knife.run
-      expect(stderr.string).to match /Created client.*adam/i
-    end
+    context "when clientname is passed" do
+      before do
+        knife.name_args = ["adam"]
+      end
 
-    it "should set the Client name" do
-      expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("name" => "adam")).and_return(client)
-      knife.run
-    end
+      context "when public_key and prevent_keygen are passed" do
+        before do
+          knife.config[:public_key] = "some_key"
+          knife.config[:prevent_keygen] = true
+        end
+
+        it "prints the usage" do
+          expect(knife).to receive(:show_usage)
+          expect { knife.run }.to raise_error(SystemExit)
+        end
+
+        it "prints a relevant error message" do
+          expect { knife.run }.to raise_error(SystemExit)
+          expect(stderr.string).to match /You cannot pass --public-key and --prevent-keygen/
+        end
+      end
 
-    it "by default it is not an admin" do
-      expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => false)).and_return(client)
-      knife.run
-    end
+      it "should create the ApiClient" do
+        expect(knife).to receive(:create_client)
+        knife.run
+      end
 
-    it "by default it is not a validator" do
-      expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => false)).and_return(client)
-      knife.run
-    end
+      it "should print a message upon creation" do
+        expect(knife).to receive(:create_client)
+        knife.run
+        expect(stderr.string).to match /Created client.*adam/i
+      end
 
-    it "should allow you to edit the data" do
-      expect(knife).to receive(:edit_hash).with(default_client_hash).and_return(default_client_hash)
-      allow(Chef::ApiClient).to receive(:from_hash).and_return(client)
-      knife.run
-    end
+      it "should set the Client name" do
+        knife.run
+        expect(client.name).to eq("adam")
+      end
 
-    describe "with -f or --file" do
-      it "should write the private key to a file" do
-        knife.config[:file] = "/tmp/monkeypants"
-        allow_any_instance_of(Chef::ApiClient).to receive(:save).and_return({ 'private_key' => "woot" })
-        filehandle = double("Filehandle")
-        expect(filehandle).to receive(:print).with('woot')
-        expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
+      it "by default it is not an admin" do
         knife.run
+        expect(client.admin).to be_falsey
       end
-    end
 
-    describe "with -a or --admin" do
-      it "should create an admin client" do
-        knife.config[:admin] = true
-        expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("admin" => true)).and_return(client)
+      it "by default it is not a validator" do
         knife.run
+        expect(client.admin).to be_falsey
       end
-    end
 
-    describe "with --validator" do
-      it "should create an validator client" do
-        knife.config[:validator] = true
-        expect(Chef::ApiClient).to receive(:from_hash).with(hash_including("validator" => true)).and_return(client)
+      it "by default it should set create_key to true" do
         knife.run
+        expect(client.create_key).to be_truthy
+      end
+
+      it "should allow you to edit the data" do
+        expect(knife).to receive(:edit_data).with(client).and_return(client)
+        knife.run
+      end
+
+      describe "with -f or --file" do
+        before do
+          client.private_key "woot"
+        end
+
+        it "should write the private key to a file" do
+          knife.config[:file] = "/tmp/monkeypants"
+          filehandle = double("Filehandle")
+          expect(filehandle).to receive(:print).with("woot")
+          expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
+          knife.run
+        end
+      end
+
+      describe "with -a or --admin" do
+        before do
+          knife.config[:admin] = true
+        end
+
+        it "should create an admin client" do
+          knife.run
+          expect(client.admin).to be_truthy
+        end
+      end
+
+      describe "with -p or --public-key" do
+        before do
+          knife.config[:public_key] = "some_key"
+          allow(File).to receive(:read).and_return("some_key")
+          allow(File).to receive(:expand_path)
+        end
+
+        it "sets the public key" do
+          knife.run
+          expect(client.public_key).to eq("some_key")
+        end
+      end
+
+      describe "with -k or --prevent-keygen" do
+        before do
+          knife.config[:prevent_keygen] = true
+        end
+
+        it "does not set create_key" do
+          knife.run
+          expect(client.create_key).to be_falsey
+        end
+      end
+
+      describe "with --validator" do
+        before do
+          knife.config[:validator] = true
+        end
+
+        it "should create an validator client" do
+          knife.run
+          expect(client.validator).to be_truthy
+        end
       end
     end
   end
diff --git a/spec/unit/knife/client_delete_spec.rb b/spec/unit/knife/client_delete_spec.rb
index 0fb5e0b..f1af3c3 100644
--- a/spec/unit/knife/client_delete_spec.rb
+++ b/spec/unit/knife/client_delete_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ClientDelete do
   before(:each) do
@@ -25,16 +25,16 @@ describe Chef::Knife::ClientDelete do
     @knife.config = {
       :delete_validators => false
     }
-    @knife.name_args = [ 'adam' ]
+    @knife.name_args = [ "adam" ]
   end
 
-  describe 'run' do
-    it 'should delete the client' do
-      expect(@knife).to receive(:delete_object).with(Chef::ApiClient, 'adam', 'client')
+  describe "run" do
+    it "should delete the client" do
+      expect(@knife).to receive(:delete_object).with(Chef::ApiClientV1, "adam", "client")
       @knife.run
     end
 
-    it 'should print usage and exit when a client name is not provided' do
+    it "should print usage and exit when a client name is not provided" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
@@ -42,15 +42,15 @@ describe Chef::Knife::ClientDelete do
     end
   end
 
-  describe 'with a validator' do
+  describe "with a validator" do
     before(:each) do
       allow(Chef::Knife::UI).to receive(:confirm).and_return(true)
       allow(@knife).to receive(:confirm).and_return(true)
-      @client = Chef::ApiClient.new
-      expect(Chef::ApiClient).to receive(:load).and_return(@client)
+      @client = Chef::ApiClientV1.new
+      expect(Chef::ApiClientV1).to receive(:load).and_return(@client)
     end
 
-    it 'should delete non-validator client if --delete-validators is not set' do
+    it "should delete non-validator client if --delete-validators is not set" do
       @knife.config[:delete_validators] = false
       expect(@client).to receive(:destroy).and_return(@client)
       expect(@knife).to receive(:msg)
@@ -58,7 +58,7 @@ describe Chef::Knife::ClientDelete do
       @knife.run
     end
 
-    it 'should delete non-validator client if --delete-validators is set' do
+    it "should delete non-validator client if --delete-validators is set" do
       @knife.config[:delete_validators] = true
       expect(@client).to receive(:destroy).and_return(@client)
       expect(@knife).to receive(:msg)
@@ -66,13 +66,13 @@ describe Chef::Knife::ClientDelete do
       @knife.run
     end
 
-    it 'should not delete validator client if --delete-validators is not set' do
+    it "should not delete validator client if --delete-validators is not set" do
       @client.validator(true)
       expect(@knife.ui).to receive(:fatal)
-      expect { @knife.run}.to raise_error(SystemExit)
+      expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should delete validator client if --delete-validators is set' do
+    it "should delete validator client if --delete-validators is set" do
       @knife.config[:delete_validators] = true
       expect(@client).to receive(:destroy).and_return(@client)
       expect(@knife).to receive(:msg)
diff --git a/spec/unit/knife/client_edit_spec.rb b/spec/unit/knife/client_edit_spec.rb
index c040c5e..bdfd7e3 100644
--- a/spec/unit/knife/client_edit_spec.rb
+++ b/spec/unit/knife/client_edit_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,34 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "chef/api_client_v1"
 
 describe Chef::Knife::ClientEdit do
   before(:each) do
     @knife = Chef::Knife::ClientEdit.new
-    @knife.name_args = [ 'adam' ]
+    @knife.name_args = [ "adam" ]
+    @knife.config[:disable_editing] = true
   end
 
-  describe 'run' do
-    it 'should edit the client' do
-      expect(@knife).to receive(:edit_object).with(Chef::ApiClient, 'adam')
+  describe "run" do
+    let(:data) {
+      {
+        "name" => "adam",
+        "validator" => false,
+        "admin" => false,
+        "chef_type" => "client",
+        "create_key" => true,
+      }
+    }
+
+    it "should edit the client" do
+      allow(Chef::ApiClientV1).to receive(:load).with("adam").and_return(data)
+      expect(@knife).to receive(:edit_data).with(data).and_return(data)
       @knife.run
     end
 
-    it 'should print usage and exit when a client name is not provided' do
+    it "should print usage and exit when a client name is not provided" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/client_list_spec.rb b/spec/unit/knife/client_list_spec.rb
index eff01da..d1b379a 100644
--- a/spec/unit/knife/client_list_spec.rb
+++ b/spec/unit/knife/client_list_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ClientList do
   before(:each) do
     @knife = Chef::Knife::ClientList.new
-    @knife.name_args = [ 'adam' ]
+    @knife.name_args = [ "adam" ]
   end
 
-  describe 'run' do
-    it 'should list the clients' do
-      expect(Chef::ApiClient).to receive(:list)
+  describe "run" do
+    it "should list the clients" do
+      expect(Chef::ApiClientV1).to receive(:list)
       expect(@knife).to receive(:format_list_for_display)
       @knife.run
     end
diff --git a/spec/unit/knife/client_reregister_spec.rb b/spec/unit/knife/client_reregister_spec.rb
index f1be4ed..6776caf 100644
--- a/spec/unit/knife/client_reregister_spec.rb
+++ b/spec/unit/knife/client_reregister_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ClientReregister do
   before(:each) do
     @knife = Chef::Knife::ClientReregister.new
-    @knife.name_args = [ 'adam' ]
-    @client_mock = double('client_mock', :private_key => "foo_key")
+    @knife.name_args = [ "adam" ]
+    @client_mock = double("client_mock", :private_key => "foo_key")
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
   end
@@ -32,28 +32,28 @@ describe Chef::Knife::ClientReregister do
       @knife.name_args = []
     end
 
-    it 'should print usage and exit when a client name is not provided' do
+    it "should print usage and exit when a client name is not provided" do
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
       expect { @knife.run }.to raise_error(SystemExit)
     end
   end
 
-  context 'when not configured for file output' do
-    it 'reregisters the client and prints the key' do
-      expect(Chef::ApiClient).to receive(:reregister).with('adam').and_return(@client_mock)
+  context "when not configured for file output" do
+    it "reregisters the client and prints the key" do
+      expect(Chef::ApiClientV1).to receive(:reregister).with("adam").and_return(@client_mock)
       @knife.run
       expect(@stdout.string).to match( /foo_key/ )
     end
   end
 
-  context 'when configured for file output' do
-    it 'should write the private key to a file' do
-      expect(Chef::ApiClient).to receive(:reregister).with('adam').and_return(@client_mock)
+  context "when configured for file output" do
+    it "should write the private key to a file" do
+      expect(Chef::ApiClientV1).to receive(:reregister).with("adam").and_return(@client_mock)
 
-      @knife.config[:file] = '/tmp/monkeypants'
+      @knife.config[:file] = "/tmp/monkeypants"
       filehandle = StringIO.new
-      expect(File).to receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle)
+      expect(File).to receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle)
       @knife.run
       expect(filehandle.string).to eq("foo_key")
     end
diff --git a/spec/unit/knife/client_show_spec.rb b/spec/unit/knife/client_show_spec.rb
index 8404e8d..47b4b6c 100644
--- a/spec/unit/knife/client_show_spec.rb
+++ b/spec/unit/knife/client_show_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,33 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ClientShow do
   before(:each) do
     @knife = Chef::Knife::ClientShow.new
-    @knife.name_args = [ 'adam' ]
-    @client_mock = double('client_mock')
+    @knife.name_args = [ "adam" ]
+    @client_mock = double("client_mock")
   end
 
-  describe 'run' do
-    it 'should list the client' do
-      expect(Chef::ApiClient).to receive(:load).with('adam').and_return(@client_mock)
+  describe "run" do
+    it "should list the client" do
+      expect(Chef::ApiClientV1).to receive(:load).with("adam").and_return(@client_mock)
       expect(@knife).to receive(:format_for_display).with(@client_mock)
       @knife.run
     end
 
-    it 'should pretty print json' do
-      @knife.config[:format] = 'json'
+    it "should pretty print json" do
+      @knife.config[:format] = "json"
       @stdout = StringIO.new
       allow(@knife.ui).to receive(:stdout).and_return(@stdout)
-      fake_client_contents = {"foo"=>"bar", "baz"=>"qux"}
-      expect(Chef::ApiClient).to receive(:load).with('adam').and_return(fake_client_contents)
+      fake_client_contents = { "foo" => "bar", "baz" => "qux" }
+      expect(Chef::ApiClientV1).to receive(:load).with("adam").and_return(fake_client_contents)
       @knife.run
       expect(@stdout.string).to eql("{\n  \"foo\": \"bar\",\n  \"baz\": \"qux\"\n}\n")
     end
 
-    it 'should print usage and exit when a client name is not provided' do
+    it "should print usage and exit when a client name is not provided" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
diff --git a/spec/unit/knife/configure_client_spec.rb b/spec/unit/knife/configure_client_spec.rb
index 363743f..192da86 100644
--- a/spec/unit/knife/configure_client_spec.rb
+++ b/spec/unit/knife/configure_client_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,21 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::ConfigureClient do
   before do
     @knife = Chef::Knife::ConfigureClient.new
-    Chef::Config[:chef_server_url] = 'https://chef.example.com'
-    Chef::Config[:validation_client_name] = 'chef-validator'
-    Chef::Config[:validation_key] = '/etc/chef/validation.pem'
+    Chef::Config[:chef_server_url] = "https://chef.example.com"
+    Chef::Config[:validation_client_name] = "chef-validator"
+    Chef::Config[:validation_key] = "/etc/chef/validation.pem"
 
     @stderr = StringIO.new
     allow(@knife.ui).to receive(:stderr).and_return(@stderr)
   end
 
-  describe 'run' do
-    it 'should print usage and exit when a directory is not provided' do
+  describe "run" do
+    it "should print usage and exit when a directory is not provided" do
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal).with(/must provide the directory/)
       expect {
@@ -38,24 +38,24 @@ describe Chef::Knife::ConfigureClient do
       }.to raise_error SystemExit
     end
 
-    describe 'when specifing a directory' do
+    describe "when specifing a directory" do
       before do
-        @knife.name_args = ['/home/bob/.chef']
+        @knife.name_args = ["/home/bob/.chef"]
         @client_file = StringIO.new
         @validation_file = StringIO.new
-        expect(File).to receive(:open).with('/home/bob/.chef/client.rb', 'w').
-                                   and_yield(@client_file)
-        expect(File).to receive(:open).with('/home/bob/.chef/validation.pem', 'w').
-                                   and_yield(@validation_file)
-        expect(IO).to receive(:read).and_return('foo_bar_baz')
+        expect(File).to receive(:open).with("/home/bob/.chef/client.rb", "w").
+          and_yield(@client_file)
+        expect(File).to receive(:open).with("/home/bob/.chef/validation.pem", "w").
+          and_yield(@validation_file)
+        expect(IO).to receive(:read).and_return("foo_bar_baz")
       end
 
-      it 'should recursively create the directory' do
-        expect(FileUtils).to receive(:mkdir_p).with('/home/bob/.chef')
+      it "should recursively create the directory" do
+        expect(FileUtils).to receive(:mkdir_p).with("/home/bob/.chef")
         @knife.run
       end
 
-      it 'should write out the config file' do
+      it "should write out the config file" do
         allow(FileUtils).to receive(:mkdir_p)
         @knife.run
         expect(@client_file.string).to match /log_level\s+\:info/
@@ -64,13 +64,13 @@ describe Chef::Knife::ConfigureClient do
         expect(@client_file.string).to match /validation_client_name\s+'chef-validator'/
       end
 
-      it 'should write out the validation.pem file' do
+      it "should write out the validation.pem file" do
         allow(FileUtils).to receive(:mkdir_p)
         @knife.run
         expect(@validation_file.string).to match /foo_bar_baz/
       end
 
-      it 'should print information on what is being configured' do
+      it "should print information on what is being configured" do
         allow(FileUtils).to receive(:mkdir_p)
         @knife.run
         expect(@stderr.string).to match /creating client configuration/i
@@ -81,4 +81,3 @@ describe Chef::Knife::ConfigureClient do
   end
 
 end
-
diff --git a/spec/unit/knife/configure_spec.rb b/spec/unit/knife/configure_spec.rb
index e3ea1f0..e96115c 100644
--- a/spec/unit/knife/configure_spec.rb
+++ b/spec/unit/knife/configure_spec.rb
@@ -1,17 +1,17 @@
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::Configure do
   before do
     Chef::Log.logger = Logger.new(StringIO.new)
 
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::Configure.new
-    @rest_client = double("null rest client", :post_rest => { :result => :true })
+    @rest_client = double("null rest client", :post => { :result => :true })
     allow(@knife).to receive(:rest).and_return(@rest_client)
 
     @out = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@out)
-    @knife.config[:config_file] = '/home/you/.chef/knife.rb'
+    @knife.config[:config_file] = "/home/you/.chef/knife.rb"
 
     @in = StringIO.new("\n" * 7)
     allow(@knife.ui).to receive(:stdin).and_return(@in)
@@ -22,7 +22,6 @@ describe Chef::Knife::Configure do
     allow(Ohai::System).to receive(:new).and_return(ohai)
   end
 
-
   let(:fqdn) { "foo.example.org" }
 
   let(:ohai) do
@@ -41,7 +40,6 @@ describe Chef::Knife::Configure do
 
   let(:default_server_url) { "https://#{fqdn}:443" }
 
-
   it "asks the user for the URL of the chef server" do
     @knife.ask_user_for_config
     expect(@out.string).to match(Regexp.escape("Please enter the chef server URL: [#{default_server_url}]"))
@@ -58,11 +56,11 @@ describe Chef::Knife::Configure do
 
   it "should not ask the user for the clientname they want for the new client if -i and --node_name are specified" do
     @knife.config[:initial] = true
-    @knife.config[:node_name] = 'testnode'
+    @knife.config[:node_name] = "testnode"
     allow(Etc).to receive(:getlogin).and_return("a-new-user")
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter a name for the new user"))
-    expect(@knife.new_client_name).to eq('testnode')
+    expect(@knife.new_client_name).to eq("testnode")
   end
 
   it "asks the user for the existing API username or clientname if -i is not specified" do
@@ -76,21 +74,21 @@ describe Chef::Knife::Configure do
     @knife.config[:initial] = true
     @knife.ask_user_for_config
     expect(@out.string).to match(Regexp.escape("Please enter the existing admin name: [admin]"))
-    expect(@knife.admin_client_name).to eq('admin')
+    expect(@knife.admin_client_name).to eq("admin")
   end
 
   it "should not ask the user for the existing admin client's name if -i and --admin-client_name are specified" do
     @knife.config[:initial] = true
-    @knife.config[:admin_client_name] = 'my-webui'
+    @knife.config[:admin_client_name] = "my-webui"
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter the existing admin:"))
-    expect(@knife.admin_client_name).to eq('my-webui')
+    expect(@knife.admin_client_name).to eq("my-webui")
   end
 
   it "should not ask the user for the existing admin client's name if -i is not specified" do
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter the existing admin: [admin]"))
-    expect(@knife.admin_client_name).not_to eq('admin')
+    expect(@knife.admin_client_name).not_to eq("admin")
   end
 
   it "asks the user for the location of the existing admin key if -i is specified" do
@@ -106,13 +104,13 @@ describe Chef::Knife::Configure do
 
   it "should not ask the user for the location of the existing admin key if -i and --admin_client_key are specified" do
     @knife.config[:initial] = true
-    @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem'
+    @knife.config[:admin_client_key] = "/home/you/.chef/my-webui.pem"
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter the location of the existing admin client's private key:"))
     if windows?
       expect(@knife.admin_client_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$}
     else
-      expect(@knife.admin_client_key).to eq('/home/you/.chef/my-webui.pem')
+      expect(@knife.admin_client_key).to eq("/home/you/.chef/my-webui.pem")
     end
   end
 
@@ -129,20 +127,20 @@ describe Chef::Knife::Configure do
   it "asks the user for the location of a chef repo" do
     @knife.ask_user_for_config
     expect(@out.string).to match(Regexp.escape("Please enter the path to a chef repository (or leave blank):"))
-    expect(@knife.chef_repo).to eq('')
+    expect(@knife.chef_repo).to eq("")
   end
 
   it "asks the users for the name of the validation client" do
     @knife.ask_user_for_config
     expect(@out.string).to match(Regexp.escape("Please enter the validation clientname: [chef-validator]"))
-    expect(@knife.validation_client_name).to eq('chef-validator')
+    expect(@knife.validation_client_name).to eq("chef-validator")
   end
 
   it "should not ask the users for the name of the validation client if --validation_client_name is specified" do
-    @knife.config[:validation_client_name] = 'my-validator'
+    @knife.config[:validation_client_name] = "my-validator"
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter the validation clientname:"))
-    expect(@knife.validation_client_name).to eq('my-validator')
+    expect(@knife.validation_client_name).to eq("my-validator")
   end
 
   it "asks the users for the location of the validation key" do
@@ -156,45 +154,45 @@ describe Chef::Knife::Configure do
   end
 
   it "should not ask the users for the location of the validation key if --validation_key is specified" do
-    @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem'
+    @knife.config[:validation_key] = "/home/you/.chef/my-validation.pem"
     @knife.ask_user_for_config
     expect(@out.string).not_to match(Regexp.escape("Please enter the location of the validation key:"))
     if windows?
       expect(@knife.validation_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$}
     else
-      expect(@knife.validation_key).to eq('/home/you/.chef/my-validation.pem')
+      expect(@knife.validation_key).to eq("/home/you/.chef/my-validation.pem")
     end
   end
 
   it "should not ask the user for anything if -i and all other properties are specified" do
     @knife.config[:initial] = true
-    @knife.config[:chef_server_url] = 'http://localhost:5000'
-    @knife.config[:node_name] = 'testnode'
-    @knife.config[:admin_client_name] = 'my-webui'
-    @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem'
-    @knife.config[:validation_client_name] = 'my-validator'
-    @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem'
-    @knife.config[:repository] = ''
-    @knife.config[:client_key] = '/home/you/a-new-user.pem'
-    allow(Etc).to receive(:getlogin).and_return('a-new-user')
+    @knife.config[:chef_server_url] = "http://localhost:5000"
+    @knife.config[:node_name] = "testnode"
+    @knife.config[:admin_client_name] = "my-webui"
+    @knife.config[:admin_client_key] = "/home/you/.chef/my-webui.pem"
+    @knife.config[:validation_client_name] = "my-validator"
+    @knife.config[:validation_key] = "/home/you/.chef/my-validation.pem"
+    @knife.config[:repository] = ""
+    @knife.config[:client_key] = "/home/you/a-new-user.pem"
+    allow(Etc).to receive(:getlogin).and_return("a-new-user")
 
     @knife.ask_user_for_config
     expect(@out.string).to match(/\s*/)
 
-    expect(@knife.new_client_name).to eq('testnode')
-    expect(@knife.chef_server).to eq('http://localhost:5000')
-    expect(@knife.admin_client_name).to eq('my-webui')
+    expect(@knife.new_client_name).to eq("testnode")
+    expect(@knife.chef_server).to eq("http://localhost:5000")
+    expect(@knife.admin_client_name).to eq("my-webui")
     if windows?
       expect(@knife.admin_client_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$}
       expect(@knife.validation_key).to match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$}
       expect(@knife.new_client_key).to match %r{^[A-Za-z]:/home/you/a-new-user\.pem$}
     else
-      expect(@knife.admin_client_key).to eq('/home/you/.chef/my-webui.pem')
-      expect(@knife.validation_key).to eq('/home/you/.chef/my-validation.pem')
-      expect(@knife.new_client_key).to eq('/home/you/a-new-user.pem')
+      expect(@knife.admin_client_key).to eq("/home/you/.chef/my-webui.pem")
+      expect(@knife.validation_key).to eq("/home/you/.chef/my-validation.pem")
+      expect(@knife.new_client_key).to eq("/home/you/a-new-user.pem")
     end
-    expect(@knife.validation_client_name).to eq('my-validator')
-    expect(@knife.chef_repo).to eq('')
+    expect(@knife.validation_client_name).to eq("my-validator")
+    expect(@knife.chef_repo).to eq("")
   end
 
   it "writes the new data to a config file" do
@@ -205,7 +203,7 @@ describe Chef::Knife::Configure do
     expect(FileUtils).to receive(:mkdir_p).with("/home/you/.chef")
     config_file = StringIO.new
     expect(::File).to receive(:open).with("/home/you/.chef/knife.rb", "w").and_yield config_file
-    @knife.config[:repository] = '/home/you/chef-repo'
+    @knife.config[:repository] = "/home/you/chef-repo"
     @knife.run
     expect(config_file.string).to match(/^node_name[\s]+'#{Etc.getlogin}'$/)
     expect(config_file.string).to match(%r{^client_key[\s]+'/home/you/.chef/#{Etc.getlogin}.pem'$})
@@ -220,7 +218,7 @@ describe Chef::Knife::Configure do
     expect(File).to receive(:expand_path).with("/home/you/.chef/a-new-user.pem").and_return("/home/you/.chef/a-new-user.pem")
     expect(File).to receive(:expand_path).with(default_validator_key).and_return(default_validator_key)
     expect(File).to receive(:expand_path).with(default_admin_key).and_return(default_admin_key)
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
 
     user_command = Chef::Knife::UserCreate.new
     expect(user_command).to receive(:run)
diff --git a/spec/unit/knife/cookbook_bulk_delete_spec.rb b/spec/unit/knife/cookbook_bulk_delete_spec.rb
index 98cd06b..62b8c9f 100644
--- a/spec/unit/knife/cookbook_bulk_delete_spec.rb
+++ b/spec/unit/knife/cookbook_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookBulkDelete do
   before(:each) do
     Chef::Log.logger = Logger.new(StringIO.new)
 
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::CookbookBulkDelete.new
-    @knife.config = {:print_after => nil}
+    @knife.config = { :print_after => nil }
     @knife.name_args = ["."]
     @stdout = StringIO.new
     @stderr = StringIO.new
@@ -36,24 +36,22 @@ describe Chef::Knife::CookbookBulkDelete do
       cookbook = Chef::CookbookVersion.new(cookbook_name)
       @cookbooks[cookbook_name] = cookbook
     end
-    @rest = double("Chef::REST")
-    allow(@rest).to receive(:get_rest).and_return(@cookbooks)
-    allow(@rest).to receive(:delete_rest).and_return(true)
+    @rest = double("Chef::ServerAPI")
+    allow(@rest).to receive(:get).and_return(@cookbooks)
+    allow(@rest).to receive(:delete).and_return(true)
     allow(@knife).to receive(:rest).and_return(@rest)
     allow(Chef::CookbookVersion).to receive(:list).and_return(@cookbooks)
 
   end
 
-
-
   describe "when there are several cookbooks on the server" do
     before do
-      @cheezburger = {'cheezburger' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-cheez", "version" => "1.0.0"}]}}
-      allow(@rest).to receive(:get_rest).with('cookbooks/cheezburger').and_return(@cheezburger)
-      @pizza = {'pizza' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-pizza", "version" => "2.0.0"}]}}
-      allow(@rest).to receive(:get_rest).with('cookbooks/pizza').and_return(@pizza)
-      @lasagna = {'lasagna' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-lasagna", "version" => "3.0.0"}]}}
-      allow(@rest).to receive(:get_rest).with('cookbooks/lasagna').and_return(@lasagna)
+      @cheezburger = { "cheezburger" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-cheez", "version" => "1.0.0" }] } }
+      allow(@rest).to receive(:get).with("cookbooks/cheezburger").and_return(@cheezburger)
+      @pizza = { "pizza" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-pizza", "version" => "2.0.0" }] } }
+      allow(@rest).to receive(:get).with("cookbooks/pizza").and_return(@pizza)
+      @lasagna = { "lasagna" => { "url" => "file:///dev/null", "versions" => [{ "url" => "file:///dev/null-lasagna", "version" => "3.0.0" }] } }
+      allow(@rest).to receive(:get).with("cookbooks/lasagna").and_return(@lasagna)
     end
 
     it "should print the cookbooks you are about to delete" do
@@ -68,15 +66,15 @@ describe Chef::Knife::CookbookBulkDelete do
     end
 
     it "should delete each cookbook" do
-      {"cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => '3.0.0'}.each do |cookbook_name, version|
-        expect(@rest).to receive(:delete_rest).with("cookbooks/#{cookbook_name}/#{version}")
+      { "cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => "3.0.0" }.each do |cookbook_name, version|
+        expect(@rest).to receive(:delete).with("cookbooks/#{cookbook_name}/#{version}")
       end
       @knife.run
     end
 
     it "should only delete cookbooks that match the regex" do
       @knife.name_args = ["cheezburger"]
-      expect(@rest).to receive(:delete_rest).with('cookbooks/cheezburger/1.0.0')
+      expect(@rest).to receive(:delete).with("cookbooks/cheezburger/1.0.0")
       @knife.run
     end
   end
diff --git a/spec/unit/knife/cookbook_create_spec.rb b/spec/unit/knife/cookbook_create_spec.rb
index 3354432..a183bef 100644
--- a/spec/unit/knife/cookbook_create_spec.rb
+++ b/spec/unit/knife/cookbook_create_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 describe Chef::Knife::CookbookCreate do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::CookbookCreate.new
     @knife.config = {}
     @knife.name_args = ["foobar"]
@@ -34,7 +34,7 @@ describe Chef::Knife::CookbookCreate do
     # Fixes CHEF-2579
     it "should expand the path of the cookbook directory" do
       expect(File).to receive(:expand_path).with("~/tmp/monkeypants")
-      @knife.config = {:cookbook_path => "~/tmp/monkeypants"}
+      @knife.config = { :cookbook_path => "~/tmp/monkeypants" }
       allow(@knife).to receive(:create_cookbook)
       allow(@knife).to receive(:create_readme)
       allow(@knife).to receive(:create_changelog)
@@ -44,7 +44,7 @@ describe Chef::Knife::CookbookCreate do
 
     it "should create a new cookbook with default values to copyright name, email, readme format and license if those are not supplied" do
       @dir = Dir.tmpdir
-      @knife.config = {:cookbook_path => @dir}
+      @knife.config = { :cookbook_path => @dir }
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "none")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -56,9 +56,9 @@ describe Chef::Knife::CookbookCreate do
       @dir = Dir.tmpdir
       @knife.config = {
         :cookbook_path => @dir,
-        :cookbook_copyright => "Opscode, Inc"
+        :cookbook_copyright => "Opscode, Inc",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -71,9 +71,9 @@ describe Chef::Knife::CookbookCreate do
       @knife.config = {
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
-        :cookbook_email => "nuo at opscode.com"
+        :cookbook_email => "nuo at opscode.com",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -87,9 +87,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => "apachev2"
+        :cookbook_license => "apachev2",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "apachev2")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -103,9 +103,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => false
+        :cookbook_license => false,
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -119,9 +119,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => "false"
+        :cookbook_license => "false",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -135,9 +135,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => "gplv2"
+        :cookbook_license => "gplv2",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv2")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -151,9 +151,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => "gplv3"
+        :cookbook_license => "gplv3",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv3")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -167,9 +167,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_path => @dir,
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
-        :cookbook_license => "mit"
+        :cookbook_license => "mit",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "md")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -184,9 +184,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
         :cookbook_license => "mit",
-        :readme_format => "rdoc"
+        :readme_format => "rdoc",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "rdoc")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -201,9 +201,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
         :cookbook_license => "mit",
-        :readme_format => "mkd"
+        :readme_format => "mkd",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "mkd")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -218,9 +218,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
         :cookbook_license => "mit",
-        :readme_format => "txt"
+        :readme_format => "txt",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "txt")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -235,9 +235,9 @@ describe Chef::Knife::CookbookCreate do
         :cookbook_copyright => "Opscode, Inc",
         :cookbook_email => "nuo at opscode.com",
         :cookbook_license => "mit",
-        :readme_format => "foo"
+        :readme_format => "foo",
       }
-      @knife.name_args=["foobar"]
+      @knife.name_args = ["foobar"]
       expect(@knife).to receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit")
       expect(@knife).to receive(:create_readme).with(@dir, @knife.name_args.first, "foo")
       expect(@knife).to receive(:create_changelog).with(@dir, @knife.name_args.first)
@@ -252,7 +252,7 @@ describe Chef::Knife::CookbookCreate do
 
       it "should throw an argument error" do
         @dir = Dir.tmpdir
-        expect{@knife.run}.to raise_error(ArgumentError)
+        expect { @knife.run }.to raise_error(ArgumentError)
       end
     end
 
diff --git a/spec/unit/knife/cookbook_delete_spec.rb b/spec/unit/knife/cookbook_delete_spec.rb
index 4e75a68..4bca4e0 100644
--- a/spec/unit/knife/cookbook_delete_spec.rb
+++ b/spec/unit/knife/cookbook_delete_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,54 +16,54 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookDelete do
   before(:each) do
     @knife = Chef::Knife::CookbookDelete.new
-    @knife.name_args = ['foobar']
-    @knife.cookbook_name = 'foobar'
+    @knife.name_args = ["foobar"]
+    @knife.cookbook_name = "foobar"
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
     @stderr = StringIO.new
     allow(@knife.ui).to receive(:stderr).and_return(@stderr)
   end
 
-  describe 'run' do
-    it 'should print usage and exit when a cookbook name is not provided' do
+  describe "run" do
+    it "should print usage and exit when a cookbook name is not provided" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    describe 'when specifying a cookbook name' do
-      it 'should delete the cookbook without a specific version' do
+    describe "when specifying a cookbook name" do
+      it "should delete the cookbook without a specific version" do
         expect(@knife).to receive(:delete_without_explicit_version)
         @knife.run
       end
 
-      describe 'and a version' do
-        it 'should delete the specific version of the cookbook' do
-          @knife.name_args << '1.0.0'
+      describe "and a version" do
+        it "should delete the specific version of the cookbook" do
+          @knife.name_args << "1.0.0"
           expect(@knife).to receive(:delete_explicit_version)
           @knife.run
         end
       end
 
-      describe 'with -a or --all' do
-        it 'should delete all versions of the cookbook' do
+      describe "with -a or --all" do
+        it "should delete all versions of the cookbook" do
           @knife.config[:all] = true
           expect(@knife).to receive(:delete_all_versions)
           @knife.run
         end
       end
 
-      describe 'with -p or --purge' do
-        it 'should prompt to purge the files' do
+      describe "with -p or --purge" do
+        it "should prompt to purge the files" do
           @knife.config[:purge] = true
           expect(@knife).to receive(:confirm).
-                 with(/.+Are you sure you want to purge files.+/)
+            with(/.+Are you sure you want to purge files.+/)
           expect(@knife).to receive(:delete_without_explicit_version)
           @knife.run
         end
@@ -71,30 +71,30 @@ describe Chef::Knife::CookbookDelete do
     end
   end
 
-  describe 'delete_explicit_version' do
-    it 'should delete the specific cookbook version' do
-      @knife.cookbook_name = 'foobar'
-      @knife.version = '1.0.0'
+  describe "delete_explicit_version" do
+    it "should delete the specific cookbook version" do
+      @knife.cookbook_name = "foobar"
+      @knife.version = "1.0.0"
       expect(@knife).to receive(:delete_object).with(Chef::CookbookVersion,
-                                                 'foobar version 1.0.0',
-                                                 'cookbook').and_yield()
-      expect(@knife).to receive(:delete_request).with('cookbooks/foobar/1.0.0')
+                                                 "foobar version 1.0.0",
+                                                 "cookbook").and_yield()
+      expect(@knife).to receive(:delete_request).with("cookbooks/foobar/1.0.0")
       @knife.delete_explicit_version
     end
   end
 
-  describe 'delete_all_versions' do
-    it 'should prompt to delete all versions of the cookbook' do
-      @knife.cookbook_name = 'foobar'
-      expect(@knife).to receive(:confirm).with('Do you really want to delete all versions of foobar')
+  describe "delete_all_versions" do
+    it "should prompt to delete all versions of the cookbook" do
+      @knife.cookbook_name = "foobar"
+      expect(@knife).to receive(:confirm).with("Do you really want to delete all versions of foobar")
       expect(@knife).to receive(:delete_all_without_confirmation)
       @knife.delete_all_versions
     end
   end
 
-  describe 'delete_all_without_confirmation' do
-    it 'should delete all versions without confirmation' do
-      versions = ['1.0.0', '1.1.0']
+  describe "delete_all_without_confirmation" do
+    it "should delete all versions without confirmation" do
+      versions = ["1.0.0", "1.1.0"]
       expect(@knife).to receive(:available_versions).and_return(versions)
       versions.each do |v|
         expect(@knife).to receive(:delete_version_without_confirmation).with(v)
@@ -103,132 +103,132 @@ describe Chef::Knife::CookbookDelete do
     end
   end
 
-  describe 'delete_without_explicit_version' do
-    it 'should exit if there are no available versions' do
+  describe "delete_without_explicit_version" do
+    it "should exit if there are no available versions" do
       expect(@knife).to receive(:available_versions).and_return(nil)
       expect { @knife.delete_without_explicit_version }.to raise_error(SystemExit)
     end
 
-    it 'should delete the version if only one is found' do
-      expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0'])
+    it "should delete the version if only one is found" do
+      expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0"])
       expect(@knife).to receive(:delete_explicit_version)
       @knife.delete_without_explicit_version
     end
 
-    it 'should ask which version(s) to delete if multiple are found' do
-      expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0', '1.1.0'])
-      expect(@knife).to receive(:ask_which_versions_to_delete).and_return(['1.0.0', '1.1.0'])
-      expect(@knife).to receive(:delete_versions_without_confirmation).with(['1.0.0', '1.1.0'])
+    it "should ask which version(s) to delete if multiple are found" do
+      expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0", "1.1.0"])
+      expect(@knife).to receive(:ask_which_versions_to_delete).and_return(["1.0.0", "1.1.0"])
+      expect(@knife).to receive(:delete_versions_without_confirmation).with(["1.0.0", "1.1.0"])
       @knife.delete_without_explicit_version
     end
   end
 
-  describe 'available_versions' do
+  describe "available_versions" do
     before(:each) do
-      @rest_mock = double('rest')
+      @rest_mock = double("rest")
       expect(@knife).to receive(:rest).and_return(@rest_mock)
-      @cookbook_data = { 'foobar' => { 'versions' => [{'version' => '1.0.0'},
-                                                      {'version' => '1.1.0'},
-                                                      {'version' => '2.0.0'} ]}
+      @cookbook_data = { "foobar" => { "versions" => [{ "version" => "1.0.0" },
+                                                      { "version" => "1.1.0" },
+                                                      { "version" => "2.0.0" } ] }
       }
     end
 
-    it 'should return the list of versions of the cookbook' do
-      expect(@rest_mock).to receive(:get_rest).with('cookbooks/foobar').and_return(@cookbook_data)
-      expect(@knife.available_versions).to eq(['1.0.0', '1.1.0', '2.0.0'])
+    it "should return the list of versions of the cookbook" do
+      expect(@rest_mock).to receive(:get).with("cookbooks/foobar").and_return(@cookbook_data)
+      expect(@knife.available_versions).to eq(["1.0.0", "1.1.0", "2.0.0"])
     end
 
-    it 'should raise if an error other than HTTP 404 is returned' do
-      exception = Net::HTTPServerException.new('500 Internal Server Error', '500')
-      expect(@rest_mock).to receive(:get_rest).and_raise(exception)
+    it "should raise if an error other than HTTP 404 is returned" do
+      exception = Net::HTTPServerException.new("500 Internal Server Error", "500")
+      expect(@rest_mock).to receive(:get).and_raise(exception)
       expect { @knife.available_versions }.to raise_error Net::HTTPServerException
     end
 
     describe "if the cookbook can't be found" do
       before(:each) do
-        expect(@rest_mock).to receive(:get_rest).
-          and_raise(Net::HTTPServerException.new('404 Not Found', '404'))
+        expect(@rest_mock).to receive(:get).
+          and_raise(Net::HTTPServerException.new("404 Not Found", "404"))
       end
 
-      it 'should print an error' do
+      it "should print an error" do
         @knife.available_versions
         expect(@stderr.string).to match /error.+cannot find a cookbook named foobar/i
       end
 
-      it 'should return nil' do
+      it "should return nil" do
         expect(@knife.available_versions).to eq(nil)
       end
     end
   end
 
-  describe 'ask_which_version_to_delete' do
+  describe "ask_which_version_to_delete" do
     before(:each) do
-      allow(@knife).to receive(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0'])
+      allow(@knife).to receive(:available_versions).and_return(["1.0.0", "1.1.0", "2.0.0"])
     end
 
-    it 'should prompt the user to select a version' do
+    it "should prompt the user to select a version" do
       prompt = /Which version\(s\) do you want to delete\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+4\. All versions.+/m
-      expect(@knife).to receive(:ask_question).with(prompt).and_return('1')
+      expect(@knife).to receive(:ask_question).with(prompt).and_return("1")
       @knife.ask_which_versions_to_delete
     end
 
     it "should print an error and exit if a version wasn't specified" do
-      expect(@knife).to receive(:ask_question).and_return('')
+      expect(@knife).to receive(:ask_question).and_return("")
       expect(@knife.ui).to receive(:error).with(/no versions specified/i)
       expect { @knife.ask_which_versions_to_delete }.to raise_error(SystemExit)
     end
 
-    it 'should print an error if an invalid choice was selected' do
-      expect(@knife).to receive(:ask_question).and_return('100')
+    it "should print an error if an invalid choice was selected" do
+      expect(@knife).to receive(:ask_question).and_return("100")
       expect(@knife.ui).to receive(:error).with(/100 is not a valid choice/i)
       @knife.ask_which_versions_to_delete
     end
 
-    it 'should return the selected versions' do
-      expect(@knife).to receive(:ask_question).and_return('1, 3')
-      expect(@knife.ask_which_versions_to_delete).to eq(['1.0.0', '2.0.0'])
+    it "should return the selected versions" do
+      expect(@knife).to receive(:ask_question).and_return("1, 3")
+      expect(@knife.ask_which_versions_to_delete).to eq(["1.0.0", "2.0.0"])
     end
 
     it "should return all of the versions if 'all' was selected" do
-      expect(@knife).to receive(:ask_question).and_return('4')
+      expect(@knife).to receive(:ask_question).and_return("4")
       expect(@knife.ask_which_versions_to_delete).to eq([:all])
     end
   end
 
-  describe 'delete_version_without_confirmation' do
-    it 'should delete the cookbook version' do
-      expect(@knife).to receive(:delete_request).with('cookbooks/foobar/1.0.0')
-      @knife.delete_version_without_confirmation('1.0.0')
+  describe "delete_version_without_confirmation" do
+    it "should delete the cookbook version" do
+      expect(@knife).to receive(:delete_request).with("cookbooks/foobar/1.0.0")
+      @knife.delete_version_without_confirmation("1.0.0")
     end
 
-    it 'should output that the cookbook was deleted' do
+    it "should output that the cookbook was deleted" do
       allow(@knife).to receive(:delete_request)
-      @knife.delete_version_without_confirmation('1.0.0')
+      @knife.delete_version_without_confirmation("1.0.0")
       expect(@stderr.string).to match /deleted cookbook\[foobar\]\[1.0.0\]/im
     end
 
-    describe 'with --print-after' do
-      it 'should display the cookbook data' do
-        object = ''
+    describe "with --print-after" do
+      it "should display the cookbook data" do
+        object = ""
         @knife.config[:print_after] = true
         allow(@knife).to receive(:delete_request).and_return(object)
         expect(@knife).to receive(:format_for_display).with(object)
-        @knife.delete_version_without_confirmation('1.0.0')
+        @knife.delete_version_without_confirmation("1.0.0")
       end
     end
   end
 
-  describe 'delete_versions_without_confirmation' do
-    it 'should delete each version without confirmation' do
-      versions = ['1.0.0', '1.1.0']
+  describe "delete_versions_without_confirmation" do
+    it "should delete each version without confirmation" do
+      versions = ["1.0.0", "1.1.0"]
       versions.each do |v|
         expect(@knife).to receive(:delete_version_without_confirmation).with(v)
       end
       @knife.delete_versions_without_confirmation(versions)
     end
 
-    describe 'with -a or --all' do
-      it 'should delete all versions without confirmation' do
+    describe "with -a or --all" do
+      it "should delete all versions without confirmation" do
         versions = [:all]
         expect(@knife).to receive(:delete_all_without_confirmation)
         @knife.delete_versions_without_confirmation(versions)
diff --git a/spec/unit/knife/cookbook_download_spec.rb b/spec/unit/knife/cookbook_download_spec.rb
index 7ca1adf..a8248a8 100644
--- a/spec/unit/knife/cookbook_download_spec.rb
+++ b/spec/unit/knife/cookbook_download_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookDownload do
   before(:each) do
@@ -25,66 +25,66 @@ describe Chef::Knife::CookbookDownload do
     allow(@knife.ui).to receive(:stderr).and_return(@stderr)
   end
 
-  describe 'run' do
-    it 'should print usage and exit when a cookbook name is not provided' do
+  describe "run" do
+    it "should print usage and exit when a cookbook name is not provided" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal).with(/must specify a cookbook name/)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should exit with a fatal error when there is no cookbook on the server' do
-      @knife.name_args = ['foobar', nil]
+    it "should exit with a fatal error when there is no cookbook on the server" do
+      @knife.name_args = ["foobar", nil]
       expect(@knife).to receive(:determine_version).and_return(nil)
-      expect(@knife.ui).to receive(:fatal).with('No such cookbook found')
+      expect(@knife.ui).to receive(:fatal).with("No such cookbook found")
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    describe 'with a cookbook name' do
+    describe "with a cookbook name" do
       before(:each) do
-        @knife.name_args = ['foobar']
-        @knife.config[:download_directory] = '/var/tmp/chef'
-        @rest_mock = double('rest')
+        @knife.name_args = ["foobar"]
+        @knife.config[:download_directory] = "/var/tmp/chef"
+        @rest_mock = double("rest")
         allow(@knife).to receive(:rest).and_return(@rest_mock)
 
         @manifest_data = {
           :recipes => [
-            {'path' => 'recipes/foo.rb',
-             'url' => 'http://example.org/files/foo.rb'},
-            {'path' => 'recipes/bar.rb',
-             'url' => 'http://example.org/files/bar.rb'}
+            { "path" => "recipes/foo.rb",
+              "url" => "http://example.org/files/foo.rb" },
+            { "path" => "recipes/bar.rb",
+              "url" => "http://example.org/files/bar.rb" },
           ],
           :templates => [
-            {'path' => 'templates/default/foo.erb',
-             'url' => 'http://example.org/files/foo.erb'},
-            {'path' => 'templates/default/bar.erb',
-             'url' => 'http://example.org/files/bar.erb'}
+            { "path" => "templates/default/foo.erb",
+              "url" => "http://example.org/files/foo.erb" },
+            { "path" => "templates/default/bar.erb",
+              "url" => "http://example.org/files/bar.erb" },
           ],
           :attributes => [
-            {'path' => 'attributes/default.rb',
-             'url' => 'http://example.org/files/default.rb'}
-          ]
+            { "path" => "attributes/default.rb",
+              "url" => "http://example.org/files/default.rb" },
+          ],
         }
 
-        @cookbook_mock = double('cookbook')
-        allow(@cookbook_mock).to receive(:version).and_return('1.0.0')
+        @cookbook_mock = double("cookbook")
+        allow(@cookbook_mock).to receive(:version).and_return("1.0.0")
         allow(@cookbook_mock).to receive(:manifest).and_return(@manifest_data)
-        expect(@rest_mock).to receive(:get_rest).with('cookbooks/foobar/1.0.0').
-                                             and_return(@cookbook_mock)
+        expect(Chef::CookbookVersion).to receive(:load).with("foobar", "1.0.0").
+          and_return(@cookbook_mock)
       end
 
-      it 'should determine which version if one was not explicitly specified'do
+      it "should determine which version if one was not explicitly specified"do
         allow(@cookbook_mock).to receive(:manifest).and_return({})
-        expect(@knife).to receive(:determine_version).and_return('1.0.0')
-        expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false)
+        expect(@knife).to receive(:determine_version).and_return("1.0.0")
+        expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(false)
         allow(Chef::CookbookVersion).to receive(:COOKBOOK_SEGEMENTS).and_return([])
         @knife.run
       end
 
-      describe 'and a version' do
+      describe "and a version" do
         before(:each) do
-          @knife.name_args << '1.0.0'
-          @files = @manifest_data.values.map { |v| v.map { |i| i['path'] } }.flatten.uniq
+          @knife.name_args << "1.0.0"
+          @files = @manifest_data.values.map { |v| v.map { |i| i["path"] } }.flatten.uniq
           @files_mocks = {}
           @files.map { |f| File.basename(f) }.flatten.uniq.each do |f|
             @files_mocks[f] = double("#{f}_mock")
@@ -92,46 +92,45 @@ describe Chef::Knife::CookbookDownload do
           end
         end
 
-        it 'should print an error and exit if the cookbook download directory already exists' do
-          expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true)
+        it "should print an error and exit if the cookbook download directory already exists" do
+          expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(true)
           expect(@knife.ui).to receive(:fatal).with(/\/var\/tmp\/chef\/foobar-1\.0\.0 exists/i)
           expect { @knife.run }.to raise_error(SystemExit)
         end
 
-        describe 'when downloading the cookbook' do
+        describe "when downloading the cookbook" do
           before(:each) do
             @files.map { |f| File.dirname(f) }.flatten.uniq.each do |dir|
               expect(FileUtils).to receive(:mkdir_p).with("/var/tmp/chef/foobar-1.0.0/#{dir}").
-              at_least(:once)
+                at_least(:once)
             end
 
             @files_mocks.each_pair do |file, mock|
-              expect(@rest_mock).to receive(:get_rest).with("http://example.org/files/#{file}", true).
-              and_return(mock)
+              expect(@rest_mock).to receive(:streaming_request).with("http://example.org/files/#{file}").
+                and_return(mock)
             end
 
-            expect(@rest_mock).to receive(:sign_on_redirect=).with(false).at_least(:once)
             @files.each do |f|
               expect(FileUtils).to receive(:mv).
-                        with("/var/tmp/#{File.basename(f)}", "/var/tmp/chef/foobar-1.0.0/#{f}")
+                with("/var/tmp/#{File.basename(f)}", "/var/tmp/chef/foobar-1.0.0/#{f}")
             end
           end
 
           it "should download the cookbook when the cookbook download directory doesn't exist" do
-            expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false)
+            expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(false)
             @knife.run
-            ['attributes', 'recipes', 'templates'].each do |segment|
+            ["attributes", "recipes", "templates"].each do |segment|
               expect(@stderr.string).to match /downloading #{segment}/im
             end
             expect(@stderr.string).to match /downloading foobar cookbook version 1\.0\.0/im
             expect(@stderr.string).to match /cookbook downloaded to \/var\/tmp\/chef\/foobar-1\.0\.0/im
           end
 
-          describe 'with -f or --force' do
-            it 'should remove the existing the cookbook download directory if it exists' do
+          describe "with -f or --force" do
+            it "should remove the existing the cookbook download directory if it exists" do
               @knife.config[:force] = true
-              expect(File).to receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true)
-              expect(FileUtils).to receive(:rm_rf).with('/var/tmp/chef/foobar-1.0.0')
+              expect(File).to receive(:exists?).with("/var/tmp/chef/foobar-1.0.0").and_return(true)
+              expect(FileUtils).to receive(:rm_rf).with("/var/tmp/chef/foobar-1.0.0")
               @knife.run
             end
           end
@@ -142,94 +141,94 @@ describe Chef::Knife::CookbookDownload do
 
   end
 
-  describe 'determine_version' do
+  describe "determine_version" do
 
-    it 'should return nil if there are no versions' do
+    it "should return nil if there are no versions" do
       expect(@knife).to receive(:available_versions).and_return(nil)
       expect(@knife.determine_version).to eq(nil)
       expect(@knife.version).to eq(nil)
     end
 
-    it 'should return and set the version if there is only one version' do
-      expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0'])
-      expect(@knife.determine_version).to eq('1.0.0')
-      expect(@knife.version).to eq('1.0.0')
+    it "should return and set the version if there is only one version" do
+      expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0"])
+      expect(@knife.determine_version).to eq("1.0.0")
+      expect(@knife.version).to eq("1.0.0")
     end
 
-    it 'should ask which version to download and return it if there is more than one' do
-      expect(@knife).to receive(:available_versions).at_least(:once).and_return(['1.0.0', '2.0.0'])
-      expect(@knife).to receive(:ask_which_version).and_return('1.0.0')
-      expect(@knife.determine_version).to eq('1.0.0')
+    it "should ask which version to download and return it if there is more than one" do
+      expect(@knife).to receive(:available_versions).at_least(:once).and_return(["1.0.0", "2.0.0"])
+      expect(@knife).to receive(:ask_which_version).and_return("1.0.0")
+      expect(@knife.determine_version).to eq("1.0.0")
     end
 
-    describe 'with -N or --latest' do
-      it 'should return and set the version to the latest version' do
+    describe "with -N or --latest" do
+      it "should return and set the version to the latest version" do
         @knife.config[:latest] = true
         expect(@knife).to receive(:available_versions).at_least(:once).
-                                                   and_return(['1.0.0', '1.1.0', '2.0.0'])
+          and_return(["1.0.0", "1.1.0", "2.0.0"])
         @knife.determine_version
-        expect(@knife.version.to_s).to eq('2.0.0')
+        expect(@knife.version.to_s).to eq("2.0.0")
       end
     end
   end
 
-  describe 'available_versions' do
+  describe "available_versions" do
     before(:each) do
-      @knife.cookbook_name = 'foobar'
+      @knife.cookbook_name = "foobar"
     end
 
-    it 'should return nil if there are no versions' do
+    it "should return nil if there are no versions" do
       expect(Chef::CookbookVersion).to receive(:available_versions).
-                            with('foobar').
-                            and_return(nil)
+        with("foobar").
+        and_return(nil)
       expect(@knife.available_versions).to eq(nil)
     end
 
-    it 'should return the available versions' do
+    it "should return the available versions" do
       expect(Chef::CookbookVersion).to receive(:available_versions).
-                            with('foobar').
-                            and_return(['1.1.0', '2.0.0', '1.0.0'])
-      expect(@knife.available_versions).to eq([Chef::Version.new('1.0.0'),
-                                           Chef::Version.new('1.1.0'),
-                                           Chef::Version.new('2.0.0')])
+        with("foobar").
+        and_return(["1.1.0", "2.0.0", "1.0.0"])
+      expect(@knife.available_versions).to eq([Chef::Version.new("1.0.0"),
+                                           Chef::Version.new("1.1.0"),
+                                           Chef::Version.new("2.0.0")])
     end
 
-    it 'should avoid multiple API calls to the server' do
+    it "should avoid multiple API calls to the server" do
       expect(Chef::CookbookVersion).to receive(:available_versions).
-                            once.
-                            with('foobar').
-                            and_return(['1.1.0', '2.0.0', '1.0.0'])
+        once.
+        with("foobar").
+        and_return(["1.1.0", "2.0.0", "1.0.0"])
       @knife.available_versions
       @knife.available_versions
     end
   end
 
-  describe 'ask_which_version' do
+  describe "ask_which_version" do
     before(:each) do
-      @knife.cookbook_name = 'foobar'
-      allow(@knife).to receive(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0'])
+      @knife.cookbook_name = "foobar"
+      allow(@knife).to receive(:available_versions).and_return(["1.0.0", "1.1.0", "2.0.0"])
     end
 
-    it 'should prompt the user to select a version' do
+    it "should prompt the user to select a version" do
       prompt = /Which version do you want to download\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+/m
-      expect(@knife).to receive(:ask_question).with(prompt).and_return('1')
+      expect(@knife).to receive(:ask_question).with(prompt).and_return("1")
       @knife.ask_which_version
     end
 
     it "should set the version to the user's selection" do
-      expect(@knife).to receive(:ask_question).and_return('1')
+      expect(@knife).to receive(:ask_question).and_return("1")
       @knife.ask_which_version
-      expect(@knife.version).to eq('1.0.0')
+      expect(@knife.version).to eq("1.0.0")
     end
 
     it "should print an error and exit if a version wasn't specified" do
-      expect(@knife).to receive(:ask_question).and_return('')
+      expect(@knife).to receive(:ask_question).and_return("")
       expect(@knife.ui).to receive(:error).with(/is not a valid value/i)
       expect { @knife.ask_which_version }.to raise_error(SystemExit)
     end
 
-    it 'should print an error if an invalid choice was selected' do
-      expect(@knife).to receive(:ask_question).and_return('100')
+    it "should print an error if an invalid choice was selected" do
+      expect(@knife).to receive(:ask_question).and_return("100")
       expect(@knife.ui).to receive(:error).with(/'100' is not a valid value/i)
       expect { @knife.ask_which_version }.to raise_error(SystemExit)
     end
diff --git a/spec/unit/knife/cookbook_list_spec.rb b/spec/unit/knife/cookbook_list_spec.rb
index 559f700..668f9af 100644
--- a/spec/unit/knife/cookbook_list_spec.rb
+++ b/spec/unit/knife/cookbook_list_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,47 +16,47 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookList do
   before do
     @knife = Chef::Knife::CookbookList.new
-    @rest_mock = double('rest')
+    @rest_mock = double("rest")
     allow(@knife).to receive(:rest).and_return(@rest_mock)
-    @cookbook_names = ['apache2', 'mysql']
-    @base_url = 'https://server.example.com/cookbooks'
+    @cookbook_names = ["apache2", "mysql"]
+    @base_url = "https://server.example.com/cookbooks"
     @cookbook_data = {}
     @cookbook_names.each do |item|
-      @cookbook_data[item] = {'url' => "#{@base_url}/#{item}",
-                              'versions' => [{'version' => '1.0.1',
-                                              'url' => "#{@base_url}/#{item}/1.0.1"}]}
+      @cookbook_data[item] = { "url" => "#{@base_url}/#{item}",
+                               "versions" => [{ "version" => "1.0.1",
+                                                "url" => "#{@base_url}/#{item}/1.0.1" }] }
     end
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
   end
 
-  describe 'run' do
-    it 'should display the latest version of the cookbooks' do
-      expect(@rest_mock).to receive(:get_rest).with('/cookbooks?num_versions=1').
-                                           and_return(@cookbook_data)
+  describe "run" do
+    it "should display the latest version of the cookbooks" do
+      expect(@rest_mock).to receive(:get).with("/cookbooks?num_versions=1").
+        and_return(@cookbook_data)
       @knife.run
       @cookbook_names.each do |item|
         expect(@stdout.string).to match /#{item}\s+1\.0\.1/
       end
     end
 
-    it 'should query cookbooks for the configured environment' do
-      @knife.config[:environment] = 'production'
-      expect(@rest_mock).to receive(:get_rest).
-                 with('/environments/production/cookbooks?num_versions=1').
-                 and_return(@cookbook_data)
+    it "should query cookbooks for the configured environment" do
+      @knife.config[:environment] = "production"
+      expect(@rest_mock).to receive(:get).
+        with("/environments/production/cookbooks?num_versions=1").
+        and_return(@cookbook_data)
       @knife.run
     end
 
-    describe 'with -w or --with-uri' do
-      it 'should display the cookbook uris' do
+    describe "with -w or --with-uri" do
+      it "should display the cookbook uris" do
         @knife.config[:with_uri] = true
-        allow(@rest_mock).to receive(:get_rest).and_return(@cookbook_data)
+        allow(@rest_mock).to receive(:get).and_return(@cookbook_data)
         @knife.run
         @cookbook_names.each do |item|
           pattern = /#{Regexp.escape(@cookbook_data[item]['versions'].first['url'])}/
@@ -65,18 +65,18 @@ describe Chef::Knife::CookbookList do
       end
     end
 
-    describe 'with -a or --all' do
+    describe "with -a or --all" do
       before do
         @cookbook_names.each do |item|
-          @cookbook_data[item]['versions'] << {'version' => '1.0.0',
-                                               'url' => "#{@base_url}/#{item}/1.0.0"}
+          @cookbook_data[item]["versions"] << { "version" => "1.0.0",
+                                                "url" => "#{@base_url}/#{item}/1.0.0" }
         end
       end
 
-      it 'should display all versions of the cookbooks' do
+      it "should display all versions of the cookbooks" do
         @knife.config[:all_versions] = true
-        expect(@rest_mock).to receive(:get_rest).with('/cookbooks?num_versions=all').
-                                             and_return(@cookbook_data)
+        expect(@rest_mock).to receive(:get).with("/cookbooks?num_versions=all").
+          and_return(@cookbook_data)
         @knife.run
         @cookbook_names.each do |item|
           expect(@stdout.string).to match /#{item}\s+1\.0\.1\s+1\.0\.0/
diff --git a/spec/unit/knife/cookbook_metadata_from_file_spec.rb b/spec/unit/knife/cookbook_metadata_from_file_spec.rb
index 456e378..274eb5e 100644
--- a/spec/unit/knife/cookbook_metadata_from_file_spec.rb
+++ b/spec/unit/knife/cookbook_metadata_from_file_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,11 +18,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookMetadataFromFile do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @src = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.rb"))
     @tgt = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.json"))
     @knife = Chef::Knife::CookbookMetadataFromFile.new
diff --git a/spec/unit/knife/cookbook_metadata_spec.rb b/spec/unit/knife/cookbook_metadata_spec.rb
index 861d85f..0e3fccf 100644
--- a/spec/unit/knife/cookbook_metadata_spec.rb
+++ b/spec/unit/knife/cookbook_metadata_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2011 Thomas Bishop
+# Copyright:: Copyright 2011-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookMetadata do
   before(:each) do
     @knife = Chef::Knife::CookbookMetadata.new
-    @knife.name_args = ['foobar']
+    @knife.name_args = ["foobar"]
     @cookbook_dir = Dir.mktmpdir
     @json_data = '{ "version": "1.0.0" }'
     @stdout = StringIO.new
@@ -30,50 +30,50 @@ describe Chef::Knife::CookbookMetadata do
     allow(@knife.ui).to receive(:stderr).and_return(@stderr)
   end
 
-  describe 'run' do
-    it 'should print an error and exit if a cookbook name was not provided' do
+  describe "run" do
+    it "should print an error and exit if a cookbook name was not provided" do
       @knife.name_args = []
       expect(@knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should print an error and exit if an empty cookbook name was provided' do
-      @knife.name_args = ['']
+    it "should print an error and exit if an empty cookbook name was provided" do
+      @knife.name_args = [""]
       expect(@knife.ui).to receive(:error).with(/you must specify the cookbook.+use the --all/i)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should generate the metadata for the cookbook' do
-      expect(@knife).to receive(:generate_metadata).with('foobar')
+    it "should generate the metadata for the cookbook" do
+      expect(@knife).to receive(:generate_metadata).with("foobar")
       @knife.run
     end
 
-    describe 'with -a or --all' do
+    describe "with -a or --all" do
       before(:each) do
         @knife.config[:all] = true
-        @foo = Chef::CookbookVersion.new('foo', '/tmp/blah')
-        @foo.version = '1.0.0'
-        @bar = Chef::CookbookVersion.new('bar', '/tmp/blah')
-        @bar.version = '2.0.0'
+        @foo = Chef::CookbookVersion.new("foo", "/tmp/blah")
+        @foo.version = "1.0.0"
+        @bar = Chef::CookbookVersion.new("bar", "/tmp/blah")
+        @bar.version = "2.0.0"
         @cookbook_loader = {
           "foo" => @foo,
-          "bar" => @bar
+          "bar" => @bar,
         }
         expect(@cookbook_loader).to receive(:load_cookbooks).and_return(@cookbook_loader)
-        expect(@knife).to receive(:generate_metadata).with('foo')
-        expect(@knife).to receive(:generate_metadata).with('bar')
+        expect(@knife).to receive(:generate_metadata).with("foo")
+        expect(@knife).to receive(:generate_metadata).with("bar")
       end
 
-      it 'should generate the metadata for each cookbook' do
+      it "should generate the metadata for each cookbook" do
         Chef::Config[:cookbook_path] = @cookbook_dir
         expect(Chef::CookbookLoader).to receive(:new).with(@cookbook_dir).and_return(@cookbook_loader)
         @knife.run
       end
 
-      describe 'and with -o or --cookbook-path' do
-        it 'should look in the provided path and generate cookbook metadata' do
-          @knife.config[:cookbook_path] = '/opt/chef/cookbooks'
-          expect(Chef::CookbookLoader).to receive(:new).with('/opt/chef/cookbooks').and_return(@cookbook_loader)
+      describe "and with -o or --cookbook-path" do
+        it "should look in the provided path and generate cookbook metadata" do
+          @knife.config[:cookbook_path] = "/opt/chef/cookbooks"
+          expect(Chef::CookbookLoader).to receive(:new).with("/opt/chef/cookbooks").and_return(@cookbook_loader)
           @knife.run
         end
       end
@@ -81,55 +81,55 @@ describe Chef::Knife::CookbookMetadata do
 
   end
 
-  describe 'generate_metadata' do
+  describe "generate_metadata" do
     before(:each) do
       @knife.config[:cookbook_path] = @cookbook_dir
       allow(File).to receive(:expand_path).with("#{@cookbook_dir}/foobar/metadata.rb").
-                                    and_return("#{@cookbook_dir}/foobar/metadata.rb")
+        and_return("#{@cookbook_dir}/foobar/metadata.rb")
     end
 
-    it 'should generate the metadata from metadata.rb if it exists' do
+    it "should generate the metadata from metadata.rb if it exists" do
       expect(File).to receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb").
-                                    and_return(true)
-      expect(@knife).to receive(:generate_metadata_from_file).with('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
+        and_return(true)
+      expect(@knife).to receive(:generate_metadata_from_file).with("foobar", "#{@cookbook_dir}/foobar/metadata.rb")
       @knife.run
     end
 
-    it 'should validate the metadata json if metadata.rb does not exist' do
+    it "should validate the metadata json if metadata.rb does not exist" do
       expect(File).to receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb").
-                                    and_return(false)
-      expect(@knife).to receive(:validate_metadata_json).with(@cookbook_dir, 'foobar')
+        and_return(false)
+      expect(@knife).to receive(:validate_metadata_json).with(@cookbook_dir, "foobar")
       @knife.run
     end
   end
 
-  describe 'generate_metadata_from_file' do
+  describe "generate_metadata_from_file" do
     before(:each) do
-      @metadata_mock = double('metadata')
-      @json_file_mock = double('json_file')
+      @metadata_mock = double("metadata")
+      @json_file_mock = double("json_file")
     end
 
-    it 'should generate the metatdata json from metatdata.rb' do
+    it "should generate the metatdata json from metatdata.rb" do
       allow(Chef::Cookbook::Metadata).to receive(:new).and_return(@metadata_mock)
-      expect(@metadata_mock).to receive(:name).with('foobar')
+      expect(@metadata_mock).to receive(:name).with("foobar")
       expect(@metadata_mock).to receive(:from_file).with("#{@cookbook_dir}/foobar/metadata.rb")
-      expect(File).to receive(:open).with("#{@cookbook_dir}/foobar/metadata.json", 'w').
-                                 and_yield(@json_file_mock)
+      expect(File).to receive(:open).with("#{@cookbook_dir}/foobar/metadata.json", "w").
+        and_yield(@json_file_mock)
       expect(@json_file_mock).to receive(:write).with(@json_data)
       expect(Chef::JSONCompat).to receive(:to_json_pretty).with(@metadata_mock).
-                                                       and_return(@json_data)
-      @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
+        and_return(@json_data)
+      @knife.generate_metadata_from_file("foobar", "#{@cookbook_dir}/foobar/metadata.rb")
       expect(@stderr.string).to match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im
     end
 
-    { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency',
-      Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint'
+    { Chef::Exceptions::ObsoleteDependencySyntax => "obsolote dependency",
+      Chef::Exceptions::InvalidVersionConstraint => "invalid version constraint",
     }.each_pair do |klass, description|
       it "should print an error and exit when an #{description} syntax exception is encountered" do
         exception = klass.new("#{description} blah")
         allow(Chef::Cookbook::Metadata).to receive(:new).and_raise(exception)
         expect {
-          @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb")
+          @knife.generate_metadata_from_file("foobar", "#{@cookbook_dir}/foobar/metadata.rb")
         }.to raise_error(SystemExit)
         expect(@stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
         expect(@stderr.string).to match /in #{@cookbook_dir}\/foobar\/metadata\.rb/im
@@ -138,36 +138,36 @@ describe Chef::Knife::CookbookMetadata do
     end
   end
 
-  describe 'validate_metadata_json' do
-    it 'should validate the metadata json' do
+  describe "validate_metadata_json" do
+    it "should validate the metadata json" do
       expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
-                                   and_return(true)
+        and_return(true)
       expect(IO).to receive(:read).with("#{@cookbook_dir}/foobar/metadata.json").
-                               and_return(@json_data)
+        and_return(@json_data)
       expect(Chef::Cookbook::Metadata).to receive(:validate_json).with(@json_data)
-      @knife.validate_metadata_json(@cookbook_dir, 'foobar')
+      @knife.validate_metadata_json(@cookbook_dir, "foobar")
     end
 
-    it 'should not try to validate the metadata json if the file does not exist' do
+    it "should not try to validate the metadata json if the file does not exist" do
       expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
-                                   and_return(false)
+        and_return(false)
       expect(IO).not_to receive(:read)
       expect(Chef::Cookbook::Metadata).not_to receive(:validate_json)
-      @knife.validate_metadata_json(@cookbook_dir, 'foobar')
+      @knife.validate_metadata_json(@cookbook_dir, "foobar")
     end
 
-    { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency',
-      Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint'
+    { Chef::Exceptions::ObsoleteDependencySyntax => "obsolote dependency",
+      Chef::Exceptions::InvalidVersionConstraint => "invalid version constraint",
     }.each_pair do |klass, description|
       it "should print an error and exit when an #{description} syntax exception is encountered" do
         expect(File).to receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json").
-                                     and_return(true)
+          and_return(true)
         expect(IO).to receive(:read).with("#{@cookbook_dir}/foobar/metadata.json").
-                                 and_return(@json_data)
+          and_return(@json_data)
         exception = klass.new("#{description} blah")
         allow(Chef::Cookbook::Metadata).to receive(:validate_json).and_raise(exception)
         expect {
-          @knife.validate_metadata_json(@cookbook_dir, 'foobar')
+          @knife.validate_metadata_json(@cookbook_dir, "foobar")
         }.to raise_error(SystemExit)
         expect(@stderr.string).to match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im
         expect(@stderr.string).to match /in #{@cookbook_dir}\/foobar\/metadata\.json/im
diff --git a/spec/unit/knife/cookbook_show_spec.rb b/spec/unit/knife/cookbook_show_spec.rb
index bf480e3..0183577 100644
--- a/spec/unit/knife/cookbook_show_spec.rb
+++ b/spec/unit/knife/cookbook_show_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, eersion 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 #
 
 # rename to cookbook not coookbook
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookShow do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::CookbookShow.new
-    @knife.config = { }
+    @knife.config = {}
     @knife.name_args = [ "cookbook_name" ]
-    @rest = double(Chef::REST)
+    @rest = double(Chef::ServerAPI)
     allow(@knife).to receive(:rest).and_return(@rest)
     allow(@knife).to receive(:pretty_print).and_return(true)
     allow(@knife).to receive(:output).and_return(true)
@@ -33,7 +33,7 @@ describe Chef::Knife::CookbookShow do
 
   describe "run" do
     describe "with 0 arguments: help" do
-      it 'should should print usage and exit when given no arguments' do
+      it "should should print usage and exit when given no arguments" do
         @knife.name_args = []
         expect(@knife).to receive(:show_usage)
         expect(@knife.ui).to receive(:fatal)
@@ -49,21 +49,21 @@ describe Chef::Knife::CookbookShow do
             "versions" => [
               { "version" => "0.10.0", "url" => "http://url/cookbooks/cookbook_name/0.10.0" },
               { "version" => "0.9.0", "url" => "http://url/cookbookx/cookbook_name/0.9.0" },
-              { "version" => "0.8.0", "url" => "http://url/cookbooks/cookbook_name/0.8.0" }
-            ]
+              { "version" => "0.8.0", "url" => "http://url/cookbooks/cookbook_name/0.8.0" },
+            ],
           }
         }
       end
 
       it "should show the raw cookbook data" do
-        expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name").and_return(@response)
+        expect(@rest).to receive(:get).with("cookbooks/cookbook_name").and_return(@response)
         expect(@knife).to receive(:format_cookbook_list_for_display).with(@response)
         @knife.run
       end
 
       it "should respect the user-supplied environment" do
         @knife.config[:environment] = "foo"
-        expect(@rest).to receive(:get_rest).with("environments/foo/cookbooks/cookbook_name").and_return(@response)
+        expect(@rest).to receive(:get).with("environments/foo/cookbooks/cookbook_name").and_return(@response)
         expect(@knife).to receive(:format_cookbook_list_for_display).with(@response)
         @knife.run
       end
@@ -72,11 +72,11 @@ describe Chef::Knife::CookbookShow do
     describe "with 2 arguments: name and version" do
       before(:each) do
         @knife.name_args << "0.1.0"
-        @response = { "0.1.0" => { "recipes" => {"default.rb" => ""} } }
+        @response = { "0.1.0" => { "recipes" => { "default.rb" => "" } } }
       end
 
       it "should show the specific part of a cookbook" do
-        expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@response)
+        expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@response)
         expect(@knife).to receive(:output).with(@response)
         @knife.run
       end
@@ -92,16 +92,16 @@ describe Chef::Knife::CookbookShow do
               :name => "default.rb",
               :path => "recipes/default.rb",
               :checksum => "1234",
-              :url => "http://example.org/files/default.rb"
-            }
+              :url => "http://example.org/files/default.rb",
+            },
           ]
         }
         @cookbook_response.manifest = @manifest
-        @response = {"name"=>"default.rb", "url"=>"http://example.org/files/default.rb", "checksum"=>"1234", "path"=>"recipes/default.rb"}
+        @response = { "name" => "default.rb", "url" => "http://example.org/files/default.rb", "checksum" => "1234", "path" => "recipes/default.rb" }
       end
 
       it "should print the json of the part" do
-        expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+        expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
         expect(@knife).to receive(:output).with(@cookbook_response.manifest["recipes"])
         @knife.run
       end
@@ -117,16 +117,16 @@ describe Chef::Knife::CookbookShow do
               :name => "default.rb",
               :path => "recipes/default.rb",
               :checksum => "1234",
-              :url => "http://example.org/files/default.rb"
-            }
+              :url => "http://example.org/files/default.rb",
+            },
           ]
         }
         @response = "Example recipe text"
       end
 
       it "should print the raw result of the request (likely a file!)" do
-        expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
-        expect(@rest).to receive(:get_rest).with("http://example.org/files/default.rb", true).and_return(StringIO.new(@response))
+        expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+        expect(@rest).to receive(:streaming_request).with("http://example.org/files/default.rb").and_return(StringIO.new(@response))
         expect(@knife).to receive(:pretty_print).with(@response)
         @knife.run
       end
@@ -143,28 +143,28 @@ describe Chef::Knife::CookbookShow do
               :path => "files/host-examplehost.example.org/afile.rb",
               :checksum => "1111",
               :specificity => "host-examplehost.example.org",
-              :url => "http://example.org/files/1111"
+              :url => "http://example.org/files/1111",
             },
             {
               :name => "afile.rb",
               :path => "files/ubuntu-9.10/afile.rb",
               :checksum => "2222",
               :specificity => "ubuntu-9.10",
-              :url => "http://example.org/files/2222"
+              :url => "http://example.org/files/2222",
             },
             {
               :name => "afile.rb",
               :path => "files/ubuntu/afile.rb",
               :checksum => "3333",
               :specificity => "ubuntu",
-              :url => "http://example.org/files/3333"
+              :url => "http://example.org/files/3333",
             },
             {
               :name => "afile.rb",
               :path => "files/default/afile.rb",
               :checksum => "4444",
               :specificity => "default",
-              :url => "http://example.org/files/4444"
+              :url => "http://example.org/files/4444",
             },
           ]
         }
@@ -177,8 +177,8 @@ describe Chef::Knife::CookbookShow do
           @knife.config[:platform] = "example_platform"
           @knife.config[:platform_version] = "1.0"
           @knife.config[:fqdn] = "examplehost.example.org"
-          expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
-          expect(@rest).to receive(:get_rest).with("http://example.org/files/1111", true).and_return(StringIO.new(@response))
+          expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+          expect(@rest).to receive(:streaming_request).with("http://example.org/files/1111").and_return(StringIO.new(@response))
           expect(@knife).to receive(:pretty_print).with(@response)
           @knife.run
         end
@@ -189,8 +189,8 @@ describe Chef::Knife::CookbookShow do
           @knife.config[:platform] = "ubuntu"
           @knife.config[:platform_version] = "1.0"
           @knife.config[:fqdn] = "differenthost.example.org"
-          expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
-          expect(@rest).to receive(:get_rest).with("http://example.org/files/3333", true).and_return(StringIO.new(@response))
+          expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+          expect(@rest).to receive(:streaming_request).with("http://example.org/files/3333").and_return(StringIO.new(@response))
           expect(@knife).to receive(:pretty_print).with(@response)
           @knife.run
         end
@@ -201,8 +201,8 @@ describe Chef::Knife::CookbookShow do
           @knife.config[:platform] = "ubuntu"
           @knife.config[:platform_version] = "9.10"
           @knife.config[:fqdn] = "differenthost.example.org"
-          expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
-          expect(@rest).to receive(:get_rest).with("http://example.org/files/2222", true).and_return(StringIO.new(@response))
+          expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+          expect(@rest).to receive(:streaming_request).with("http://example.org/files/2222").and_return(StringIO.new(@response))
           expect(@knife).to receive(:pretty_print).with(@response)
           @knife.run
         end
@@ -210,8 +210,8 @@ describe Chef::Knife::CookbookShow do
 
       describe "with none of the arguments, it should use the default" do
         it "should pass them all" do
-          expect(@rest).to receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
-          expect(@rest).to receive(:get_rest).with("http://example.org/files/4444", true).and_return(StringIO.new(@response))
+          expect(@rest).to receive(:get).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response)
+          expect(@rest).to receive(:streaming_request).with("http://example.org/files/4444").and_return(StringIO.new(@response))
           expect(@knife).to receive(:pretty_print).with(@response)
           @knife.run
         end
@@ -220,4 +220,3 @@ describe Chef::Knife::CookbookShow do
     end
   end
 end
-
diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb
index fdf4c21..d7f26f2 100644
--- a/spec/unit/knife/cookbook_site_download_spec.rb
+++ b/spec/unit/knife/cookbook_site_download_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2012 Thomas Bishop
+# Copyright:: Copyright 2012-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,73 +16,71 @@
 # limitations under the License.
 #
 
-require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
+require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
 
 describe Chef::Knife::CookbookSiteDownload do
 
-  describe 'run' do
+  describe "run" do
     before do
       @knife            = Chef::Knife::CookbookSiteDownload.new
-      @knife.name_args  = ['apache2']
-      @noauth_rest      = double('no auth rest')
+      @knife.name_args  = ["apache2"]
+      @noauth_rest      = double("no auth rest")
       @stderr           = StringIO.new
-      @cookbook_api_url = 'https://supermarket.chef.io/api/v1/cookbooks'
-      @version          = '1.0.2'
-      @version_us       = @version.gsub '.', '_'
-      @current_data     = { 'deprecated'       => false,
-                            'latest_version'   => "#{@cookbook_api_url}/apache2/versions/#{@version_us}",
-                            'replacement' => 'other_apache2' }
+      @cookbook_api_url = "https://supermarket.chef.io/api/v1/cookbooks"
+      @version          = "1.0.2"
+      @version_us       = @version.gsub ".", "_"
+      @current_data     = { "deprecated"       => false,
+                            "latest_version"   => "#{@cookbook_api_url}/apache2/versions/#{@version_us}",
+                            "replacement" => "other_apache2" }
 
       allow(@knife.ui).to receive(:stderr).and_return(@stderr)
       allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest)
-      expect(@noauth_rest).to receive(:get_rest).
-                   with("#{@cookbook_api_url}/apache2").
-                   and_return(@current_data)
+      expect(@noauth_rest).to receive(:get).
+        with("#{@cookbook_api_url}/apache2").
+        and_return(@current_data)
     end
 
-    context 'when the cookbook is deprecated and not forced' do
+    context "when the cookbook is deprecated and not forced" do
       before do
-        @current_data['deprecated'] = true
+        @current_data["deprecated"] = true
       end
 
-      it 'should warn with info about the replacement' do
+      it "should warn with info about the replacement" do
         expect(@knife.ui).to receive(:warn).
-                  with(/.+deprecated.+replaced by other_apache2.+/i)
+          with(/.+deprecated.+replaced by other_apache2.+/i)
         expect(@knife.ui).to receive(:warn).
-                  with(/use --force.+download.+/i)
+          with(/use --force.+download.+/i)
         @knife.run
       end
     end
 
-    context 'when' do
+    context "when" do
       before do
-        @cookbook_data = { 'version' => @version,
-                           'file'    => "http://example.com/apache2_#{@version_us}.tgz" }
-        @temp_file     =  double( :path => "/tmp/apache2_#{@version_us}.tgz" )
+        @cookbook_data = { "version" => @version,
+                           "file"    => "http://example.com/apache2_#{@version_us}.tgz" }
+        @temp_file     = double( :path => "/tmp/apache2_#{@version_us}.tgz" )
         @file          = File.join(Dir.pwd, "apache2-#{@version}.tar.gz")
-
-        expect(@noauth_rest).to receive(:sign_on_redirect=).with(false)
       end
 
-      context 'downloading the latest version' do
+      context "downloading the latest version" do
         before do
-          expect(@noauth_rest).to receive(:get_rest).
-                       with(@current_data['latest_version']).
-                       and_return(@cookbook_data)
-          expect(@noauth_rest).to receive(:get_rest).
-                       with(@cookbook_data['file'], true).
-                       and_return(@temp_file)
+          expect(@noauth_rest).to receive(:get).
+            with(@current_data["latest_version"]).
+            and_return(@cookbook_data)
+          expect(@noauth_rest).to receive(:streaming_request).
+            with(@cookbook_data["file"]).
+            and_return(@temp_file)
         end
 
-        context 'and it is deprecated and with --force' do
+        context "and it is deprecated and with --force" do
           before do
-            @current_data['deprecated'] = true
+            @current_data["deprecated"] = true
             @knife.config[:force] = true
           end
 
-          it 'should download the latest version' do
+          it "should download the latest version" do
             expect(@knife.ui).to receive(:warn).
-                      with(/.+deprecated.+replaced by other_apache2.+/i)
+              with(/.+deprecated.+replaced by other_apache2.+/i)
             expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
             @knife.run
             expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
@@ -91,52 +89,52 @@ describe Chef::Knife::CookbookSiteDownload do
 
         end
 
-        it 'should download the latest version' do
+        it "should download the latest version" do
           expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
           @knife.run
           expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
           expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i
         end
 
-        context 'with -f or --file' do
+        context "with -f or --file" do
           before do
-            @file = '/opt/chef/cookbooks/apache2.tar.gz'
+            @file = "/opt/chef/cookbooks/apache2.tar.gz"
             @knife.config[:file] = @file
             expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
           end
 
-          it 'should download the cookbook to the desired file' do
+          it "should download the cookbook to the desired file" do
             @knife.run
             expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
             expect(@stderr.string).to match /cookbook save.+#{Regexp.escape(@file)}/i
           end
         end
 
-        it 'should provide an accessor to the version' do
+        it "should provide an accessor to the version" do
           allow(FileUtils).to receive(:cp).and_return(true)
           expect(@knife.version).to eq(@version)
           @knife.run
         end
       end
 
-      context 'downloading a cookbook of a specific version' do
+      context "downloading a cookbook of a specific version" do
         before do
-          @version         = '1.0.1'
-          @version_us      = @version.gsub '.', '_'
-          @cookbook_data   = { 'version' => @version,
-                               'file'    => "http://example.com/apache2_#{@version_us}.tgz" }
+          @version         = "1.0.1"
+          @version_us      = @version.gsub ".", "_"
+          @cookbook_data   = { "version" => @version,
+                               "file"    => "http://example.com/apache2_#{@version_us}.tgz" }
           @temp_file       = double(:path => "/tmp/apache2_#{@version_us}.tgz")
           @file            = File.join(Dir.pwd, "apache2-#{@version}.tar.gz")
           @knife.name_args << @version
         end
 
-        it 'should download the desired version' do
-          expect(@noauth_rest).to receive(:get_rest).
-                       with("#{@cookbook_api_url}/apache2/versions/#{@version_us}").
-                       and_return(@cookbook_data)
-          expect(@noauth_rest).to receive(:get_rest).
-                       with(@cookbook_data['file'], true).
-                       and_return(@temp_file)
+        it "should download the desired version" do
+          expect(@noauth_rest).to receive(:get).
+            with("#{@cookbook_api_url}/apache2/versions/#{@version_us}").
+            and_return(@cookbook_data)
+          expect(@noauth_rest).to receive(:streaming_request).
+            with(@cookbook_data["file"]).
+            and_return(@temp_file)
           expect(FileUtils).to receive(:cp).with(@temp_file.path, @file)
           @knife.run
           expect(@stderr.string).to match /downloading apache2.+version.+#{Regexp.escape(@version)}/i
diff --git a/spec/unit/knife/cookbook_site_install_spec.rb b/spec/unit/knife/cookbook_site_install_spec.rb
index 07b268b..b0b1e8a 100644
--- a/spec/unit/knife/cookbook_site_install_spec.rb
+++ b/spec/unit/knife/cookbook_site_install_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,14 +26,16 @@ describe Chef::Knife::CookbookSiteInstall do
   let(:repo) { double(:sanity_check => true, :reset_to_default_state => true,
                       :prepare_to_import => true, :finalize_updates_to => true,
                       :merge_updates_from => true) }
-  let(:install_path) { if Chef::Platform.windows?
-                        'C:/tmp/chef'
-                      else
-                        '/var/tmp/chef'
-                      end }
+  let(:install_path) {
+    if Chef::Platform.windows?
+      "C:/tmp/chef"
+    else
+      "/var/tmp/chef"
+    end
+  }
 
   before(:each) do
-    require 'chef/knife/core/cookbook_scm_repo'
+    require "chef/knife/core/cookbook_scm_repo"
 
     allow(knife.ui).to receive(:stdout).and_return(stdout)
     knife.config = {}
diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb
index 76e4ec7..662b53d 100644
--- a/spec/unit/knife/cookbook_site_share_spec.rb
+++ b/spec/unit/knife/cookbook_site_share_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/cookbook_uploader'
-require 'chef/cookbook_site_streaming_uploader'
+require "chef/cookbook_uploader"
+require "chef/cookbook_site_streaming_uploader"
 
 describe Chef::Knife::CookbookSiteShare do
 
@@ -27,19 +27,19 @@ describe Chef::Knife::CookbookSiteShare do
     @knife = Chef::Knife::CookbookSiteShare.new
     # Merge default settings in.
     @knife.merge_configs
-    @knife.name_args = ['cookbook_name', 'AwesomeSausage']
+    @knife.name_args = ["cookbook_name", "AwesomeSausage"]
 
-    @cookbook = Chef::CookbookVersion.new('cookbook_name')
+    @cookbook = Chef::CookbookVersion.new("cookbook_name")
 
-    @cookbook_loader = double('Chef::CookbookLoader')
+    @cookbook_loader = double("Chef::CookbookLoader")
     allow(@cookbook_loader).to receive(:cookbook_exists?).and_return(true)
     allow(@cookbook_loader).to receive(:[]).and_return(@cookbook)
     allow(Chef::CookbookLoader).to receive(:new).and_return(@cookbook_loader)
 
-    @noauth_rest = double(Chef::REST)
+    @noauth_rest = double(Chef::ServerAPI)
     allow(@knife).to receive(:noauth_rest).and_return(@noauth_rest)
 
-    @cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest")
+    @cookbook_uploader = Chef::CookbookUploader.new("herpderp", :rest => "norest")
     allow(Chef::CookbookUploader).to receive(:new).and_return(@cookbook_uploader)
     allow(@cookbook_uploader).to receive(:validate_cookbooks).and_return(true)
     allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return(Dir.mktmpdir)
@@ -49,55 +49,55 @@ describe Chef::Knife::CookbookSiteShare do
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
   end
 
-  describe 'run' do
+  describe "run" do
 
     before(:each) do
       allow(@knife).to receive(:do_upload).and_return(true)
       @category_response = {
         "name" => "cookbook_name",
-        "category" => "Testing Category"
+        "category" => "Testing Category",
       }
       @bad_category_response = {
         "error_code" => "NOT_FOUND",
         "error_messages" => [
             "Resource does not exist."
-        ]
+        ],
       }
     end
 
-    it 'should set true to config[:dry_run] as default' do
+    it "should set true to config[:dry_run] as default" do
       expect(@knife.config[:dry_run]).to be_falsey
     end
 
-    it 'should should print usage and exit when given no arguments' do
+    it "should should print usage and exit when given no arguments" do
       @knife.name_args = []
       expect(@knife).to receive(:show_usage)
       expect(@knife.ui).to receive(:fatal)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should not fail when given only 1 argument and can determine category' do
-      @knife.name_args = ['cookbook_name']
-      expect(@noauth_rest).to receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name").and_return(@category_response)
+    it "should not fail when given only 1 argument and can determine category" do
+      @knife.name_args = ["cookbook_name"]
+      expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@category_response)
       expect(@knife).to receive(:do_upload)
       @knife.run
     end
 
-    it 'should print error and exit when given only 1 argument and cannot determine category' do
-      @knife.name_args = ['cookbook_name']
-      expect(@noauth_rest).to receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name").and_return(@bad_category_response)
+    it "should print error and exit when given only 1 argument and cannot determine category" do
+      @knife.name_args = ["cookbook_name"]
+      expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name").and_return(@bad_category_response)
       expect(@knife.ui).to receive(:fatal)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should print error and exit when given only 1 argument and Chef::REST throws an exception' do
-      @knife.name_args = ['cookbook_name']
-      expect(@noauth_rest).to receive(:get_rest).with("http://cookbooks.opscode.com/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" }
+    it "should print error and exit when given only 1 argument and Chef::ServerAPI throws an exception" do
+      @knife.name_args = ["cookbook_name"]
+      expect(@noauth_rest).to receive(:get).with("https://supermarket.chef.io/api/v1/cookbooks/cookbook_name") { raise Errno::ECONNREFUSED, "Connection refused" }
       expect(@knife.ui).to receive(:fatal)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should check if the cookbook exists' do
+    it "should check if the cookbook exists" do
       expect(@cookbook_loader).to receive(:cookbook_exists?)
       @knife.run
     end
@@ -108,15 +108,15 @@ describe Chef::Knife::CookbookSiteShare do
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    if File.exists?('/usr/bin/gnutar') || File.exists?('/bin/gnutar')
-      it 'should use gnutar to make a tarball of the cookbook' do
+    if File.exists?("/usr/bin/gnutar") || File.exists?("/bin/gnutar")
+      it "should use gnutar to make a tarball of the cookbook" do
         expect(@knife).to receive(:shell_out!) do |args|
           expect(args.to_s).to match(/gnutar -czf/)
         end
         @knife.run
       end
     else
-      it 'should make a tarball of the cookbook' do
+      it "should make a tarball of the cookbook" do
         expect(@knife).to receive(:shell_out!) do |args|
           expect(args.to_s).to match(/tar -czf/)
         end
@@ -124,13 +124,13 @@ describe Chef::Knife::CookbookSiteShare do
       end
     end
 
-    it 'should exit and log to error when the tarball creation fails' do
+    it "should exit and log to error when the tarball creation fails" do
       allow(@knife).to receive(:shell_out!).and_raise(Chef::Exceptions::Exec)
       expect(@knife.ui).to receive(:error)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should upload the cookbook and clean up the tarball' do
+    it "should upload the cookbook and clean up the tarball" do
       expect(@knife).to receive(:do_upload)
       expect(FileUtils).to receive(:rm_rf)
       @knife.run
@@ -140,13 +140,13 @@ describe Chef::Knife::CookbookSiteShare do
       before do
         allow(Chef::CookbookSiteStreamingUploader).to receive(:create_build_dir).and_return("/var/tmp/dummy")
         @knife.config = { :dry_run => true }
-        allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return('file')
+        allow(@knife).to receive_message_chain(:shell_out!, :stdout).and_return("file")
       end
 
       it "should list files in the tarball" do
         allow(@knife).to receive(:tar_cmd).and_return("footar")
-        expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", {:cwd => "/var/tmp/dummy"})
-        expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", {:cwd => "/var/tmp/dummy"})
+        expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", { :cwd => "/var/tmp/dummy" })
+        expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", { :cwd => "/var/tmp/dummy" })
         @knife.run
       end
 
@@ -158,10 +158,10 @@ describe Chef::Knife::CookbookSiteShare do
     end
   end
 
-  describe 'do_upload' do
+  describe "do_upload" do
 
     before(:each) do
-      @upload_response = double('Net::HTTPResponse')
+      @upload_response = double("Net::HTTPResponse")
       allow(Chef::CookbookSiteStreamingUploader).to receive(:post).and_return(@upload_response)
 
       @stdout = StringIO.new
@@ -172,31 +172,31 @@ describe Chef::Knife::CookbookSiteShare do
     end
 
     it 'should post the cookbook to "https://supermarket.chef.io"' do
-      response_text = Chef::JSONCompat.to_json({:uri => 'https://supermarket.chef.io/cookbooks/cookbook_name'})
+      response_text = Chef::JSONCompat.to_json({ :uri => "https://supermarket.chef.io/cookbooks/cookbook_name" })
       allow(@upload_response).to receive(:body).and_return(response_text)
       allow(@upload_response).to receive(:code).and_return(201)
       expect(Chef::CookbookSiteStreamingUploader).to receive(:post).with(/supermarket\.chef\.io/, anything(), anything(), anything())
       @knife.run
     end
 
-    it 'should alert the user when a version already exists' do
-      response_text = Chef::JSONCompat.to_json({:error_messages => ['Version already exists']})
+    it "should alert the user when a version already exists" do
+      response_text = Chef::JSONCompat.to_json({ :error_messages => ["Version already exists"] })
       allow(@upload_response).to receive(:body).and_return(response_text)
       allow(@upload_response).to receive(:code).and_return(409)
       expect { @knife.run }.to raise_error(SystemExit)
       expect(@stderr.string).to match(/ERROR(.+)cookbook already exists/)
     end
 
-    it 'should pass any errors on to the user' do
-      response_text = Chef::JSONCompat.to_json({:error_messages => ["You're holding it wrong"]})
+    it "should pass any errors on to the user" do
+      response_text = Chef::JSONCompat.to_json({ :error_messages => ["You're holding it wrong"] })
       allow(@upload_response).to receive(:body).and_return(response_text)
       allow(@upload_response).to receive(:code).and_return(403)
       expect { @knife.run }.to raise_error(SystemExit)
       expect(@stderr.string).to match("ERROR(.*)You're holding it wrong")
     end
 
-    it 'should print the body if no errors are exposed on failure' do
-      response_text = Chef::JSONCompat.to_json({:system_error => "Your call was dropped", :reason => "There's a map for that"})
+    it "should print the body if no errors are exposed on failure" do
+      response_text = Chef::JSONCompat.to_json({ :system_error => "Your call was dropped", :reason => "There's a map for that" })
       allow(@upload_response).to receive(:body).and_return(response_text)
       allow(@upload_response).to receive(:code).and_return(500)
       expect(@knife.ui).to receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered
diff --git a/spec/unit/knife/cookbook_site_unshare_spec.rb b/spec/unit/knife/cookbook_site_unshare_spec.rb
index ec46a87..8e43582 100644
--- a/spec/unit/knife/cookbook_site_unshare_spec.rb
+++ b/spec/unit/knife/cookbook_site_unshare_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,26 +17,26 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::CookbookSiteUnshare do
 
   before(:each) do
     @knife = Chef::Knife::CookbookSiteUnshare.new
-    @knife.name_args = ['cookbook_name']
+    @knife.name_args = ["cookbook_name"]
     allow(@knife).to receive(:confirm).and_return(true)
 
-    @rest = double('Chef::REST')
-    allow(@rest).to receive(:delete_rest).and_return(true)
+    @rest = double("Chef::ServerAPI")
+    allow(@rest).to receive(:delete).and_return(true)
     allow(@knife).to receive(:rest).and_return(@rest)
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
   end
 
-  describe 'run' do
+  describe "run" do
 
-    describe 'with no cookbook argument' do
-      it 'should print the usage and exit' do
+    describe "with no cookbook argument" do
+      it "should print the usage and exit" do
         @knife.name_args = []
         expect(@knife.ui).to receive(:fatal)
         expect(@knife).to receive(:show_usage)
@@ -44,30 +44,30 @@ describe Chef::Knife::CookbookSiteUnshare do
       end
     end
 
-    it 'should confirm you want to unshare the cookbook' do
+    it "should confirm you want to unshare the cookbook" do
       expect(@knife).to receive(:confirm)
       @knife.run
     end
 
-    it 'should send a delete request to the cookbook site' do
-      expect(@rest).to receive(:delete_rest)
+    it "should send a delete request to the cookbook site" do
+      expect(@rest).to receive(:delete)
       @knife.run
     end
 
-    it 'should log an error and exit when forbidden' do
-      exception = double('403 "Forbidden"', :code => '403')
-      allow(@rest).to receive(:delete_rest).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception))
+    it "should log an error and exit when forbidden" do
+      exception = double('403 "Forbidden"', :code => "403")
+      allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception))
       expect(@knife.ui).to receive(:error)
       expect { @knife.run }.to raise_error(SystemExit)
     end
 
-    it 'should re-raise any non-forbidden errors on delete_rest' do
-      exception = double('500 "Application Error"', :code => '500')
-      allow(@rest).to receive(:delete_rest).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception))
+    it "should re-raise any non-forbidden errors on delete" do
+      exception = double('500 "Application Error"', :code => "500")
+      allow(@rest).to receive(:delete).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception))
       expect { @knife.run }.to raise_error(Net::HTTPServerException)
     end
 
-    it 'should log a success message' do
+    it "should log a success message" do
       expect(@knife.ui).to receive(:info)
       @knife.run
     end
diff --git a/spec/unit/knife/cookbook_test_spec.rb b/spec/unit/knife/cookbook_test_spec.rb
index ce74bca..abb88fe 100644
--- a/spec/unit/knife/cookbook_test_spec.rb
+++ b/spec/unit/knife/cookbook_test_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)$
+# Author:: Stephen Delano (<stephen at chef.io>)$
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.$
-# Copyright:: Copyright (c) 2010 Matthew Kent
+# Copyright:: Copyright 2010-2016, Chef Software Inc.$
+# Copyright:: Copyright 2010-2016, Matthew Kent
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +18,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 Chef::Knife::CookbookTest.load_deps
 
 describe Chef::Knife::CookbookTest do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::CookbookTest.new
-    @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA,'cookbooks')
+    @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA, "cookbooks")
     allow(@knife.cookbook_loader).to receive(:cookbook_exists?).and_return(true)
     @cookbooks = []
     %w{tats central_market jimmy_johns pho}.each do |cookbook_name|
diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb
index fb94886..dc55a70 100644
--- a/spec/unit/knife/cookbook_upload_spec.rb
+++ b/spec/unit/knife/cookbook_upload_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,14 @@
 
 require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
 
-require 'chef/cookbook_uploader'
-require 'timeout'
+require "chef/cookbook_uploader"
+require "timeout"
 
 describe Chef::Knife::CookbookUpload do
-  let(:cookbook) { Chef::CookbookVersion.new('test_cookbook', '/tmp/blah.txt') }
+  let(:cookbook) { Chef::CookbookVersion.new("test_cookbook", "/tmp/blah.txt") }
 
   let(:cookbooks_by_name) do
-    {cookbook.name => cookbook}
+    { cookbook.name => cookbook }
   end
 
   let(:cookbook_loader) do
@@ -40,7 +40,7 @@ describe Chef::Knife::CookbookUpload do
 
   let(:output) { StringIO.new }
 
-  let(:name_args) { ['test_cookbook'] }
+  let(:name_args) { ["test_cookbook"] }
 
   let(:knife) do
     k = Chef::Knife::CookbookUpload.new
@@ -54,49 +54,49 @@ describe Chef::Knife::CookbookUpload do
     allow(Chef::CookbookLoader).to receive(:new).and_return(cookbook_loader)
   end
 
-  describe 'with --concurrency' do
-    it 'should upload cookbooks with predefined concurrency' do
+  describe "with --concurrency" do
+    it "should upload cookbooks with predefined concurrency" do
       allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
       knife.config[:concurrency] = 3
-      test_cookbook = Chef::CookbookVersion.new('test_cookbook', '/tmp/blah')
+      test_cookbook = Chef::CookbookVersion.new("test_cookbook", "/tmp/blah")
       allow(cookbook_loader).to receive(:each).and_yield("test_cookbook", test_cookbook)
       allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook"])
       expect(Chef::CookbookUploader).to receive(:new).
-        with( kind_of(Array), { :force => nil, :concurrency => 3}).
-        and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true))
+        with( kind_of(Array), { :force => nil, :concurrency => 3 }).
+        and_return(double("Chef::CookbookUploader", :upload_cookbooks => true))
       knife.run
     end
   end
 
-  describe 'run' do
+  describe "run" do
     before(:each) do
       allow(Chef::CookbookUploader).to receive_messages(:new => cookbook_uploader)
       allow(Chef::CookbookVersion).to receive(:list_all_versions).and_return({})
     end
 
-    it 'should print usage and exit when a cookbook name is not provided' do
+    it "should print usage and exit when a cookbook name is not provided" do
       knife.name_args = []
       expect(knife).to receive(:show_usage)
       expect(knife.ui).to receive(:fatal)
       expect { knife.run }.to raise_error(SystemExit)
     end
 
-    describe 'when specifying a cookbook name' do
-      it 'should upload the cookbook' do
+    describe "when specifying a cookbook name" do
+      it "should upload the cookbook" do
         expect(knife).to receive(:upload).once
         knife.run
       end
 
-      it 'should report on success' do
+      it "should report on success" do
         expect(knife).to receive(:upload).once
         expect(knife.ui).to receive(:info).with(/Uploaded 1 cookbook/)
         knife.run
       end
     end
 
-    describe 'when specifying the same cookbook name twice' do
-      it 'should upload the cookbook only once' do
-        knife.name_args = ['test_cookbook', 'test_cookbook']
+    describe "when specifying the same cookbook name twice" do
+      it "should upload the cookbook only once" do
+        knife.name_args = ["test_cookbook", "test_cookbook"]
         expect(knife).to receive(:upload).once
         knife.run
       end
@@ -105,14 +105,14 @@ describe Chef::Knife::CookbookUpload do
     context "when uploading a cookbook that uses deprecated overlays" do
 
       before do
-        allow(cookbook_loader).to receive(:merged_cookbooks).and_return(['test_cookbook'])
+        allow(cookbook_loader).to receive(:merged_cookbooks).and_return(["test_cookbook"])
         allow(cookbook_loader).to receive(:merged_cookbook_paths).
-          and_return({'test_cookbook' => %w{/path/one/test_cookbook /path/two/test_cookbook}})
+          and_return({ "test_cookbook" => %w{/path/one/test_cookbook /path/two/test_cookbook} })
       end
 
       it "emits a warning" do
         knife.run
-        expected_message=<<-E
+        expected_message = <<-E
 WARNING: The cookbooks: test_cookbook exist in multiple places in your cookbook_path.
 A composite version of these cookbooks has been compiled for uploading.
 
@@ -127,19 +127,19 @@ E
       end
     end
 
-    describe 'when specifying a cookbook name among many' do
-      let(:name_args) { ['test_cookbook1'] }
+    describe "when specifying a cookbook name among many" do
+      let(:name_args) { ["test_cookbook1"] }
 
       let(:cookbooks_by_name) do
         {
-          'test_cookbook1' => Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah'),
-          'test_cookbook2' => Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah'),
-          'test_cookbook3' => Chef::CookbookVersion.new('test_cookbook3', '/tmp/blah')
+          "test_cookbook1" => Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah"),
+          "test_cookbook2" => Chef::CookbookVersion.new("test_cookbook2", "/tmp/blah"),
+          "test_cookbook3" => Chef::CookbookVersion.new("test_cookbook3", "/tmp/blah"),
         }
       end
 
       it "should read only one cookbook" do
-        expect(cookbook_loader).to receive(:[]).once.with('test_cookbook1').and_call_original
+        expect(cookbook_loader).to receive(:[]).once.with("test_cookbook1").and_call_original
         knife.run
       end
 
@@ -155,7 +155,7 @@ E
     end
 
     # This is testing too much.  We should break it up.
-    describe 'when specifying a cookbook name with dependencies' do
+    describe "when specifying a cookbook name with dependencies" do
       let(:name_args) { ["test_cookbook2"] }
 
       let(:cookbooks_by_name) do
@@ -164,16 +164,16 @@ E
           "test_cookbook3" => test_cookbook3 }
       end
 
-      let(:test_cookbook1) { Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') }
+      let(:test_cookbook1) { Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah") }
 
       let(:test_cookbook2) do
-        c = Chef::CookbookVersion.new('test_cookbook2')
+        c = Chef::CookbookVersion.new("test_cookbook2")
         c.metadata.depends("test_cookbook3")
         c
       end
 
       let(:test_cookbook3) do
-        c = Chef::CookbookVersion.new('test_cookbook3')
+        c = Chef::CookbookVersion.new("test_cookbook3")
         c.metadata.depends("test_cookbook1")
         c.metadata.depends("test_cookbook2")
         c
@@ -191,46 +191,46 @@ E
       end
     end
 
-    describe 'when specifying a cookbook name with missing dependencies' do
-      let(:cookbook_dependency) { Chef::CookbookVersion.new('dependency', '/tmp/blah') }
+    describe "when specifying a cookbook name with missing dependencies" do
+      let(:cookbook_dependency) { Chef::CookbookVersion.new("dependency", "/tmp/blah") }
 
       before(:each) do
         cookbook.metadata.depends("dependency")
-        allow(cookbook_loader).to receive(:[])  do |ckbk|
+        allow(cookbook_loader).to receive(:[]) do |ckbk|
           { "test_cookbook" =>  cookbook,
-            "dependency" => cookbook_dependency}[ckbk]
+            "dependency" => cookbook_dependency }[ckbk]
         end
         allow(knife).to receive(:cookbook_names).and_return(["cookbook_dependency", "test_cookbook"])
         @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
         knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
       end
 
-      it 'should exit and not upload the cookbook' do
-        expect(cookbook_loader).to receive(:[]).once.with('test_cookbook')
+      it "should exit and not upload the cookbook" do
+        expect(cookbook_loader).to receive(:[]).once.with("test_cookbook")
         expect(cookbook_loader).not_to receive(:load_cookbooks)
         expect(cookbook_uploader).not_to receive(:upload_cookbooks)
-        expect {knife.run}.to raise_error(SystemExit)
+        expect { knife.run }.to raise_error(SystemExit)
       end
 
-      it 'should output a message for a single missing dependency' do
-        expect {knife.run}.to raise_error(SystemExit)
-        expect(@stderr.string).to include('Cookbook test_cookbook depends on cookbooks which are not currently')
-        expect(@stderr.string).to include('being uploaded and cannot be found on the server.')
+      it "should output a message for a single missing dependency" do
+        expect { knife.run }.to raise_error(SystemExit)
+        expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
+        expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
         expect(@stderr.string).to include("The missing cookbook(s) are: 'dependency' version '>= 0.0.0'")
       end
 
-      it 'should output a message for a multiple missing dependencies which are concatenated' do
-        cookbook_dependency2 = Chef::CookbookVersion.new('dependency2')
+      it "should output a message for a multiple missing dependencies which are concatenated" do
+        cookbook_dependency2 = Chef::CookbookVersion.new("dependency2")
         cookbook.metadata.depends("dependency2")
-        allow(cookbook_loader).to receive(:[])  do |ckbk|
+        allow(cookbook_loader).to receive(:[]) do |ckbk|
           { "test_cookbook" =>  cookbook,
             "dependency" => cookbook_dependency,
-            "dependency2" => cookbook_dependency2}[ckbk]
+            "dependency2" => cookbook_dependency2 }[ckbk]
         end
         allow(knife).to receive(:cookbook_names).and_return(["dependency", "dependency2", "test_cookbook"])
-        expect {knife.run}.to raise_error(SystemExit)
-        expect(@stderr.string).to include('Cookbook test_cookbook depends on cookbooks which are not currently')
-        expect(@stderr.string).to include('being uploaded and cannot be found on the server.')
+        expect { knife.run }.to raise_error(SystemExit)
+        expect(@stderr.string).to include("Cookbook test_cookbook depends on cookbooks which are not currently")
+        expect(@stderr.string).to include("being uploaded and cannot be found on the server.")
         expect(@stderr.string).to include("The missing cookbook(s) are:")
         expect(@stderr.string).to include("'dependency' version '>= 0.0.0'")
         expect(@stderr.string).to include("'dependency2' version '>= 0.0.0'")
@@ -243,31 +243,31 @@ E
       knife.run
     end
 
-    describe 'with -a or --all' do
+    describe "with -a or --all" do
       before(:each) do
         knife.config[:all] = true
       end
 
-      context 'when cookbooks exist in the cookbook path' do
+      context "when cookbooks exist in the cookbook path" do
         before(:each) do
-          @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah')
-          @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah')
+          @test_cookbook1 = Chef::CookbookVersion.new("test_cookbook1", "/tmp/blah")
+          @test_cookbook2 = Chef::CookbookVersion.new("test_cookbook2", "/tmp/blah")
           allow(cookbook_loader).to receive(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2)
           allow(cookbook_loader).to receive(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"])
         end
 
-        it 'should upload all cookbooks' do
+        it "should upload all cookbooks" do
           expect(knife).to receive(:upload).once
           knife.run
         end
 
-        it 'should report on success' do
+        it "should report on success" do
           expect(knife).to receive(:upload).once
           expect(knife.ui).to receive(:info).with(/Uploaded all cookbooks/)
           knife.run
         end
 
-        it 'should update the version constraints for an environment' do
+        it "should update the version constraints for an environment" do
           allow(knife).to receive(:assert_environment_valid!).and_return(true)
           knife.config[:environment] = "production"
           expect(knife).to receive(:update_version_constraints).once
@@ -275,28 +275,28 @@ E
         end
       end
 
-      context 'when no cookbooks exist in the cookbook path' do
+      context "when no cookbooks exist in the cookbook path" do
         before(:each) do
           allow(cookbook_loader).to receive(:each)
         end
 
-        it 'should not upload any cookbooks' do
+        it "should not upload any cookbooks" do
           expect(knife).to_not receive(:upload)
           knife.run
         end
 
-        context 'when cookbook path is an array' do
-          it 'should warn users that no cookbooks exist' do
-            knife.config[:cookbook_path] = ['/chef-repo/cookbooks', '/home/user/cookbooks']
+        context "when cookbook path is an array" do
+          it "should warn users that no cookbooks exist" do
+            knife.config[:cookbook_path] = ["/chef-repo/cookbooks", "/home/user/cookbooks"]
             expect(knife.ui).to receive(:warn).with(
               /Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path].join(', ')}\. Use --cookbook-path to specify the desired path\./)
             knife.run
           end
         end
 
-        context 'when cookbook path is a string' do
-          it 'should warn users that no cookbooks exist' do
-            knife.config[:cookbook_path] = '/chef-repo/cookbooks'
+        context "when cookbook path is a string" do
+          it "should warn users that no cookbooks exist" do
+            knife.config[:cookbook_path] = "/chef-repo/cookbooks"
             expect(knife.ui).to receive(:warn).with(
               /Could not find any cookbooks in your cookbook path: #{knife.config[:cookbook_path]}\. Use --cookbook-path to specify the desired path\./)
             knife.run
@@ -305,8 +305,8 @@ E
       end
     end
 
-    describe 'when a frozen cookbook exists on the server' do
-      it 'should fail to replace it' do
+    describe "when a frozen cookbook exists on the server" do
+      it "should fail to replace it" do
         exception = Chef::Exceptions::CookbookFrozen.new
         expect(cookbook_uploader).to receive(:upload_cookbooks).
           and_raise(exception)
@@ -315,7 +315,7 @@ E
         expect { knife.run }.to raise_error(SystemExit)
       end
 
-      it 'should not update the version constraints for an environment' do
+      it "should not update the version constraints for an environment" do
         allow(knife).to receive(:assert_environment_valid!).and_return(true)
         knife.config[:environment] = "production"
         allow(knife).to receive(:upload).and_raise(Chef::Exceptions::CookbookFrozen)
diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 3718cb2..efcc265 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,23 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/knife/core/bootstrap_context'
+require "spec_helper"
+require "chef/knife/core/bootstrap_context"
 
 describe Chef::Knife::Core::BootstrapContext do
-  let(:config) { {:foo => :bar} }
-  let(:run_list) { Chef::RunList.new('recipe[tmux]', 'role[base]') }
+  before do
+    # This is required because the chef-fips pipeline does
+    # has a default value of true for fips
+    Chef::Config[:fips] = false
+  end
+
+  let(:config) { { :foo => :bar, :color => true } }
+  let(:run_list) { Chef::RunList.new("recipe[tmux]", "role[base]") }
   let(:chef_config) do
     {
-      :validation_key => File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem'),
-      :chef_server_url => 'http://chef.example.com:4444',
-      :validation_client_name => 'chef-validator-testing'
+      :validation_key => File.join(CHEF_SPEC_DATA, "ssl", "private_key.pem"),
+      :chef_server_url => "http://chef.example.com:4444",
+      :validation_client_name => "chef-validator-testing",
     }
   end
 
@@ -35,26 +41,33 @@ describe Chef::Knife::Core::BootstrapContext do
   subject(:bootstrap_context) { described_class.new(config, run_list, chef_config, secret) }
 
   it "initializes with Chef 11 parameters" do
-    expect{described_class.new(config, run_list, chef_config)}.not_to raise_error
+    expect { described_class.new(config, run_list, chef_config) }.not_to raise_error
   end
 
-  it "runs chef with the first-boot.json in the _default environment" do
-    expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -E _default"
+  it "runs chef with the first-boot.json with no environment specified" do
+    expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json"
   end
 
   describe "when in verbosity mode" do
-    let(:config) { {:verbosity => 2} }
+    let(:config) { { :verbosity => 2, :color => true } }
     it "adds '-l debug' when verbosity is >= 2" do
-      expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -l debug -E _default"
+      expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -l debug"
+    end
+  end
+
+  describe "when no color value has been set in config" do
+    let(:config) { { :color => false } }
+    it "adds '--no-color' when color is false" do
+      expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json --no-color"
     end
   end
 
   it "reads the validation key" do
-    expect(bootstrap_context.validation_key).to eq IO.read(File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem'))
+    expect(bootstrap_context.validation_key).to eq IO.read(File.join(CHEF_SPEC_DATA, "ssl", "private_key.pem"))
   end
 
   it "generates the config file data" do
-    expected=<<-EXPECTED
+    expected = <<-EXPECTED
 log_location     STDOUT
 chef_server_url  "http://chef.example.com:4444"
 validation_client_name "chef-validator-testing"
@@ -68,48 +81,65 @@ EXPECTED
   end
 
   describe "alternate chef-client path" do
-    let(:chef_config){ {:chef_client_path => '/usr/local/bin/chef-client'} }
+    let(:chef_config) { { :chef_client_path => "/usr/local/bin/chef-client" } }
     it "runs chef-client from another path when specified" do
-      expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json -E _default"
+      expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json"
     end
   end
 
   describe "validation key path that contains a ~" do
-    let(:chef_config){ {:validation_key => '~/my.key'} }
+    let(:chef_config) { { :validation_key => "~/my.key" } }
     it "reads the validation key when it contains a ~" do
-      expect(File).to receive(:exist?).with(File.expand_path("my.key", ENV['HOME'])).and_return(true)
-      expect(IO).to receive(:read).with(File.expand_path("my.key", ENV['HOME']))
+      expect(File).to receive(:exist?).with(File.expand_path("my.key", ENV["HOME"])).and_return(true)
+      expect(IO).to receive(:read).with(File.expand_path("my.key", ENV["HOME"]))
       bootstrap_context.validation_key
     end
   end
 
   describe "when an explicit node name is given" do
-    let(:config){ {:chef_node_name => 'foobar.example.com' }}
+    let(:config) { { :chef_node_name => "foobar.example.com" } }
     it "sets the node name in the client.rb" do
       expect(bootstrap_context.config_content).to match(/node_name "foobar\.example\.com"/)
     end
   end
 
   describe "when bootstrapping into a specific environment" do
-    let(:chef_config){ {:environment => "prodtastic"} }
+    let(:config) { { :environment => "prodtastic", :color => true } }
     it "starts chef in the configured environment" do
-      expect(bootstrap_context.start_chef).to eq('chef-client -j /etc/chef/first-boot.json -E prodtastic')
+      expect(bootstrap_context.start_chef).to eq("chef-client -j /etc/chef/first-boot.json -E prodtastic")
+    end
+  end
+
+  describe "when tags are given" do
+    let(:config) { { :tags => [ "unicorn" ] } }
+    it "adds the attributes to first_boot" do
+      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :run_list => run_list, :tags => ["unicorn"] }))
     end
   end
 
   describe "when JSON attributes are given" do
-    let(:config) { {:first_boot_attributes => {:baz => :quux}} }
+    let(:config) { { :first_boot_attributes => { :baz => :quux } } }
     it "adds the attributes to first_boot" do
-      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({:baz => :quux, :run_list => run_list}))
+      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :baz => :quux, :run_list => run_list }))
     end
   end
 
   describe "when JSON attributes are NOT given" do
     it "sets first_boot equal to run_list" do
-      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({:run_list => run_list}))
+      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json({ :run_list => run_list }))
     end
   end
 
+  describe "when policy_name and policy_group are present in config" do
+
+    let(:config) { { policy_name: "my_app_server", policy_group: "staging" } }
+
+    it "includes them in the first_boot data and excludes run_list" do
+      expect(Chef::JSONCompat.to_json(bootstrap_context.first_boot)).to eq(Chef::JSONCompat.to_json(config))
+    end
+
+  end
+
   describe "when an encrypted_data_bag_secret is provided" do
     let(:secret) { "supersekret" }
     it "reads the encrypted_data_bag_secret" do
@@ -130,7 +160,7 @@ EXPECTED
   describe "when a bootstrap_version is specified" do
     let(:chef_config) do
       {
-        :knife => {:bootstrap_version => "11.12.4" }
+        :knife => { :bootstrap_version => "11.12.4" }
       }
     end
 
@@ -142,7 +172,7 @@ EXPECTED
   describe "when a pre-release bootstrap_version is specified" do
     let(:chef_config) do
       {
-        :knife => {:bootstrap_version => "11.12.4.rc.0" }
+        :knife => { :bootstrap_version => "11.12.4.rc.0" }
       }
     end
 
@@ -166,7 +196,7 @@ EXPECTED
     describe "when configured in config" do
       let(:chef_config) do
         {
-          :knife => {:ssl_verify_mode => :verify_peer}
+          :knife => { :ssl_verify_mode => :verify_peer }
         }
       end
 
@@ -175,7 +205,7 @@ EXPECTED
       end
 
       describe "when configured via CLI" do
-        let(:config) {{:node_ssl_verify_mode => "none"}}
+        let(:config) { { :node_ssl_verify_mode => "none" } }
 
         it "uses CLI value" do
           expect(bootstrap_context.config_content).to include("ssl_verify_mode :verify_none")
@@ -192,7 +222,7 @@ EXPECTED
     describe "when configured in config" do
       let(:chef_config) do
         {
-          :knife => {:verify_api_cert => :false}
+          :knife => { :verify_api_cert => :false }
         }
       end
 
@@ -201,7 +231,7 @@ EXPECTED
       end
 
       describe "when configured via CLI" do
-        let(:config) {{:node_verify_api_cert => true}}
+        let(:config) { { :node_verify_api_cert => true } }
 
         it "uses CLI value" do
           expect(bootstrap_context.config_content).to include("verify_api_cert true")
@@ -216,7 +246,7 @@ EXPECTED
     end
 
     describe "when configured via cli" do
-      let(:config) {{:prerelease => true}}
+      let(:config) { { :prerelease => true } }
 
       it "uses CLI value" do
         expect(bootstrap_context.latest_current_chef_version_string).to eq("-p")
diff --git a/spec/unit/knife/core/cookbook_scm_repo_spec.rb b/spec/unit/knife/core/cookbook_scm_repo_spec.rb
index 2d66df3..137bddd 100644
--- a/spec/unit/knife/core/cookbook_scm_repo_spec.rb
+++ b/spec/unit/knife/core/cookbook_scm_repo_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/knife/core/cookbook_scm_repo'
+require "spec_helper"
+require "chef/knife/core/cookbook_scm_repo"
 
 describe Chef::Knife::CookbookSCMRepo do
   before do
-    @repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks')
+    @repo_path = File.join(CHEF_SPEC_DATA, "cookbooks")
     @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new
     @ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {})
-    @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'master')
+    @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => "master")
 
     @branch_list = Mixlib::ShellOut.new
     @branch_list.stdout.replace(<<-BRANCHES)
@@ -43,13 +43,13 @@ BRANCHES
   end
 
   it "has a default branch" do
-    expect(@cookbook_repo.default_branch).to eq('master')
+    expect(@cookbook_repo.default_branch).to eq("master")
   end
 
   describe "when sanity checking the repo" do
     it "exits when the directory does not exist" do
       expect(::File).to receive(:directory?).with(@repo_path).and_return(false)
-      expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+      expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
     end
 
     describe "and the repo dir exists" do
@@ -59,18 +59,18 @@ BRANCHES
 
       it "exits when there is no git repo" do
         allow(::File).to receive(:directory?).with(/.*\.git/).and_return(false)
-        expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+        expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
       end
 
       describe "and the repo is a git repo" do
         before do
-          allow(::File).to receive(:directory?).with(File.join(@repo_path, '.git')).and_return(true)
+          allow(::File).to receive(:directory?).with(File.join(@repo_path, ".git")).and_return(true)
         end
 
         it "exits when the default branch doesn't exist" do
-          @nobranches = Mixlib::ShellOut.new.tap {|s|s.stdout.replace "\n"}
-          expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@nobranches)
-          expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+          @nobranches = Mixlib::ShellOut.new.tap { |s| s.stdout.replace "\n" }
+          expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@nobranches)
+          expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
         end
 
         describe "and the default branch exists" do
@@ -85,14 +85,14 @@ BRANCHES
             @dirty_status.stdout.replace(<<-DIRTY)
  M chef/lib/chef/knife/cookbook_site_vendor.rb
 DIRTY
-            expect(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@dirty_status)
-            expect {@cookbook_repo.sanity_check}.to raise_error(SystemExit)
+            expect(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain", :cwd => @repo_path).and_return(@dirty_status)
+            expect { @cookbook_repo.sanity_check }.to raise_error(SystemExit)
           end
 
           describe "and the repo is clean" do
             before do
-              @clean_status = Mixlib::ShellOut.new.tap {|s| s.stdout.replace("\n")}
-              allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@clean_status)
+              @clean_status = Mixlib::ShellOut.new.tap { |s| s.stdout.replace("\n") }
+              allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain", :cwd => @repo_path).and_return(@clean_status)
             end
 
             it "passes the sanity check" do
@@ -106,35 +106,35 @@ DIRTY
   end
 
   it "resets to default state by checking out the default branch" do
-    expect(@cookbook_repo).to receive(:shell_out!).with('git checkout master', :cwd => @repo_path)
+    expect(@cookbook_repo).to receive(:shell_out!).with("git checkout master", :cwd => @repo_path)
     @cookbook_repo.reset_to_default_state
   end
 
   it "determines if a the pristine copy branch exists" do
-    expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+    expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
     expect(@cookbook_repo.branch_exists?("chef-vendor-apache2")).to be_truthy
-    expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+    expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
     expect(@cookbook_repo.branch_exists?("chef-vendor-nginx")).to be_falsey
   end
 
   it "determines if a the branch not exists correctly without substring search" do
-    expect(@cookbook_repo).to receive(:shell_out!).twice.with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
+    expect(@cookbook_repo).to receive(:shell_out!).twice.with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
     expect(@cookbook_repo).not_to be_branch_exists("chef-vendor-absent")
     expect(@cookbook_repo).to be_branch_exists("chef-vendor-absent-new")
   end
 
   describe "when the pristine copy branch does not exist" do
     it "prepares for import by creating the pristine copy branch" do
-      expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
-      expect(@cookbook_repo).to receive(:shell_out!).with('git checkout -b chef-vendor-nginx', :cwd => @repo_path)
+      expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
+      expect(@cookbook_repo).to receive(:shell_out!).with("git checkout -b chef-vendor-nginx", :cwd => @repo_path)
       @cookbook_repo.prepare_to_import("nginx")
     end
   end
 
   describe "when the pristine copy branch does exist" do
     it "prepares for import by checking out the pristine copy branch" do
-      expect(@cookbook_repo).to receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list)
-      expect(@cookbook_repo).to receive(:shell_out!).with('git checkout chef-vendor-apache2', :cwd => @repo_path)
+      expect(@cookbook_repo).to receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@branch_list)
+      expect(@cookbook_repo).to receive(:shell_out!).with("git checkout chef-vendor-apache2", :cwd => @repo_path)
       @cookbook_repo.prepare_to_import("apache2")
     end
   end
@@ -143,15 +143,15 @@ DIRTY
     before do
       @updates = Mixlib::ShellOut.new
       @updates.stdout.replace("\n")
-      allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates)
+      allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain -- apache2", :cwd => @repo_path).and_return(@updates)
     end
 
     it "shows no changes in the pristine copy" do
-      expect(@cookbook_repo.updated?('apache2')).to be_falsey
+      expect(@cookbook_repo.updated?("apache2")).to be_falsey
     end
 
     it "does nothing to finalize the updates" do
-      expect(@cookbook_repo.finalize_updates_to('apache2', '1.2.3')).to be_falsey
+      expect(@cookbook_repo.finalize_updates_to("apache2", "1.2.3")).to be_falsey
     end
   end
 
@@ -159,11 +159,11 @@ DIRTY
     before do
       @updates = Mixlib::ShellOut.new
       @updates.stdout.replace(" M cookbooks/apache2/recipes/default.rb\n")
-      allow(@cookbook_repo).to receive(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates)
+      allow(@cookbook_repo).to receive(:shell_out!).with("git status --porcelain -- apache2", :cwd => @repo_path).and_return(@updates)
     end
 
     it "shows changes in the pristine copy" do
-      expect(@cookbook_repo.updated?('apache2')).to be_truthy
+      expect(@cookbook_repo.updated?("apache2")).to be_truthy
     end
 
     it "commits the changes to the repo and tags the commit" do
@@ -176,11 +176,11 @@ DIRTY
 
   describe "when a custom default branch is specified" do
     before do
-      @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'develop')
+      @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => "develop")
     end
 
     it "resets to default state by checking out the default branch" do
-      expect(@cookbook_repo).to receive(:shell_out!).with('git checkout develop', :cwd => @repo_path)
+      expect(@cookbook_repo).to receive(:shell_out!).with("git checkout develop", :cwd => @repo_path)
       @cookbook_repo.reset_to_default_state
     end
   end
diff --git a/spec/unit/knife/core/custom_manifest_loader_spec.rb b/spec/unit/knife/core/custom_manifest_loader_spec.rb
new file mode 100644
index 0000000..3668fca
--- /dev/null
+++ b/spec/unit/knife/core/custom_manifest_loader_spec.rb
@@ -0,0 +1,41 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Knife::SubcommandLoader::CustomManifestLoader do
+  let(:ec2_server_create_plugin) { "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_server_create.rb" }
+  let(:manifest_content) do
+    { "plugins" => {
+        "knife-ec2" => {
+          "paths" => [
+                      ec2_server_create_plugin
+                     ]
+        }
+      }
+    }
+  end
+  let(:loader) do
+    Chef::Knife::SubcommandLoader::CustomManifestLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands"),
+                                                            manifest_content)
+  end
+
+  it "uses paths from the manifest instead of searching gems" do
+    expect(Gem::Specification).not_to receive(:latest_specs).and_call_original
+    expect(loader.subcommand_files).to include(ec2_server_create_plugin)
+  end
+end
diff --git a/spec/unit/knife/core/gem_glob_loader_spec.rb b/spec/unit/knife/core/gem_glob_loader_spec.rb
new file mode 100644
index 0000000..69a40eb
--- /dev/null
+++ b/spec/unit/knife/core/gem_glob_loader_spec.rb
@@ -0,0 +1,209 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Knife::SubcommandLoader::GemGlobLoader do
+  let(:loader) { Chef::Knife::SubcommandLoader::GemGlobLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands")) }
+  let(:home) { File.join(CHEF_SPEC_DATA, "knife-home") }
+  let(:plugin_dir) { File.join(home, ".chef", "plugins", "knife") }
+
+  before do
+    allow(ChefConfig).to receive(:windows?) { false }
+    Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
+  end
+
+  after do
+    Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
+  end
+
+  it "builds a list of the core subcommand file require paths" do
+    expect(loader.subcommand_files).not_to be_empty
+    loader.subcommand_files.each do |require_path|
+      expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
+    end
+  end
+
+  it "finds files installed via rubygems" do
+    expect(loader.find_subcommands_via_rubygems).to include("chef/knife/node_create")
+    loader.find_subcommands_via_rubygems.each { |rel_path, abs_path| expect(abs_path).to match(%r{chef/knife/.+}) }
+  end
+
+  it "finds files from latest version of installed gems" do
+    gems = [ double("knife-ec2-0.5.12") ]
+    gem_files = [
+      "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_base.rb",
+      "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_otherstuff.rb",
+    ]
+    expect($LOAD_PATH).to receive(:map).and_return([])
+    if Gem::Specification.respond_to? :latest_specs
+      expect(Gem::Specification).to receive(:latest_specs).with(true).and_return(gems)
+      expect(gems[0]).to receive(:matches_for_glob).with(/chef\/knife\/\*\.rb\{(.*),\.rb,(.*)\}/).and_return(gem_files)
+    else
+      expect(Gem.source_index).to receive(:latest_specs).with(true).and_return(gems)
+      expect(gems[0]).to receive(:require_paths).twice.and_return(["lib"])
+      expect(gems[0]).to receive(:full_gem_path).and_return("/usr/lib/ruby/gems/knife-ec2-0.5.12")
+      expect(Dir).to receive(:[]).with("/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb").and_return(gem_files)
+    end
+    expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
+    expect(loader.subcommand_files.select { |file| file =~ /knife-ec2/ }.sort).to eq(gem_files)
+  end
+
+  it "finds files using a dirglob when rubygems is not available" do
+    expect(loader.find_subcommands_via_dirglob).to include("chef/knife/node_create")
+    loader.find_subcommands_via_dirglob.each { |rel_path, abs_path| expect(abs_path).to match(%r{chef/knife/.+}) }
+  end
+
+  it "finds user-specific subcommands in the user's ~/.chef directory" do
+    expected_command = File.join(home, ".chef", "plugins", "knife", "example_home_subcommand.rb")
+    expect(loader.site_subcommands).to include(expected_command)
+  end
+
+  it "finds repo specific subcommands by searching for a .chef directory" do
+    expected_command = File.join(CHEF_SPEC_DATA, "knife-site-subcommands", "plugins", "knife", "example_subcommand.rb")
+    expect(loader.site_subcommands).to include(expected_command)
+  end
+
+  # https://github.com/opscode/chef-dk/issues/227
+  #
+  # `knife` in ChefDK isn't from a gem install, it's directly run from a clone
+  # of the source, but there can be one or more versions of chef also installed
+  # as a gem. If the gem install contains a command that doesn't exist in the
+  # source tree of the "primary" chef install, it can be loaded and cause an
+  # error. We also want to ensure that we only load builtin commands from the
+  # "primary" chef install.
+  context "when a different version of chef is also installed as a gem" do
+
+    let(:all_found_commands) do
+      [
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
+
+        # We use the fake version 1.0.0 because that version doesn't exist,
+        # which ensures it won't ever equal "chef-#{Chef::VERSION}"
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/bootstrap.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_bulk_delete.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_create.rb",
+
+        # Test that we don't accept a version number that is different only in
+        # trailing characters, e.g. we are running Chef 12.0.0 but there is a
+        # Chef 12.0.0.rc.0 gem also:
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0/lib/chef/knife/thing.rb",
+
+        # Test that we ignore the platform suffix when checking for different
+        # gem versions.
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
+        # ...but don't ignore the .rc / .dev parts in the case when we have
+        # platform suffixes
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0-x86-mingw32/lib/chef/knife/invalid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev-mswin32/lib/chef/knife/invalid-too.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.dev.0-x86-mingw64/lib/chef/knife/still-invalid.rb",
+
+        # This command is "extra" compared to what's in the embedded/apps/chef install:
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/data_bag_secret_options.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
+
+        # These are fake commands that have names designed to test that the
+        # regex is strict enough
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
+
+        # In a real scenario, we'd use rubygems APIs to only select the most
+        # recent gem, but for this test we want to check that we're doing the
+        # right thing both when the plugin version matches and does not match
+        # the current chef version. Looking at
+        # `SubcommandLoader::MATCHES_THIS_CHEF_GEM` and
+        # `SubcommandLoader::MATCHES_CHEF_GEM` should make it clear why we want
+        # to test these two cases.
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb",
+      ]
+    end
+
+    let(:expected_valid_commands) do
+      [
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
+        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-x86-mingw32/lib/chef/knife/valid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-i386-mingw64/lib/chef/knife/valid-too.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-mswin32/lib/chef/knife/also-valid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}-universal-mingw32/lib/chef/knife/universal-is-valid.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
+        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb",
+      ]
+    end
+
+    before do
+      expect(loader).to receive(:find_files_latest_gems).with("chef/knife/*.rb").and_return(all_found_commands)
+      expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
+    end
+
+    it "ignores commands from the non-matching gem install" do
+      expect(loader.find_subcommands_via_rubygems.values).to eq(expected_valid_commands)
+    end
+
+  end
+
+  describe "finding 3rd party plugins" do
+    let(:env_home) { "/home/alice" }
+    let(:manifest_path) { env_home + "/.chef/plugin_manifest.json" }
+
+    before do
+      env_dup = ENV.to_hash
+      allow(ENV).to receive(:[]) { |key| env_dup[key] }
+      allow(ENV).to receive(:[]).with("HOME").and_return(env_home)
+    end
+
+    it "searches rubygems for plugins" do
+      if Gem::Specification.respond_to?(:latest_specs)
+        expect(Gem::Specification).to receive(:latest_specs).and_call_original
+      else
+        expect(Gem.source_index).to receive(:latest_specs).and_call_original
+      end
+      loader.subcommand_files.each do |require_path|
+        expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
+      end
+    end
+
+    context "and HOME environment variable is not set" do
+      before do
+        allow(ENV).to receive(:[]).with("HOME").and_return(nil)
+      end
+
+      it "searches rubygems for plugins" do
+        if Gem::Specification.respond_to?(:latest_specs)
+          expect(Gem::Specification).to receive(:latest_specs).and_call_original
+        else
+          expect(Gem.source_index).to receive(:latest_specs).and_call_original
+        end
+        loader.subcommand_files.each do |require_path|
+          expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/knife/core/hashed_command_loader_spec.rb b/spec/unit/knife/core/hashed_command_loader_spec.rb
new file mode 100644
index 0000000..d9f5e57
--- /dev/null
+++ b/spec/unit/knife/core/hashed_command_loader_spec.rb
@@ -0,0 +1,93 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Knife::SubcommandLoader::HashedCommandLoader do
+  before do
+    allow(ChefConfig).to receive(:windows?) { false }
+  end
+
+  let(:plugin_manifest) {
+    {
+      "_autogenerated_command_paths" => {
+        "plugins_paths" => {
+          "cool_a" => ["/file/for/plugin/a"],
+          "cooler_b" => ["/file/for/plugin/b"],
+        },
+        "plugins_by_category" => {
+          "cool" => [
+            "cool_a"
+          ],
+          "cooler" => [
+            "cooler_b"
+          ],
+        },
+      }
+    }
+  }
+
+  let(:loader) { Chef::Knife::SubcommandLoader::HashedCommandLoader.new(
+    File.join(CHEF_SPEC_DATA, "knife-site-subcommands"),
+    plugin_manifest)}
+
+  describe "#list_commands" do
+    it "lists all commands by category when no argument is given" do
+      expect(loader.list_commands).to eq({ "cool" => ["cool_a"], "cooler" => ["cooler_b"] })
+    end
+
+    it "lists only commands in the given category when a category is given" do
+      expect(loader.list_commands("cool")).to eq({ "cool" => ["cool_a"] })
+    end
+  end
+
+  describe "#subcommand_files" do
+    it "lists all the files" do
+      expect(loader.subcommand_files).to eq(["/file/for/plugin/a", "/file/for/plugin/b"])
+    end
+  end
+
+  describe "#load_commands" do
+    before do
+      allow(Kernel).to receive(:load).and_return(true)
+    end
+
+    it "returns false for non-existant commands" do
+      expect(loader.load_command(["nothere"])).to eq(false)
+    end
+
+    it "loads the correct file and returns true if the command exists" do
+      allow(File).to receive(:exists?).and_return(true)
+      expect(Kernel).to receive(:load).with("/file/for/plugin/a").and_return(true)
+      expect(loader.load_command(["cool_a"])).to eq(true)
+    end
+  end
+
+  describe "#subcommand_for_args" do
+    it "returns the subcommands for an exact match" do
+      expect(loader.subcommand_for_args(["cooler_b"])).to eq("cooler_b")
+    end
+
+    it "finds the right subcommand even when _'s are elided" do
+      expect(loader.subcommand_for_args(["cooler", "b"])).to eq("cooler_b")
+    end
+
+    it "returns nil if the the subcommand isn't in our manifest" do
+      expect(loader.subcommand_for_args(["cooler c"])).to eq(nil)
+    end
+  end
+end
diff --git a/spec/unit/knife/core/node_editor_spec.rb b/spec/unit/knife/core/node_editor_spec.rb
new file mode 100644
index 0000000..32ce402
--- /dev/null
+++ b/spec/unit/knife/core/node_editor_spec.rb
@@ -0,0 +1,211 @@
+#
+# Author:: Jordan Running (<jr at chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/core/node_editor"
+
+describe Chef::Knife::NodeEditor do
+  let(:node_data) do
+    { "name" => "test_node",
+      "chef_environment" => "production",
+      "automatic" => { "foo" => "bar" },
+      "default"   => { "alpha" => { "bravo" => "charlie", "delta" => "echo" } },
+      "normal"    => { "alpha" => { "bravo" => "hotel" }, "tags" => [] },
+      "override"  => { "alpha" => { "bravo" => "foxtrot", "delta" => "golf" } },
+      "policy_name"  => nil,
+      "policy_group" => nil,
+      "run_list" => %w{role[comedy] role[drama] recipe[mystery]},
+    }
+  end
+
+  let(:node) { Chef::Node.from_hash(node_data) }
+
+  let(:ui) { double "ui" }
+  let(:base_config) { { editor: "cat" } }
+  let(:config) { base_config.merge(all_attributes: false) }
+
+  subject { described_class.new(node, ui, config) }
+
+  describe '#view' do
+    it "returns a Hash with only the name, chef_environment, normal, " +
+      "policy_name, policy_group, and run_list properties" do
+      expected = node_data.select do |key,|
+        %w{ name chef_environment normal
+            policy_name policy_group run_list }.include?(key)
+      end
+
+      expect(subject.view).to eq(expected)
+    end
+
+    context "when config[:all_attributes] == true" do
+      let(:config) { base_config.merge(all_attributes: true) }
+
+      it 'returns a Hash with all of the node\'s properties' do
+        expect(subject.view).to eq(node_data)
+      end
+    end
+  end
+
+  describe '#apply_updates' do
+    context "when the node name is changed" do
+      before(:each) do
+        allow(ui).to receive(:warn)
+        allow(ui).to receive(:confirm).and_return(true)
+      end
+
+      it "emits a warning and prompts for confirmation" do
+        data = subject.view.merge("name" => "foo_new_name_node")
+        updated_node = subject.apply_updates(data)
+
+        expect(ui).to have_received(:warn)
+          .with "Changing the name of a node results in a new node being " +
+            "created, test_node will not be modified or removed."
+
+        expect(ui).to have_received(:confirm)
+          .with("Proceed with creation of new node")
+
+        expect(updated_node).to be_a(Chef::Node)
+      end
+    end
+
+    context "when config[:all_attributes] == false" do
+      let(:config) { base_config.merge(all_attributes: false) }
+
+      let(:updated_data) do
+        subject.view.merge(
+          "normal" => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+          "policy_name" => "mypolicy",
+          "policy_group" => "prod",
+          "run_list" => %w{role[drama] recipe[mystery]},
+        )
+      end
+
+      it "returns a node with run_list and normal_attrs changed" do
+        updated_node = subject.apply_updates(updated_data)
+        expect(updated_node).to be_a(Chef::Node)
+
+        # Expected to have been changed
+        expect(updated_node.chef_environment).to eql(updated_data["chef_environment"])
+        expect(updated_node.normal_attrs).to eql(updated_data["normal"])
+        expect(updated_node.policy_name).to eql(updated_data["policy_name"])
+        expect(updated_node.policy_group).to eql(updated_data["policy_group"])
+        expect(updated_node.run_list.map(&:to_s)).to eql(updated_data["run_list"])
+
+        # Expected not to have changed
+        expect(updated_node.default_attrs).to eql(node.default_attrs)
+        expect(updated_node.override_attrs).to eql(node.override_attrs)
+        expect(updated_node.automatic_attrs).to eql(node.automatic_attrs)
+      end
+    end
+
+    context "when config[:all_attributes] == true" do
+      let(:config) { base_config.merge(all_attributes: true) }
+
+      let(:updated_data) do
+        subject.view.merge(
+          "default"   => { "alpha" => { "bravo" => "charlie2", "delta" => "echo2" } },
+          "normal"    => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+          "override"  => { "alpha" => { "bravo" => "foxtrot2", "delta" => "golf2" } },
+          "policy_name" => "mypolicy",
+          "policy_group" => "prod",
+          "run_list"  => %w{role[drama] recipe[mystery]},
+        )
+      end
+
+      it "returns a node with all editable properties changed" do
+        updated_node = subject.apply_updates(updated_data)
+        expect(updated_node).to be_a(Chef::Node)
+
+        expect(updated_node.chef_environment).to eql(updated_data["chef_environment"])
+        expect(updated_node.automatic_attrs).to eql(updated_data["automatic"])
+        expect(updated_node.normal_attrs).to eql(updated_data["normal"])
+        expect(updated_node.default_attrs).to eql(updated_data["default"])
+        expect(updated_node.override_attrs).to eql(updated_data["override"])
+        expect(updated_node.policy_name).to eql(updated_data["policy_name"])
+        expect(updated_node.policy_group).to eql(updated_data["policy_group"])
+        expect(updated_node.run_list.map(&:to_s)).to eql(updated_data["run_list"])
+      end
+    end
+  end
+
+  describe '#updated?' do
+    context "before the node has been edited" do
+      it "returns false" do
+        expect(subject.updated?).to be false
+      end
+    end
+
+    context "after the node has been edited" do
+      context "and changes were made" do
+        let(:updated_data) do
+          subject.view.merge(
+            "default"   => { "alpha" => { "bravo" => "charlie2", "delta" => "echo2" } },
+            "normal"    => { "alpha" => { "bravo" => "hotel2" }, "tags" => [ "xyz" ] },
+            "override"  => { "alpha" => { "bravo" => "foxtrot2", "delta" => "golf2" } },
+            "policy_name"  => "mypolicy",
+            "policy_group" => "prod",
+            "run_list"  => %w{role[drama] recipe[mystery]},
+          )
+        end
+
+        context "and changes affect only editable properties" do
+          before(:each) do
+            allow(ui).to receive(:edit_data)
+              .with(subject.view)
+              .and_return(updated_data)
+
+            subject.edit_node
+          end
+
+          it "returns an array of the changed property names" do
+            expect(subject.updated?).to eql %w{ normal policy_name policy_group run_list }
+          end
+        end
+
+        context "and the changes include non-editable properties" do
+          before(:each) do
+            data = updated_data.merge("bad_property" => "bad_value")
+
+            allow(ui).to receive(:edit_data)
+              .with(subject.view)
+              .and_return(data)
+
+            subject.edit_node
+          end
+
+          it 'returns an array of property names that doesn\'t include ' +
+            "the non-editable properties" do
+            expect(subject.updated?).to eql %w{ normal policy_name policy_group run_list }
+          end
+        end
+      end
+
+      context "and changes were not made" do
+        before(:each) do
+          allow(ui).to receive(:edit_data)
+            .with(subject.view)
+            .and_return(subject.view.dup)
+
+          subject.edit_node
+        end
+
+        it { is_expected.not_to be_updated }
+      end
+    end
+  end
+end
diff --git a/spec/unit/knife/core/object_loader_spec.rb b/spec/unit/knife/core/object_loader_spec.rb
index 67fa858..9cabf2b 100644
--- a/spec/unit/knife/core/object_loader_spec.rb
+++ b/spec/unit/knife/core/object_loader_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
 # Author:: Juanje Ojeda (<juanje.ojeda at gmail.com>)
-# Copyright:: Copyright (c) 2011-2012 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/knife/core/object_loader'
+require "spec_helper"
+require "chef/knife/core/object_loader"
 
 describe Chef::Knife::Core::ObjectLoader do
   before(:each) do
     @knife = Chef::Knife.new
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
-    Dir.chdir(File.join(CHEF_SPEC_DATA, 'object_loader'))
+    Dir.chdir(File.join(CHEF_SPEC_DATA, "object_loader"))
   end
 
   shared_examples_for "Chef object" do |chef_class|
@@ -34,14 +34,14 @@ describe Chef::Knife::Core::ObjectLoader do
     end
 
     it "should has a attribute 'name'" do
-      expect(@object.name).to eql('test')
+      expect(@object.name).to eql("test")
     end
   end
 
   {
-    'nodes' => Chef::Node,
-    'roles' => Chef::Role,
-    'environments' => Chef::Environment
+    "nodes" => Chef::Node,
+    "roles" => Chef::Role,
+    "environments" => Chef::Environment,
   }.each do |repo_location, chef_class|
 
     describe "when the file is a #{chef_class}" do
@@ -51,7 +51,7 @@ describe Chef::Knife::Core::ObjectLoader do
 
       describe "when the file is a Ruby" do
         before do
-          @object = @loader.load_from(repo_location, 'test.rb')
+          @object = @loader.load_from(repo_location, "test.rb")
         end
 
         it_behaves_like "Chef object", chef_class
@@ -61,7 +61,7 @@ describe Chef::Knife::Core::ObjectLoader do
       describe "when the file is a JSON" do
         describe "and it has defined 'json_class'" do
           before do
-            @object = @loader.load_from(repo_location, 'test_json_class.json')
+            @object = @loader.load_from(repo_location, "test_json_class.json")
           end
 
           it_behaves_like "Chef object", chef_class
@@ -69,7 +69,7 @@ describe Chef::Knife::Core::ObjectLoader do
 
         describe "and it has not defined 'json_class'" do
           before do
-            @object = @loader.load_from(repo_location, 'test.json')
+            @object = @loader.load_from(repo_location, "test.json")
           end
 
           it_behaves_like "Chef object", chef_class
diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb
index 7f9308b..6cda244 100644
--- a/spec/unit/knife/core/subcommand_loader_spec.rb
+++ b/spec/unit/knife/core/subcommand_loader_spec.rb
@@ -1,6 +1,5 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,209 +15,50 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::SubcommandLoader do
-  let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands')) }
-  let(:home) { File.join(CHEF_SPEC_DATA, 'knife-home') }
-  let(:plugin_dir) { File.join(home, '.chef', 'plugins', 'knife') }
-  
+  let(:loader) { Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, "knife-site-subcommands")) }
+  let(:home) { File.join(CHEF_SPEC_DATA, "knife-home") }
+  let(:plugin_dir) { File.join(home, ".chef", "plugins", "knife") }
+
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
-    Chef::Util::PathHelper.class_variable_set(:@@home_dir, home) 
+    allow(ChefConfig).to receive(:windows?) { false }
+    Chef::Util::PathHelper.class_variable_set(:@@home_dir, home)
   end
 
   after do
-    Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil) 
-  end
-
-  it "builds a list of the core subcommand file require paths" do
-    expect(loader.subcommand_files).not_to be_empty
-    loader.subcommand_files.each do |require_path|
-      expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
-    end
-  end
-
-  it "finds files installed via rubygems" do
-    expect(loader.find_subcommands_via_rubygems).to include('chef/knife/node_create')
-    loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
-  end
-
-  it "finds files from latest version of installed gems" do
-    gems = [ double('knife-ec2-0.5.12') ]
-    gem_files = [
-      '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_base.rb',
-      '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_otherstuff.rb'
-    ]
-    expect($LOAD_PATH).to receive(:map).and_return([])
-    if Gem::Specification.respond_to? :latest_specs
-      expect(Gem::Specification).to receive(:latest_specs).with(true).and_return(gems)
-      expect(gems[0]).to receive(:matches_for_glob).with(/chef\/knife\/\*\.rb\{(.*),\.rb,(.*)\}/).and_return(gem_files)
-    else
-      expect(Gem.source_index).to receive(:latest_specs).with(true).and_return(gems)
-      expect(gems[0]).to receive(:require_paths).twice.and_return(['lib'])
-      expect(gems[0]).to receive(:full_gem_path).and_return('/usr/lib/ruby/gems/knife-ec2-0.5.12')
-      expect(Dir).to receive(:[]).with('/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb').and_return(gem_files)
-    end
-    expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
-    expect(loader.find_subcommands_via_rubygems.values.select { |file| file =~ /knife-ec2/ }.sort).to eq(gem_files)
-  end
-
-  it "finds files using a dirglob when rubygems is not available" do
-    expect(loader.find_subcommands_via_dirglob).to include('chef/knife/node_create')
-    loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| expect(abs_path).to match(%r[chef/knife/.+])}
-  end
-
-  it "finds user-specific subcommands in the user's ~/.chef directory" do
-    expected_command = File.join(home, '.chef', 'plugins', 'knife', 'example_home_subcommand.rb')
-    expect(loader.site_subcommands).to include(expected_command)
-  end
-
-  it "finds repo specific subcommands by searching for a .chef directory" do
-    expected_command = File.join(CHEF_SPEC_DATA, 'knife-site-subcommands', 'plugins', 'knife', 'example_subcommand.rb')
-    expect(loader.site_subcommands).to include(expected_command)
+    Chef::Util::PathHelper.class_variable_set(:@@home_dir, nil)
   end
 
-  # https://github.com/opscode/chef-dk/issues/227
-  #
-  # `knife` in ChefDK isn't from a gem install, it's directly run from a clone
-  # of the source, but there can be one or more versions of chef also installed
-  # as a gem. If the gem install contains a command that doesn't exist in the
-  # source tree of the "primary" chef install, it can be loaded and cause an
-  # error. We also want to ensure that we only load builtin commands from the
-  # "primary" chef install.
-  context "when a different version of chef is also installed as a gem" do
-
-    let(:all_found_commands) do
-      [
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
-
-        # We use the fake version 1.0.0 because that version doesn't exist,
-        # which ensures it won't ever equal "chef-#{Chef::VERSION}"
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/bootstrap.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_bulk_delete.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_create.rb",
-
-        # Test that we don't accept a version number that is different only in
-        # trailing characters, e.g. we are running Chef 12.0.0 but there is a
-        # Chef 12.0.0.rc.0 gem also:
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-#{Chef::VERSION}.rc.0/lib/chef/knife/thing.rb",
-
-        # This command is "extra" compared to what's in the embedded/apps/chef install:
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/data_bag_secret_options.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
-
-        # These are fake commands that have names designed to test that the
-        # regex is strict enough
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
+  let(:config_dir) { File.join(CHEF_SPEC_DATA, "knife-site-subcommands") }
 
-        # In a real scenario, we'd use rubygems APIs to only select the most
-        # recent gem, but for this test we want to check that we're doing the
-        # right thing both when the plugin version matches and does not match
-        # the current chef version. Looking at
-        # `SubcommandLoader::MATCHES_THIS_CHEF_GEM` and
-        # `SubcommandLoader::MATCHES_CHEF_GEM` should make it clear why we want
-        # to test these two cases.
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
-      ]
-    end
-
-    let(:expected_valid_commands) do
-      [
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
-        "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
-        "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
-      ]
-    end
-
-    before do
-      expect(loader).to receive(:find_files_latest_gems).with("chef/knife/*.rb").and_return(all_found_commands)
-      expect(loader).to receive(:find_subcommands_via_dirglob).and_return({})
-    end
-
-    it "ignores commands from the non-matching gem install" do
-      expect(loader.find_subcommands_via_rubygems.values).to eq(expected_valid_commands)
-    end
-
-  end
-
-  describe "finding 3rd party plugins" do
-    let(:home) { "/home/alice" }
-    let(:manifest_path) { home + "/.chef/plugin_manifest.json" }
-
-    context "when there is not a ~/.chef/plugin_manifest.json file" do
+  describe "#for_config" do
+    context "when ~/.chef/plugin_manifest.json exists" do
       before do
-        allow(File).to receive(:exist?).with(manifest_path).and_return(false)
+        allow(File).to receive(:exist?).with(File.join(home, ".chef", "plugin_manifest.json")).and_return(true)
       end
 
-      it "searches rubygems for plugins" do
-        if Gem::Specification.respond_to?(:latest_specs)
-          expect(Gem::Specification).to receive(:latest_specs).and_call_original
-        else
-          expect(Gem.source_index).to receive(:latest_specs).and_call_original
-        end
-        loader.subcommand_files.each do |require_path|
-          expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
-        end
+      it "creates a HashedCommandLoader with the manifest has _autogenerated_command_paths" do
+        allow(File).to receive(:read).with(File.join(home, ".chef", "plugin_manifest.json")).and_return("{ \"_autogenerated_command_paths\": {}}")
+        expect(Chef::Knife::SubcommandLoader.for_config(config_dir)).to be_a Chef::Knife::SubcommandLoader::HashedCommandLoader
       end
 
-      context "and HOME environment variable is not set" do
-        before do
-          allow(Chef::Util::PathHelper).to receive(:home).and_return(nil)
-        end
-
-        it "searches rubygems for plugins" do
-          if Gem::Specification.respond_to?(:latest_specs)
-            expect(Gem::Specification).to receive(:latest_specs).and_call_original
-          else
-            expect(Gem.source_index).to receive(:latest_specs).and_call_original
-          end
-          loader.subcommand_files.each do |require_path|
-            expect(require_path).to match(/chef\/knife\/.*|plugins\/knife\/.*/)
-          end
-        end
+      it "creates a CustomManifestLoader with then manifest has a key other than _autogenerated_command_paths" do
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+        allow(File).to receive(:read).with(File.join(home, ".chef", "plugin_manifest.json")).and_return("{ \"plugins\": {}}")
+        expect(Chef::Knife::SubcommandLoader.for_config(config_dir)).to be_a Chef::Knife::SubcommandLoader::CustomManifestLoader
       end
-
     end
 
-    context "when there is a ~/.chef/plugin_manifest.json file" do
-      let(:ec2_server_create_plugin) { "/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_server_create.rb" }
-
-      let(:manifest_content) do
-        { "plugins" => {
-            "knife-ec2" => {
-              "paths" => [
-                ec2_server_create_plugin
-              ]
-            }
-          }
-        }
-      end
-
-      let(:manifest_json) { Chef::JSONCompat.to_json(manifest_content) }
-
+    context "when ~/.chef/plugin_manifest.json does not exist" do
       before do
-        allow(File).to receive(:exist?).with(manifest_path).and_return(true)
-        allow(File).to receive(:read).with(manifest_path).and_return(manifest_json)
+        allow(File).to receive(:exist?).with(File.join(home, ".chef", "plugin_manifest.json")).and_return(false)
       end
 
-      it "uses paths from the manifest instead of searching gems" do
-        expect(Gem::Specification).not_to receive(:latest_specs).and_call_original
-        expect(loader.subcommand_files).to include(ec2_server_create_plugin)
+      it "creates a GemGlobLoader" do
+        expect(Chef::Knife::SubcommandLoader.for_config(config_dir)).to be_a Chef::Knife::SubcommandLoader::GemGlobLoader
       end
-
     end
   end
-
 end
diff --git a/spec/unit/knife/core/ui_spec.rb b/spec/unit/knife/core/ui_spec.rb
index ac42ad6..d2381f6 100644
--- a/spec/unit/knife/core/ui_spec.rb
+++ b/spec/unit/knife/core/ui_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011, 2012 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UI do
   before do
@@ -33,10 +33,10 @@ describe Chef::Knife::UI do
   end
 
   describe "edit" do
-    ruby_for_json = { 'foo' => 'bar' }
+    ruby_for_json = { "foo" => "bar" }
     json_from_ruby = "{\n  \"foo\": \"bar\"\n}"
     json_from_editor = "{\n  \"bar\": \"foo\"\n}"
-    ruby_from_editor = { 'bar' => 'foo' }
+    ruby_from_editor = { "bar" => "foo" }
     my_editor = "veeeye"
     temp_path = "/tmp/bar/baz"
 
@@ -46,7 +46,7 @@ describe Chef::Knife::UI do
     context "when editing is disabled" do
       before do
         @ui.config[:disable_editing] = true
-        stub_const("Tempfile", double)  # Tempfiles should never be invoked
+        stub_const("Tempfile", double) # Tempfiles should never be invoked
       end
       context "when parse_output is false" do
         it "returns pretty json string" do
@@ -66,12 +66,12 @@ describe Chef::Knife::UI do
       before do
         @ui.config[:disable_editing] = false
         @ui.config[:editor] = my_editor
-        @mock = double('Tempfile')
+        @mock = double("Tempfile")
         expect(@mock).to receive(:sync=).with(true)
         expect(@mock).to receive(:puts).with(json_from_ruby)
         expect(@mock).to receive(:close)
         expect(@mock).to receive(:path).at_least(:once).and_return(temp_path)
-        expect(Tempfile).to receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@mock)
+        expect(Tempfile).to receive(:open).with([ "knife-edit-", ".json" ]).and_yield(@mock)
       end
       context "and the editor works" do
         before do
@@ -97,7 +97,7 @@ describe Chef::Knife::UI do
           expect(IO).not_to receive(:read)
         end
         it "throws an exception" do
-          expect{ subject }.to raise_error(RuntimeError)
+          expect { subject }.to raise_error(RuntimeError)
         end
       end
       context "when running the editor fails with false" do
@@ -106,7 +106,7 @@ describe Chef::Knife::UI do
           expect(IO).not_to receive(:read)
         end
         it "throws an exception" do
-          expect{ subject }.to raise_error(RuntimeError)
+          expect { subject }.to raise_error(RuntimeError)
         end
       end
     end
@@ -114,8 +114,8 @@ describe Chef::Knife::UI do
       before do
         @ui.config[:disable_editing] = false
         @ui.config[:editor] = my_editor
-        @tempfile = Tempfile.new([ 'knife-edit-', '.json' ])
-        expect(Tempfile).to receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@tempfile)
+        @tempfile = Tempfile.new([ "knife-edit-", ".json" ])
+        expect(Tempfile).to receive(:open).with([ "knife-edit-", ".json" ]).and_yield(@tempfile)
       end
 
       context "and the editor works" do
@@ -166,20 +166,20 @@ describe Chef::Knife::UI do
     it "should throw Errno::EIO exceptions" do
       allow(@out).to receive(:puts).and_raise(Errno::EIO)
       allow(@err).to receive(:puts).and_raise(Errno::EIO)
-      expect {@ui.send(method, "hi")}.to raise_error(Errno::EIO)
+      expect { @ui.send(method, "hi") }.to raise_error(Errno::EIO)
     end
 
     it "should ignore Errno::EPIPE exceptions (CHEF-3516)" do
       allow(@out).to receive(:puts).and_raise(Errno::EPIPE)
       allow(@err).to receive(:puts).and_raise(Errno::EPIPE)
-      expect {@ui.send(method, "hi")}.to raise_error(SystemExit)
+      expect { @ui.send(method, "hi") }.to raise_error(SystemExit)
     end
 
     it "should throw Errno::EPIPE exceptions with -VV (CHEF-3516)" do
       @config[:verbosity] = 2
       allow(@out).to receive(:puts).and_raise(Errno::EPIPE)
       allow(@err).to receive(:puts).and_raise(Errno::EPIPE)
-      expect {@ui.send(method, "hi")}.to raise_error(Errno::EPIPE)
+      expect { @ui.send(method, "hi") }.to raise_error(Errno::EPIPE)
     end
   end
 
@@ -192,7 +192,7 @@ describe Chef::Knife::UI do
     end
 
     it "formats hashes appropriately" do
-      @ui.output({'hi' => 'a', 'lo' => 'b' })
+      @ui.output({ "hi" => "a", "lo" => "b" })
       expect(@out.string).to eq <<EOM
 hi: a
 lo: b
@@ -205,7 +205,7 @@ EOM
     end
 
     it "formats arrays appropriately" do
-      @ui.output([ 'a', 'b' ])
+      @ui.output([ "a", "b" ])
       expect(@out.string).to eq <<EOM
 a
 b
@@ -218,17 +218,17 @@ EOM
     end
 
     it "formats single-member arrays appropriately" do
-      @ui.output([ 'a' ])
+      @ui.output([ "a" ])
       expect(@out.string).to eq("a\n")
     end
 
     it "formats nested single-member arrays appropriately" do
-      @ui.output([ [ 'a' ] ])
+      @ui.output([ [ "a" ] ])
       expect(@out.string).to eq("a\n")
     end
 
     it "formats nested arrays appropriately" do
-      @ui.output([ [ 'a', 'b' ], [ 'c', 'd' ]])
+      @ui.output([ [ "a", "b" ], [ "c", "d" ]])
       expect(@out.string).to eq <<EOM
 a
 b
@@ -239,7 +239,7 @@ EOM
     end
 
     it "formats nested arrays with single- and empty subarrays appropriately" do
-      @ui.output([ [ 'a', 'b' ], [ 'c' ], [], [ 'd', 'e' ]])
+      @ui.output([ [ "a", "b" ], [ "c" ], [], [ "d", "e" ]])
       expect(@out.string).to eq <<EOM
 a
 b
@@ -253,7 +253,7 @@ EOM
     end
 
     it "formats arrays of hashes with extra lines in between for readability" do
-      @ui.output([ { 'a' => 'b', 'c' => 'd' }, { 'x' => 'y' }, { 'm' => 'n', 'o' => 'p' }])
+      @ui.output([ { "a" => "b", "c" => "d" }, { "x" => "y" }, { "m" => "n", "o" => "p" }])
       expect(@out.string).to eq <<EOM
 a: b
 c: d
@@ -266,7 +266,7 @@ EOM
     end
 
     it "formats hashes with empty array members appropriately" do
-      @ui.output({ 'a' => [], 'b' => 'c' })
+      @ui.output({ "a" => [], "b" => "c" })
       expect(@out.string).to eq <<EOM
 a:
 b: c
@@ -274,7 +274,7 @@ EOM
     end
 
     it "formats hashes with single-member array values appropriately" do
-      @ui.output({ 'a' => [ 'foo' ], 'b' => 'c' })
+      @ui.output({ "a" => [ "foo" ], "b" => "c" })
       expect(@out.string).to eq <<EOM
 a: foo
 b: c
@@ -282,7 +282,7 @@ EOM
     end
 
     it "formats hashes with array members appropriately" do
-      @ui.output({ 'a' => [ 'foo', 'bar' ], 'b' => 'c' })
+      @ui.output({ "a" => [ "foo", "bar" ], "b" => "c" })
       expect(@out.string).to eq <<EOM
 a:
   foo
@@ -292,7 +292,7 @@ EOM
     end
 
     it "formats hashes with single-member nested array values appropriately" do
-      @ui.output({ 'a' => [ [ 'foo' ] ], 'b' => 'c' })
+      @ui.output({ "a" => [ [ "foo" ] ], "b" => "c" })
       expect(@out.string).to eq <<EOM
 a:
   foo
@@ -301,14 +301,14 @@ EOM
     end
 
     it "formats hashes with nested array values appropriately" do
-      @ui.output({ 'a' => [ [ 'foo', 'bar' ], [ 'baz', 'bjork' ] ], 'b' => 'c' })
+      @ui.output({ "a" => [ [ "foo", "bar" ], [ "baz", "bjork" ] ], "b" => "c" })
       # XXX: using a HEREDOC at this point results in a line with required spaces which auto-whitespace removal settings
       # on editors will remove and will break this test.
       expect(@out.string).to eq("a:\n  foo\n  bar\n  \n  baz\n  bjork\nb: c\n")
     end
 
     it "formats hashes with hash values appropriately" do
-      @ui.output({ 'a' => { 'aa' => 'bb', 'cc' => 'dd' }, 'b' => 'c' })
+      @ui.output({ "a" => { "aa" => "bb", "cc" => "dd" }, "b" => "c" })
       expect(@out.string).to eq <<EOM
 a:
   aa: bb
@@ -318,7 +318,7 @@ EOM
     end
 
     it "formats hashes with empty hash values appropriately" do
-      @ui.output({ 'a' => { }, 'b' => 'c' })
+      @ui.output({ "a" => {}, "b" => "c" })
       expect(@out.string).to eq <<EOM
 a:
 b: c
@@ -354,7 +354,7 @@ EOM
       it "should return multiple attributes" do
         input = { "gi" =>  "go", "hi" => "ho", "id" => "sample-data-bag-item" }
         @ui.config[:attribute] = ["gi", "hi"]
-        expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "gi" => "go", "hi"=> "ho" } })
+        expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "gi" => "go", "hi" => "ho" } })
       end
 
       it "should handle attributes named the same as methods" do
@@ -364,10 +364,24 @@ EOM
       end
 
       it "should handle nested attributes named the same as methods" do
-        input = { "keys" =>  {"keys" => "values"}, "hi" => "ho", "id" => "sample-data-bag-item" }
+        input = { "keys" =>  { "keys" => "values" }, "hi" => "ho", "id" => "sample-data-bag-item" }
         @ui.config[:attribute] = "keys.keys"
         expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { "keys.keys" => "values" } })
       end
+
+      it "should return the name attribute" do
+        allow_any_instance_of(Chef::Node).to receive(:name).and_return("chef.localdomain")
+        input = Chef::Node.new
+        @ui.config[:attribute] = "name"
+        expect(@ui.format_for_display(input)).to eq( { "chef.localdomain" => { "name" => "chef.localdomain" } })
+      end
+
+      it "returns nil when given an attribute path that isn't a name or attribute" do
+        input = { "keys" =>  { "keys" => "values" }, "hi" => "ho", "id" => "sample-data-bag-item" }
+        non_existing_path = "nope.nada.nothingtoseehere"
+        @ui.config[:attribute] = non_existing_path
+        expect(@ui.format_for_display(input)).to eq({ "sample-data-bag-item" => { non_existing_path => nil } })
+      end
     end
 
     describe "with --run-list passed" do
@@ -391,8 +405,8 @@ EOM
           "versions" => [
             { "version" => "3.0.0", "url" => "http://url/cookbooks/3.0.0" },
             { "version" => "2.0.0", "url" => "http://url/cookbooks/2.0.0" },
-            { "version" => "1.0.0", "url" => "http://url/cookbooks/1.0.0" }
-          ]
+            { "version" => "1.0.0", "url" => "http://url/cookbooks/1.0.0" },
+          ],
         }
       }
     end
@@ -406,10 +420,10 @@ EOM
     describe "with --with-uri" do
       it "should return the URIs" do
         response = {
-          "cookbook_name"=>{
+          "cookbook_name" => {
             "1.0.0" => "http://url/cookbooks/1.0.0",
             "2.0.0" => "http://url/cookbooks/2.0.0",
-            "3.0.0" => "http://url/cookbooks/3.0.0"}
+            "3.0.0" => "http://url/cookbooks/3.0.0" }
         }
         @ui.config[:with_uri] = true
         expect(@ui.format_cookbook_list_for_display(@item)).to eq(response)
@@ -418,9 +432,9 @@ EOM
 
     context "when running on Windows" do
       before(:each) do
-        stdout = double('StringIO', :tty? => true)
+        stdout = double("StringIO", :tty? => true)
         allow(@ui).to receive(:stdout).and_return(stdout)
-        allow(Chef::Platform).to receive(:windows?) { true }
+        allow(ChefConfig).to receive(:windows?) { true }
         Chef::Config.reset
       end
 
@@ -446,11 +460,11 @@ EOM
   end
 
   describe "confirm" do
-    let(:stdout) {StringIO.new}
-    let(:output) {stdout.string}
+    let(:stdout) { StringIO.new }
+    let(:output) { stdout.string }
 
     let(:question) { "monkeys rule" }
-    let(:answer) { 'y' }
+    let(:answer) { "y" }
 
     let(:default_choice) { nil }
     let(:append_instructions) { true }
@@ -569,7 +583,7 @@ EOM
       out = StringIO.new
       allow(@ui).to receive(:stdout).and_return(out)
       allow(@ui).to receive(:stdin).and_return(StringIO.new(" \n"))
-      expect(@ui.ask_question("your chef server URL? ", :default => 'http://localhost:4000')).to eq("http://localhost:4000")
+      expect(@ui.ask_question("your chef server URL? ", :default => "http://localhost:4000")).to eq("http://localhost:4000")
       expect(out.string).to eq("your chef server URL? [http://localhost:4000] ")
     end
   end
diff --git a/spec/unit/knife/data_bag_create_spec.rb b/spec/unit/knife/data_bag_create_spec.rb
index c31c885..b852c30 100644
--- a/spec/unit/knife/data_bag_create_spec.rb
+++ b/spec/unit/knife/data_bag_create_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2009-2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
 
 describe Chef::Knife::DataBagCreate do
   let(:knife) do
@@ -28,7 +28,7 @@ describe Chef::Knife::DataBagCreate do
     k
   end
 
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
   let(:stdout) { StringIO.new }
 
   let(:bag_name) { "sudoing_admins" }
@@ -36,7 +36,7 @@ describe Chef::Knife::DataBagCreate do
 
   let(:secret) { "abc123SECRET" }
 
-  let(:raw_hash)  {{ "login_name" => "alphaomega", "id" => item_name }}
+  let(:raw_hash) { { "login_name" => "alphaomega", "id" => item_name } }
 
   let(:config) { {} }
 
@@ -47,9 +47,9 @@ describe Chef::Knife::DataBagCreate do
   end
 
   it "tries to create a data bag with an invalid name when given one argument" do
-    knife.name_args = ['invalid&char']
+    knife.name_args = ["invalid&char"]
     expect(Chef::DataBag).to receive(:validate_name!).with(knife.name_args[0]).and_raise(Chef::Exceptions::InvalidDataBagName)
-    expect {knife.run}.to exit_with_code(1)
+    expect { knife.run }.to exit_with_code(1)
   end
 
   context "when given one argument" do
@@ -58,7 +58,7 @@ describe Chef::Knife::DataBagCreate do
     end
 
     it "creates a data bag" do
-      expect(rest).to receive(:post_rest).with("data", {"name" => bag_name})
+      expect(rest).to receive(:post).with("data", { "name" => bag_name })
       expect(knife.ui).to receive(:info).with("Created data_bag[#{bag_name}]")
 
       knife.run
@@ -75,8 +75,8 @@ describe Chef::Knife::DataBagCreate do
     it "creates a data bag item" do
       expect(knife).to receive(:create_object).and_yield(raw_hash)
       expect(knife).to receive(:encryption_secret_provided?).and_return(false)
-      expect(rest).to receive(:post_rest).with("data", {'name' => bag_name}).ordered
-      expect(rest).to receive(:post_rest).with("data/#{bag_name}", item).ordered
+      expect(rest).to receive(:post).with("data", { "name" => bag_name }).ordered
+      expect(rest).to receive(:post).with("data/#{bag_name}", item).ordered
 
       knife.run
     end
@@ -99,8 +99,8 @@ describe Chef::Knife::DataBagCreate do
         .to receive(:encrypt_data_bag_item)
         .with(raw_hash, secret)
         .and_return(encoded_data)
-      expect(rest).to receive(:post_rest).with("data", {"name" => bag_name}).ordered
-      expect(rest).to receive(:post_rest).with("data/#{bag_name}", item).ordered
+      expect(rest).to receive(:post).with("data", { "name" => bag_name }).ordered
+      expect(rest).to receive(:post).with("data/#{bag_name}", item).ordered
 
       knife.run
     end
diff --git a/spec/unit/knife/data_bag_edit_spec.rb b/spec/unit/knife/data_bag_edit_spec.rb
index 6f19b5e..1001e68 100644
--- a/spec/unit/knife/data_bag_edit_spec.rb
+++ b/spec/unit/knife/data_bag_edit_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
 
 describe Chef::Knife::DataBagEdit do
   before do
@@ -33,11 +33,11 @@ describe Chef::Knife::DataBagEdit do
     k
   end
 
-  let(:raw_hash) { {"login_name" => "alphaomega", "id" => "item_name"} }
-  let(:db) { Chef::DataBagItem.from_hash(raw_hash)}
-  let(:raw_edited_hash) { {"login_name" => "rho", "id" => "item_name", "new_key" => "new_value"} }
+  let(:raw_hash) { { "login_name" => "alphaomega", "id" => "item_name" } }
+  let(:db) { Chef::DataBagItem.from_hash(raw_hash) }
+  let(:raw_edited_hash) { { "login_name" => "rho", "id" => "item_name", "new_key" => "new_value" } }
 
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
   let(:stdout) { StringIO.new }
 
   let(:bag_name) { "sudoing_admins" }
@@ -56,7 +56,7 @@ describe Chef::Knife::DataBagEdit do
       expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(db)
       expect(knife).to receive(:encrypted?).with(db.raw_data).and_return(is_encrypted?)
       expect(knife).to receive(:edit_data).with(data_to_edit).and_return(raw_edited_hash)
-      expect(rest).to receive(:put_rest).with("data/#{bag_name}/#{item_name}", transmitted_hash).ordered
+      expect(rest).to receive(:put).with("data/#{bag_name}/#{item_name}", transmitted_hash).ordered
 
       knife.run
     end
@@ -65,7 +65,7 @@ describe Chef::Knife::DataBagEdit do
   it "requires data bag and item arguments" do
     knife.name_args = []
     expect(stdout).to receive(:puts).twice.with(anything)
-    expect {knife.run}.to exit_with_code(1)
+    expect { knife.run }.to exit_with_code(1)
     expect(stdout.string).to eq("")
   end
 
@@ -74,7 +74,7 @@ describe Chef::Knife::DataBagEdit do
   end
 
   context "when config[:print_after] is set" do
-    let(:config) { {:print_after => true} }
+    let(:config) { { :print_after => true } }
     before do
       expect(knife.ui).to receive(:output).with(raw_edited_hash)
     end
@@ -121,7 +121,7 @@ describe Chef::Knife::DataBagEdit do
     expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
 
     expect(knife.ui).to receive(:fatal).with("You cannot edit an encrypted data bag without providing the secret.")
-    expect {knife.run}.to exit_with_code(1)
+    expect { knife.run }.to exit_with_code(1)
   end
 
 end
diff --git a/spec/unit/knife/data_bag_from_file_spec.rb b/spec/unit/knife/data_bag_from_file_spec.rb
index 3882bff..0b6f389 100644
--- a/spec/unit/knife/data_bag_from_file_spec.rb
+++ b/spec/unit/knife/data_bag_from_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'tempfile'
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "tempfile"
 
 Chef::Knife::DataBagFromFile.load_deps
 
 describe Chef::Knife::DataBagFromFile do
   before :each do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
     Chef::Config[:node_name] = "webmonkey.example.com"
     FileUtils.mkdir_p([db_folder, db_folder2])
     db_file.write(Chef::JSONCompat.to_json(plain_data))
@@ -75,11 +75,11 @@ describe Chef::Knife::DataBagFromFile do
   let(:plain_data) { {
       "id" => "item_name",
       "greeting" => "hello",
-      "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }}
+      "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true } },
   } }
   let(:enc_data) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(plain_data, secret) }
 
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
   let(:stdout) { StringIO.new }
 
   let(:bag_name) { "sudoing_admins" }
@@ -164,7 +164,7 @@ describe Chef::Knife::DataBagFromFile do
   describe "command line parsing" do
     it "prints help if given no arguments" do
       knife.name_args = [bag_name]
-      expect {knife.run}.to exit_with_code(1)
+      expect { knife.run }.to exit_with_code(1)
       expect(stdout.string).to start_with("knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)")
     end
   end
diff --git a/spec/unit/knife/data_bag_secret_options_spec.rb b/spec/unit/knife/data_bag_secret_options_spec.rb
index 0a2d8ca..2f4d8c8 100644
--- a/spec/unit/knife/data_bag_secret_options_spec.rb
+++ b/spec/unit/knife/data_bag_secret_options_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at opscode.com>)
-# Copyright:: Copyright (c) 2009-2014 Opscode, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/knife'
-require 'chef/config'
-require 'tempfile'
+require "spec_helper"
+require "chef/knife"
+require "chef/config"
+require "tempfile"
 
 class ExampleDataBagCommand < Chef::Knife
   include Chef::Knife::DataBagSecretOptions
diff --git a/spec/unit/knife/data_bag_show_spec.rb b/spec/unit/knife/data_bag_show_spec.rb
index 1125d99..4637e34 100644
--- a/spec/unit/knife/data_bag_show_spec.rb
+++ b/spec/unit/knife/data_bag_show_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2008-2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/data_bag_item'
-require 'chef/encrypted_data_bag_item'
-require 'chef/json_compat'
-require 'tempfile'
+require "chef/data_bag_item"
+require "chef/encrypted_data_bag_item"
+require "chef/json_compat"
+require "tempfile"
 
 describe Chef::Knife::DataBagShow do
 
@@ -39,16 +39,16 @@ describe Chef::Knife::DataBagShow do
     k
   end
 
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
   let(:stdout) { StringIO.new }
 
   let(:bag_name) { "sudoing_admins" }
   let(:item_name) { "ME" }
 
-  let(:data_bag_contents) { { "id" => "id", "baz"=>"http://localhost:4000/data/bag_o_data/baz",
-                        "qux"=>"http://localhost:4000/data/bag_o_data/qux"} }
-  let(:enc_hash) {Chef::EncryptedDataBagItem.encrypt_data_bag_item(data_bag_contents, secret)}
-  let(:data_bag) {Chef::DataBagItem.from_hash(data_bag_contents)}
+  let(:data_bag_contents) { { "id" => "id", "baz" => "http://localhost:4000/data/bag_o_data/baz",
+                              "qux" => "http://localhost:4000/data/bag_o_data/qux" } }
+  let(:enc_hash) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(data_bag_contents, secret) }
+  let(:data_bag) { Chef::DataBagItem.from_hash(data_bag_contents) }
   let(:data_bag_with_encoded_hash) { Chef::DataBagItem.from_hash(enc_hash) }
   let(:enc_data_bag) { Chef::EncryptedDataBagItem.new(enc_hash, secret) }
 
@@ -56,7 +56,7 @@ describe Chef::Knife::DataBagShow do
   #
   # let(:raw_hash)  {{ "login_name" => "alphaomega", "id" => item_name }}
   #
-  let(:config) { {format: "json"} }
+  let(:config) { { format: "json" } }
 
   context "Data bag to show is encrypted" do
     before do
@@ -70,9 +70,9 @@ describe Chef::Knife::DataBagShow do
       expect(knife.ui).to receive(:info).with("Encrypted data bag detected, decrypting with provided secret.")
       expect(Chef::EncryptedDataBagItem).to receive(:load).with(bag_name, item_name, secret).and_return(enc_data_bag)
 
-      expected = %q|baz: http://localhost:4000/data/bag_o_data/baz
+      expected = %q{baz: http://localhost:4000/data/bag_o_data/baz
 id:  id
-qux: http://localhost:4000/data/bag_o_data/qux|
+qux: http://localhost:4000/data/bag_o_data/qux}
       knife.run
       expect(stdout.string.strip).to eq(expected)
     end
@@ -97,9 +97,9 @@ qux: http://localhost:4000/data/bag_o_data/qux|
       expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(data_bag)
       expect(knife.ui).to receive(:info).with("Unencrypted data bag detected, ignoring any provided secret options.")
 
-      expected = %q|baz: http://localhost:4000/data/bag_o_data/baz
+      expected = %q{baz: http://localhost:4000/data/bag_o_data/baz
 id:  id
-qux: http://localhost:4000/data/bag_o_data/qux|
+qux: http://localhost:4000/data/bag_o_data/qux}
       knife.run
       expect(stdout.string.strip).to eq(expected)
     end
@@ -116,7 +116,7 @@ qux: http://localhost:4000/data/bag_o_data/qux|
   it "raises an error when no @name_args are provided" do
     knife.name_args = []
 
-    expect {knife.run}.to exit_with_code(1)
+    expect { knife.run }.to exit_with_code(1)
     expect(stdout.string).to start_with("knife data bag show BAG [ITEM] (options)")
   end
 
diff --git a/spec/unit/knife/environment_compare_spec.rb b/spec/unit/knife/environment_compare_spec.rb
index 6d4d3ea..7a34119 100644
--- a/spec/unit/knife/environment_compare_spec.rb
+++ b/spec/unit/knife/environment_compare_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Sander Botman (<sbotman at schubergphilis.com>)
-# Copyright:: Copyright (c) 2013 Sander Botman.
+# Copyright:: Copyright 2013-2016, Sander Botman.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,66 +16,66 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentCompare do
   before(:each) do
     @knife = Chef::Knife::EnvironmentCompare.new
-    
+
     @environments = {
       "cita" => "http://localhost:4000/environments/cita",
-      "citm" => "http://localhost:4000/environments/citm"
+      "citm" => "http://localhost:4000/environments/citm",
     }
 
     allow(@knife).to receive(:environment_list).and_return(@environments)
 
     @constraints = {
       "cita" => { "foo" => "= 1.0.1", "bar" => "= 0.0.4" },
-      "citm" => { "foo" => "= 1.0.1", "bar" => "= 0.0.2" }
+      "citm" => { "foo" => "= 1.0.1", "bar" => "= 0.0.2" },
     }
- 
+
     allow(@knife).to receive(:constraint_list).and_return(@constraints)
 
-    @cookbooks = { "foo"=>"= 1.0.1", "bar"=>"= 0.0.1" } 
+    @cookbooks = { "foo" => "= 1.0.1", "bar" => "= 0.0.1" }
 
     allow(@knife).to receive(:cookbook_list).and_return(@cookbooks)
 
-    @rest_double = double('rest')
+    @rest_double = double("rest")
     allow(@knife).to receive(:rest).and_return(@rest_double)
-    @cookbook_names = ['apache2', 'mysql', 'foo', 'bar', 'dummy', 'chef_handler']
-    @base_url = 'https://server.example.com/cookbooks'
+    @cookbook_names = ["apache2", "mysql", "foo", "bar", "dummy", "chef_handler"]
+    @base_url = "https://server.example.com/cookbooks"
     @cookbook_data = {}
     @cookbook_names.each do |item|
-      @cookbook_data[item] = {'url' => "#{@base_url}/#{item}",
-                              'versions' => [{'version' => '1.0.1',
-                                              'url' => "#{@base_url}/#{item}/1.0.1"}]}
-    end 
+      @cookbook_data[item] = { "url" => "#{@base_url}/#{item}",
+                               "versions" => [{ "version" => "1.0.1",
+                                                "url" => "#{@base_url}/#{item}/1.0.1" }] }
+    end
 
-    allow(@rest_double).to receive(:get_rest).with("/cookbooks?num_versions=1").and_return(@cookbook_data)
+    allow(@rest_double).to receive(:get).with("/cookbooks?num_versions=1").and_return(@cookbook_data)
 
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
   end
 
-  describe 'run' do
-    it 'should display only cookbooks with version constraints' do
-      @knife.config[:format] = 'summary'
+  describe "run" do
+    it "should display only cookbooks with version constraints" do
+      @knife.config[:format] = "summary"
       @knife.run
       @environments.each do |item, url|
         expect(@stdout.string).to match /#{item}/ and expect(@stdout.string.lines.count).to be 4
       end
     end
- 
-    it 'should display 4 number of lines' do
-      @knife.config[:format] = 'summary'
+
+    it "should display 4 number of lines" do
+      @knife.config[:format] = "summary"
       @knife.run
       expect(@stdout.string.lines.count).to be 4
     end
   end
 
-  describe 'with -m or --mismatch' do
-    it 'should display only cookbooks that have mismatching version constraints' do
-      @knife.config[:format] = 'summary'
+  describe "with -m or --mismatch" do
+    it "should display only cookbooks that have mismatching version constraints" do
+      @knife.config[:format] = "summary"
       @knife.config[:mismatch] = true
       @knife.run
       @constraints.each do |item, ver|
@@ -83,17 +83,17 @@ describe Chef::Knife::EnvironmentCompare do
       end
     end
 
-    it 'should display 3 number of lines' do
-      @knife.config[:format] = 'summary'
+    it "should display 3 number of lines" do
+      @knife.config[:format] = "summary"
       @knife.config[:mismatch] = true
       @knife.run
       expect(@stdout.string.lines.count).to be 3
     end
   end
- 
-  describe 'with -a or --all' do
-    it 'should display all cookbooks' do
-      @knife.config[:format] = 'summary'
+
+  describe "with -a or --all" do
+    it "should display all cookbooks" do
+      @knife.config[:format] = "summary"
       @knife.config[:all] = true
       @knife.run
       @constraints.each do |item, ver|
@@ -101,8 +101,8 @@ describe Chef::Knife::EnvironmentCompare do
       end
     end
 
-    it 'should display 8 number of lines' do
-      @knife.config[:format] = 'summary'
+    it "should display 8 number of lines" do
+      @knife.config[:format] = "summary"
       @knife.config[:all] = true
       @knife.run
       expect(@stdout.string.lines.count).to be 8
diff --git a/spec/unit/knife/environment_create_spec.rb b/spec/unit/knife/environment_create_spec.rb
index 04e4504..6e6e085 100644
--- a/spec/unit/knife/environment_create_spec.rb
+++ b/spec/unit/knife/environment_create_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentCreate do
   before(:each) do
diff --git a/spec/unit/knife/environment_delete_spec.rb b/spec/unit/knife/environment_delete_spec.rb
index 95df6e1..307a619 100644
--- a/spec/unit/knife/environment_delete_spec.rb
+++ b/spec/unit/knife/environment_delete_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentDelete do
   before(:each) do
diff --git a/spec/unit/knife/environment_edit_spec.rb b/spec/unit/knife/environment_edit_spec.rb
index 61c2663..6ec4965 100644
--- a/spec/unit/knife/environment_edit_spec.rb
+++ b/spec/unit/knife/environment_edit_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentEdit do
   before(:each) do
diff --git a/spec/unit/knife/environment_from_file_spec.rb b/spec/unit/knife/environment_from_file_spec.rb
index d150e5e..4505da3 100644
--- a/spec/unit/knife/environment_from_file_spec.rb
+++ b/spec/unit/knife/environment_from_file_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
 # Author:: Seth Falcon (<seth at ospcode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::EnvironmentFromFile.load_deps
 
 describe Chef::Knife::EnvironmentFromFile do
   before(:each) do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
     @knife = Chef::Knife::EnvironmentFromFile.new
     @stdout = StringIO.new
     allow(@knife.ui).to receive(:stdout).and_return(@stdout)
@@ -32,14 +32,14 @@ describe Chef::Knife::EnvironmentFromFile do
     @environment = Chef::Environment.new
     @environment.name("spec")
     @environment.description("runs the unit tests")
-    @environment.cookbook_versions({"apt" => "= 1.2.3"})
+    @environment.cookbook_versions({ "apt" => "= 1.2.3" })
     allow(@environment).to receive(:save).and_return true
     allow(@knife.loader).to receive(:load_from).and_return @environment
   end
 
   describe "run" do
     it "loads the environment data from a file and saves it" do
-      expect(@knife.loader).to receive(:load_from).with('environments', 'spec.rb').and_return(@environment)
+      expect(@knife.loader).to receive(:load_from).with("environments", "spec.rb").and_return(@environment)
       expect(@environment).to receive(:save)
       @knife.run
     end
@@ -61,7 +61,7 @@ describe Chef::Knife::EnvironmentFromFile do
         allow(File).to receive(:expand_path).with("./environments/").and_return("/tmp/environments")
         allow(Dir).to receive(:glob).with("/tmp/environments/*.{json,rb}").and_return(["spec.rb", "apple.rb"])
         @knife.name_args = []
-        allow(@knife).to receive(:config).and_return({:all => true})
+        allow(@knife).to receive(:config).and_return({ :all => true })
         expect(@environment).to receive(:save).twice
         @knife.run
       end
diff --git a/spec/unit/knife/environment_list_spec.rb b/spec/unit/knife/environment_list_spec.rb
index 6488a07..636b322 100644
--- a/spec/unit/knife/environment_list_spec.rb
+++ b/spec/unit/knife/environment_list_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentList do
   before(:each) do
@@ -28,7 +28,7 @@ describe Chef::Knife::EnvironmentList do
     @environments = {
       "production" => "http://localhost:4000/environments/production",
       "development" => "http://localhost:4000/environments/development",
-      "testing" => "http://localhost:4000/environments/testing"
+      "testing" => "http://localhost:4000/environments/testing",
     }
     allow(Chef::Environment).to receive(:list).and_return @environments
   end
@@ -39,7 +39,7 @@ describe Chef::Knife::EnvironmentList do
   end
 
   it "should print the environment names in a sorted list" do
-    names = @environments.keys.sort { |a,b| a <=> b }
+    names = @environments.keys.sort { |a, b| a <=> b }
     expect(@knife).to receive(:output).with(names)
     @knife.run
   end
diff --git a/spec/unit/knife/environment_show_spec.rb b/spec/unit/knife/environment_show_spec.rb
index caac958..bd4148e 100644
--- a/spec/unit/knife/environment_show_spec.rb
+++ b/spec/unit/knife/environment_show_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Delano (<stephen at ospcode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::EnvironmentShow do
   before(:each) do
diff --git a/spec/unit/knife/index_rebuild_spec.rb b/spec/unit/knife/index_rebuild_spec.rb
index 6c3b60b..97a3a69 100644
--- a/spec/unit/knife/index_rebuild_spec.rb
+++ b/spec/unit/knife/index_rebuild_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::IndexRebuild do
 
-  let(:knife){Chef::Knife::IndexRebuild.new}
-  let(:rest_client){double(Chef::REST)}
+  let(:knife) { Chef::Knife::IndexRebuild.new }
+  let(:rest_client) { double(Chef::ServerAPI) }
 
   let(:stub_rest!) do
     expect(knife).to receive(:rest).and_return(rest_client)
@@ -45,18 +45,18 @@ describe Chef::Knife::IndexRebuild do
 
     before(:each) do
       stub_rest!
-      allow(rest_client).to receive(:get_rest).and_raise(http_server_exception)
+      allow(rest_client).to receive(:get).and_raise(http_server_exception)
     end
 
     context "against a Chef 11 server" do
-      let(:api_header_value){"flavor=osc;version=11.0.0;erchef=1.2.3"}
+      let(:api_header_value) { "flavor=osc;version=11.0.0;erchef=1.2.3" }
       it "retrieves API information" do
-        expect(knife.grab_api_info).to eq({"flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3"})
+        expect(knife.grab_api_info).to eq({ "flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3" })
       end
     end # Chef 11
 
     context "against a Chef 10 server" do
-      let(:api_header_value){nil}
+      let(:api_header_value) { nil }
       it "finds no API information" do
         expect(knife.grab_api_info).to eq({})
       end
@@ -66,11 +66,11 @@ describe Chef::Knife::IndexRebuild do
   context "#unsupported_version?" do
     context "with Chef 11 API metadata" do
       it "is unsupported" do
-        expect(knife.unsupported_version?({"version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3"})).to be_truthy
+        expect(knife.unsupported_version?({ "version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3" })).to be_truthy
       end
 
       it "only truly relies on the version being non-nil" do
-        expect(knife.unsupported_version?({"version" => "1", "flavor" => "osc", "erchef" => "1.2.3"})).to be_truthy
+        expect(knife.unsupported_version?({ "version" => "1", "flavor" => "osc", "erchef" => "1.2.3" })).to be_truthy
       end
     end
 
@@ -91,9 +91,9 @@ describe Chef::Knife::IndexRebuild do
 
     context "against a Chef 11 server" do
       let(:api_info) do
-        {"flavor" => "osc",
+        { "flavor" => "osc",
           "version" => "11.0.0",
-          "erchef" => "1.2.3"
+          "erchef" => "1.2.3",
         }
       end
       let(:server_specific_stubs!) do
@@ -107,10 +107,10 @@ describe Chef::Knife::IndexRebuild do
     end
 
     context "against a Chef 10 server" do
-      let(:api_info){ {} }
+      let(:api_info) { {} }
       let(:server_specific_stubs!) do
         stub_rest!
-        expect(rest_client).to receive(:post_rest).with("/search/reindex", {}).and_return("representative output")
+        expect(rest_client).to receive(:post).with("/search/reindex", {}).and_return("representative output")
         expect(knife).not_to receive(:unsupported_server_message)
         expect(knife).to receive(:deprecated_server_message)
         expect(knife).to receive(:nag)
@@ -123,6 +123,3 @@ describe Chef::Knife::IndexRebuild do
   end
 
 end
-
-
-
diff --git a/spec/unit/knife/key_create_spec.rb b/spec/unit/knife/key_create_spec.rb
new file mode 100644
index 0000000..1647b14
--- /dev/null
+++ b/spec/unit/knife/key_create_spec.rb
@@ -0,0 +1,223 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/user_key_create"
+require "chef/knife/client_key_create"
+require "chef/knife/key_create"
+require "chef/key"
+
+describe "key create commands that inherit knife" do
+  shared_examples_for "a key create command" do
+    let(:stderr) { StringIO.new }
+    let(:params) { [] }
+    let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+    let(:command) do
+      c = described_class.new([])
+      c.ui.config[:disable_editing] = true
+      allow(c.ui).to receive(:stderr).and_return(stderr)
+      allow(c.ui).to receive(:stdout).and_return(stderr)
+      allow(c).to receive(:show_usage)
+      c
+    end
+
+    context "after apply_params! is called with valid args" do
+      let(:params) { ["charmander"] }
+      before do
+        command.apply_params!(params)
+      end
+
+      context "when the service object is called" do
+        it "creates a new instance of Chef::Knife::KeyCreate with the correct args" do
+          expect(Chef::Knife::KeyCreate).to receive(:new).
+            with("charmander", command.actor_field_name, command.ui, command.config).
+            and_return(service_object)
+          command.service_object
+        end
+      end # when the service object is called
+    end # after apply_params! is called with valid args
+  end # a key create command
+
+  describe Chef::Knife::UserKeyCreate do
+    it_should_behave_like "a key create command"
+    # defined in key_helper.rb
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+      let(:params) { ["charmander"] }
+    end
+  end
+
+  describe Chef::Knife::ClientKeyCreate do
+    it_should_behave_like "a key create command"
+    # defined in key_helper.rb
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyCreate) }
+      let(:params) { ["charmander"] }
+    end
+  end
+end
+
+describe Chef::Knife::KeyCreate do
+  let(:public_key) {
+    "-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----"
+  }
+  let(:config) { Hash.new }
+  let(:actor) { "charmander" }
+  let(:ui) { instance_double("Chef::Knife::UI") }
+
+  shared_examples_for "key create run command" do
+    let(:key_create_object) {
+      described_class.new(actor, actor_field_name, ui, config)
+    }
+
+    context "when public_key and key_name weren't passed" do
+      it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+        expect { key_create_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_create_object.public_key_or_key_name_error_msg)
+      end
+    end
+
+    context "when the command is run" do
+      let(:expected_hash) {
+        {
+          actor_field_name => "charmander"
+        }
+      }
+
+      before do
+        allow(File).to receive(:read).and_return(public_key)
+        allow(File).to receive(:expand_path)
+
+        allow(key_create_object).to receive(:output_private_key_to_file)
+        allow(key_create_object).to receive(:display_private_key)
+        allow(key_create_object).to receive(:edit_data).and_return(expected_hash)
+        allow(key_create_object).to receive(:create_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+        allow(key_create_object).to receive(:display_info)
+      end
+
+      context "when a valid hash is passed" do
+        let(:key_name) { "charmander-key" }
+        let(:valid_expiration_date) { "2020-12-24T21:00:00Z" }
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+            "expiration_date" => valid_expiration_date,
+            "key_name" => key_name,
+          }
+        }
+        before do
+          key_create_object.config[:public_key] = "public_key_path"
+          key_create_object.config[:expiration_Date] = valid_expiration_date,
+          key_create_object.config[:key_name] = key_name
+        end
+
+        it "creates the proper hash" do
+          expect(key_create_object).to receive(:create_key_from_hash).with(expected_hash)
+          key_create_object.run
+        end
+      end
+
+      context "when public_key is passed" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+          }
+        }
+        before do
+          key_create_object.config[:public_key] = "public_key_path"
+        end
+
+        it "calls File.expand_path with the public_key input" do
+          expect(File).to receive(:expand_path).with("public_key_path")
+          key_create_object.run
+        end
+      end # when public_key is passed
+
+      context "when public_key isn't passed and key_name is" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "name" => "charmander-key",
+            "create_key" => true,
+          }
+        }
+        before do
+          key_create_object.config[:key_name] = "charmander-key"
+        end
+
+        it "should set create_key to true" do
+          expect(key_create_object).to receive(:create_key_from_hash).with(expected_hash)
+          key_create_object.run
+        end
+      end
+
+      context "when the server returns a private key" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+            "private_key" => "super_private",
+          }
+        }
+
+        before do
+          key_create_object.config[:public_key] = "public_key_path"
+        end
+
+        context "when file is not passed" do
+          it "calls display_private_key with the private_key" do
+            expect(key_create_object).to receive(:display_private_key).with("super_private")
+            key_create_object.run
+          end
+        end
+
+        context "when file is passed" do
+          before do
+            key_create_object.config[:file] = "/fake/file"
+          end
+
+          it "calls output_private_key_to_file with the private_key" do
+            expect(key_create_object).to receive(:output_private_key_to_file).with("super_private")
+            key_create_object.run
+          end
+        end
+      end # when the server returns a private key
+    end # when the command is run
+  end #key create run command"
+
+  context "when actor_field_name is 'user'" do
+    it_should_behave_like "key create run command" do
+      let(:actor_field_name) { "user" }
+    end
+  end
+
+  context "when actor_field_name is 'client'" do
+    it_should_behave_like "key create run command" do
+      let(:actor_field_name) { "client" }
+    end
+  end
+end
diff --git a/spec/unit/knife/key_delete_spec.rb b/spec/unit/knife/key_delete_spec.rb
new file mode 100644
index 0000000..3da5a97
--- /dev/null
+++ b/spec/unit/knife/key_delete_spec.rb
@@ -0,0 +1,133 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/user_key_delete"
+require "chef/knife/client_key_delete"
+require "chef/knife/key_delete"
+require "chef/key"
+
+describe "key delete commands that inherit knife" do
+  shared_examples_for "a key delete command" do
+    let(:stderr) { StringIO.new }
+    let(:params) { [] }
+    let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+    let(:command) do
+      c = described_class.new([])
+      c.ui.config[:disable_editing] = true
+      allow(c.ui).to receive(:stderr).and_return(stderr)
+      allow(c.ui).to receive(:stdout).and_return(stderr)
+      allow(c).to receive(:show_usage)
+      c
+    end
+
+    context "after apply_params! is called with valid args" do
+      let(:params) { ["charmander", "charmander-key"] }
+      before do
+        command.apply_params!(params)
+      end
+
+      context "when the service object is called" do
+        it "creates a new instance of Chef::Knife::KeyDelete with the correct args" do
+          expect(Chef::Knife::KeyDelete).to receive(:new).
+            with("charmander-key", "charmander", command.actor_field_name, command.ui).
+            and_return(service_object)
+          command.service_object
+        end
+      end # when the service object is called
+    end # after apply_params! is called with valid args
+  end # a key delete command
+
+  describe Chef::Knife::UserKeyDelete do
+    it_should_behave_like "a key delete command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+
+  describe Chef::Knife::ClientKeyDelete do
+    it_should_behave_like "a key delete command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyDelete) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+end
+
+describe Chef::Knife::KeyDelete do
+  let(:actor) { "charmander" }
+  let(:keyname) { "charmander-key" }
+  let(:ui) { instance_double("Chef::Knife::UI") }
+
+  shared_examples_for "key delete run command" do
+    let(:key_delete_object) {
+      described_class.new(keyname, actor, actor_field_name, ui)
+    }
+
+    before do
+      allow_any_instance_of(Chef::Key).to receive(:destroy)
+      allow(key_delete_object).to receive(:print_destroyed)
+      allow(key_delete_object).to receive(:confirm!)
+    end
+
+    context "when the command is run" do
+      it "calls Chef::Key.new with the proper input" do
+        expect(Chef::Key).to receive(:new).with(actor, actor_field_name).and_call_original
+        key_delete_object.run
+      end
+
+      it "calls name on the Chef::Key instance with the proper input" do
+        expect_any_instance_of(Chef::Key).to receive(:name).with(keyname)
+        key_delete_object.run
+      end
+
+      it "calls destroy on the Chef::Key instance" do
+        expect_any_instance_of(Chef::Key).to receive(:destroy).once
+        key_delete_object.run
+      end
+
+      it "calls confirm!" do
+        expect(key_delete_object).to receive(:confirm!)
+        key_delete_object.run
+      end
+
+      it "calls print_destroyed" do
+        expect(key_delete_object).to receive(:print_destroyed)
+        key_delete_object.run
+      end
+    end # when the command is run
+
+  end # key delete run command
+
+  context "when actor_field_name is 'user'" do
+    it_should_behave_like "key delete run command" do
+      let(:actor_field_name) { "user" }
+    end
+  end
+
+  context "when actor_field_name is 'client'" do
+    it_should_behave_like "key delete run command" do
+      let(:actor_field_name) { "client" }
+    end
+  end
+end
diff --git a/spec/unit/knife/key_edit_spec.rb b/spec/unit/knife/key_edit_spec.rb
new file mode 100644
index 0000000..0fc7208
--- /dev/null
+++ b/spec/unit/knife/key_edit_spec.rb
@@ -0,0 +1,264 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/user_key_edit"
+require "chef/knife/client_key_edit"
+require "chef/knife/key_edit"
+require "chef/key"
+
+describe "key edit commands that inherit knife" do
+  shared_examples_for "a key edit command" do
+    let(:stderr) { StringIO.new }
+    let(:params) { [] }
+    let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+    let(:command) do
+      c = described_class.new([])
+      c.ui.config[:disable_editing] = true
+      allow(c.ui).to receive(:stderr).and_return(stderr)
+      allow(c.ui).to receive(:stdout).and_return(stderr)
+      allow(c).to receive(:show_usage)
+      c
+    end
+
+    context "after apply_params! is called with valid args" do
+      let(:params) { ["charmander", "charmander-key"] }
+      before do
+        command.apply_params!(params)
+      end
+
+      context "when the service object is called" do
+        it "creates a new instance of Chef::Knife::KeyEdit with the correct args" do
+          expect(Chef::Knife::KeyEdit).to receive(:new).
+            with("charmander-key", "charmander", command.actor_field_name, command.ui, command.config).
+            and_return(service_object)
+          command.service_object
+        end
+      end # when the service object is called
+    end # after apply_params! is called with valid args
+  end # a key edit command
+
+  describe Chef::Knife::UserKeyEdit do
+    it_should_behave_like "a key edit command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+
+  describe Chef::Knife::ClientKeyEdit do
+    it_should_behave_like "a key edit command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyEdit) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+end
+
+describe Chef::Knife::KeyEdit do
+  let(:public_key) {
+    "-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPo+oNPB7uuNkws0fC02
+KxSwdyqPLu0fhI1pOweNKAZeEIiEz2PkybathHWy8snSXGNxsITkf3eyvIIKa8OZ
+WrlqpI3yv/5DOP8HTMCxnFuMJQtDwMcevlqebX4bCxcByuBpNYDcAHjjfLGSfMjn
+E5lZpgYWwnpic4kSjYcL9ORK9nYvlWV9P/kCYmRhIjB4AhtpWRiOfY/TKi3P2LxT
+IjSmiN/ihHtlhV/VSnBJ5PzT/lRknlrJ4kACoz7Pq9jv+aAx5ft/xE9yDa2DYs0q
+Tfuc9dUYsFjptWYrV6pfEQ+bgo1OGBXORBFcFL+2D7u9JYquKrMgosznHoEkQNLo
+0wIDAQAB
+-----END PUBLIC KEY-----"
+  }
+  let(:config) { Hash.new }
+  let(:actor) { "charmander" }
+  let(:keyname) { "charmander-key" }
+  let(:ui) { instance_double("Chef::Knife::UI") }
+
+  shared_examples_for "key edit run command" do
+    let(:key_edit_object) {
+      described_class.new(keyname, actor, actor_field_name, ui, config)
+    }
+
+    context "when the command is run" do
+      let(:expected_hash) {
+        {
+          actor_field_name => "charmander"
+        }
+      }
+      let(:new_keyname) { "charizard-key" }
+
+      before do
+        allow(File).to receive(:read).and_return(public_key)
+        allow(File).to receive(:expand_path)
+
+        allow(key_edit_object).to receive(:output_private_key_to_file)
+        allow(key_edit_object).to receive(:display_private_key)
+        allow(key_edit_object).to receive(:edit_data).and_return(expected_hash)
+        allow(key_edit_object).to receive(:display_info)
+      end
+
+      context "when public_key and create_key are passed" do
+        before do
+          key_edit_object.config[:public_key] = "public_key_path"
+          key_edit_object.config[:create_key] = true
+        end
+
+        it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+          expect { key_edit_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_edit_object.public_key_and_create_key_error_msg)
+        end
+      end
+
+      context "when key_name is passed" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "name" => new_keyname,
+          }
+        }
+        before do
+          key_edit_object.config[:key_name] = new_keyname
+          allow_any_instance_of(Chef::Key).to receive(:update)
+        end
+
+        it "update_key_from_hash gets passed a hash with new key name" do
+          expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash).and_return(Chef::Key.from_hash(expected_hash))
+          key_edit_object.run
+        end
+
+        it "Chef::Key.update is passed a string containing the original keyname" do
+          expect_any_instance_of(Chef::Key).to receive(:update).with(/#{keyname}/).and_return(Chef::Key.from_hash(expected_hash))
+          key_edit_object.run
+        end
+
+        it "Chef::Key.update is not passed a string containing the new keyname" do
+          expect_any_instance_of(Chef::Key).not_to receive(:update).with(/#{new_keyname}/)
+          allow_any_instance_of(Chef::Key).to receive(:update).and_return(Chef::Key.from_hash(expected_hash))
+          key_edit_object.run
+        end
+      end
+
+      context "when public_key, key_name, and expiration_date are passed" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+            "name" => new_keyname,
+            "expiration_date" => "infinity",
+          }
+        }
+        before do
+          key_edit_object.config[:public_key] = "this-public-key"
+          key_edit_object.config[:key_name] = new_keyname
+          key_edit_object.config[:expiration_date] = "infinity"
+          allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+        end
+
+        it "passes the right hash to update_key_from_hash" do
+          expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash)
+          key_edit_object.run
+        end
+      end
+
+      context "when create_key is passed" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "create_key" => true,
+          }
+        }
+
+        before do
+          key_edit_object.config[:create_key] = true
+          allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+        end
+
+        it "passes the right hash to update_key_from_hash" do
+          expect(key_edit_object).to receive(:update_key_from_hash).with(expected_hash)
+          key_edit_object.run
+        end
+      end
+
+      context "when public_key is passed" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+          }
+        }
+        before do
+          allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+          key_edit_object.config[:public_key] = "public_key_path"
+        end
+
+        it "calls File.expand_path with the public_key input" do
+          expect(File).to receive(:expand_path).with("public_key_path")
+          key_edit_object.run
+        end
+      end # when public_key is passed
+
+      context "when the server returns a private key" do
+        let(:expected_hash) {
+          {
+            actor_field_name => "charmander",
+            "public_key" => public_key,
+            "private_key" => "super_private",
+          }
+        }
+
+        before do
+          allow(key_edit_object).to receive(:update_key_from_hash).and_return(Chef::Key.from_hash(expected_hash))
+          key_edit_object.config[:public_key] = "public_key_path"
+        end
+
+        context "when file is not passed" do
+          it "calls display_private_key with the private_key" do
+            expect(key_edit_object).to receive(:display_private_key).with("super_private")
+            key_edit_object.run
+          end
+        end
+
+        context "when file is passed" do
+          before do
+            key_edit_object.config[:file] = "/fake/file"
+          end
+
+          it "calls output_private_key_to_file with the private_key" do
+            expect(key_edit_object).to receive(:output_private_key_to_file).with("super_private")
+            key_edit_object.run
+          end
+        end
+      end # when the server returns a private key
+
+    end # when the command is run
+
+  end # key edit run command
+
+  context "when actor_field_name is 'user'" do
+    it_should_behave_like "key edit run command" do
+      let(:actor_field_name) { "user" }
+    end
+  end
+
+  context "when actor_field_name is 'client'" do
+    it_should_behave_like "key edit run command" do
+      let(:actor_field_name) { "client" }
+    end
+  end
+end
diff --git a/spec/unit/knife/key_helper.rb b/spec/unit/knife/key_helper.rb
new file mode 100644
index 0000000..af81812
--- /dev/null
+++ b/spec/unit/knife/key_helper.rb
@@ -0,0 +1,74 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+shared_examples_for "a knife key command" do
+  let(:stderr) { StringIO.new }
+  let(:params) { [] }
+  let(:command) do
+    c = described_class.new([])
+    c.ui.config[:disable_editing] = true
+    allow(c.ui).to receive(:stderr).and_return(stderr)
+    allow(c.ui).to receive(:stdout).and_return(stderr)
+    allow(c).to receive(:show_usage)
+    c
+  end
+
+  context "before apply_params! is called" do
+    context "when apply_params! is called with invalid args" do
+      it "shows the usage" do
+        expect(command).to receive(:show_usage)
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+
+      it "outputs the proper error" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+        expect(stderr.string).to include(command.actor_missing_error)
+      end
+
+      it "exits 1" do
+        expect { command.apply_params!(params) }.to exit_with_code(1)
+      end
+    end
+  end # before apply_params! is called
+
+  context "after apply_params! is called with valid args" do
+    let(:params) { ["charmander"] }
+    before do
+      command.apply_params!(params)
+    end
+
+    it "properly defines the actor" do
+      expect(command.actor).to eq("charmander")
+    end
+  end # after apply_params! is called with valid args
+
+  context "when the command is run" do
+    before do
+      allow(command).to receive(:service_object).and_return(service_object)
+      allow(command).to receive(:name_args).and_return(["charmander"])
+    end
+
+    context "when the command is successful" do
+      before do
+        expect(service_object).to receive(:run)
+      end
+    end
+  end
+end # a knife key command
diff --git a/spec/unit/knife/key_list_spec.rb b/spec/unit/knife/key_list_spec.rb
new file mode 100644
index 0000000..2d4f0a0
--- /dev/null
+++ b/spec/unit/knife/key_list_spec.rb
@@ -0,0 +1,216 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/user_key_list"
+require "chef/knife/client_key_list"
+require "chef/knife/key_list"
+require "chef/key"
+
+describe "key list commands that inherit knife" do
+  shared_examples_for "a key list command" do
+    let(:stderr) { StringIO.new }
+    let(:params) { [] }
+    let(:service_object) { instance_double(Chef::Knife::KeyList) }
+    let(:command) do
+      c = described_class.new([])
+      c.ui.config[:disable_editing] = true
+      allow(c.ui).to receive(:stderr).and_return(stderr)
+      allow(c.ui).to receive(:stdout).and_return(stderr)
+      allow(c).to receive(:show_usage)
+      c
+    end
+
+    context "after apply_params! is called with valid args" do
+      let(:params) { ["charmander"] }
+      before do
+        command.apply_params!(params)
+      end
+
+      context "when the service object is called" do
+        it "creates a new instance of Chef::Knife::KeyList with the correct args" do
+          expect(Chef::Knife::KeyList).to receive(:new).
+            with("charmander", command.list_method, command.ui, command.config).
+            and_return(service_object)
+          command.service_object
+        end
+      end # when the service object is called
+    end # after apply_params! is called with valid args
+  end # a key list command
+
+  describe Chef::Knife::UserKeyList do
+    it_should_behave_like "a key list command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyList) }
+      let(:params) { ["charmander"] }
+    end
+  end
+
+  describe Chef::Knife::ClientKeyList do
+    it_should_behave_like "a key list command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyList) }
+      let(:params) { ["charmander"] }
+    end
+  end
+end
+
+describe Chef::Knife::KeyList do
+  let(:config) { Hash.new }
+  let(:actor) { "charmander" }
+  let(:ui) { instance_double("Chef::Knife::UI") }
+
+  shared_examples_for "key list run command" do
+    let(:key_list_object) {
+      described_class.new(actor, list_method, ui, config)
+    }
+
+    before do
+      allow(Chef::Key).to receive(list_method).and_return(http_response)
+      allow(key_list_object).to receive(:display_info)
+      # simply pass the string though that colorize takes in
+      allow(key_list_object).to receive(:colorize).with(kind_of(String)) do |input|
+        input
+      end
+    end
+
+    context "when only_expired and only_non_expired were both passed" do
+      before do
+        key_list_object.config[:only_expired] = true
+        key_list_object.config[:only_non_expired] = true
+      end
+
+      it "raises a Chef::Exceptions::KeyCommandInputError with the proper error message" do
+        expect { key_list_object.run }.to raise_error(Chef::Exceptions::KeyCommandInputError, key_list_object.expired_and_non_expired_msg)
+      end
+    end
+
+    context "when the command is run" do
+      before do
+        key_list_object.config[:only_expired] = false
+        key_list_object.config[:only_non_expired] = false
+        key_list_object.config[:with_details] = false
+      end
+
+      it "calls Chef::Key with the proper list command and input" do
+        expect(Chef::Key).to receive(list_method).with(actor)
+        key_list_object.run
+      end
+
+      it "displays all the keys" do
+        expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+        expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+        key_list_object.run
+      end
+
+      context "when only_expired is called" do
+        before do
+          key_list_object.config[:only_expired] = true
+        end
+
+        it "excludes displaying non-expired keys" do
+          expect(key_list_object).to receive(:display_info).with(/non-expired/).exactly(0).times
+          key_list_object.run
+        end
+
+        it "displays the expired keys" do
+          expect(key_list_object).to receive(:display_info).with(/out-of-date/).once
+          key_list_object.run
+        end
+      end # when only_expired is called
+
+      context "when only_non_expired is called" do
+        before do
+          key_list_object.config[:only_non_expired] = true
+        end
+
+        it "excludes displaying expired keys" do
+          expect(key_list_object).to receive(:display_info).with(/out-of-date/).exactly(0).times
+          key_list_object.run
+        end
+
+        it "displays the non-expired keys" do
+          expect(key_list_object).to receive(:display_info).with(/non-expired/).twice
+          key_list_object.run
+        end
+      end # when only_expired is called
+
+      context "when with_details is false" do
+        before do
+          key_list_object.config[:with_details] = false
+        end
+
+        it "does not display the uri" do
+          expect(key_list_object).to receive(:display_info).with(/https/).exactly(0).times
+          key_list_object.run
+        end
+
+        it "does not display the expired status" do
+          expect(key_list_object).to receive(:display_info).with(/\(expired\)/).exactly(0).times
+          key_list_object.run
+        end
+      end # when with_details is false
+
+      context "when with_details is true" do
+        before do
+          key_list_object.config[:with_details] = true
+        end
+
+        it "displays the uri" do
+          expect(key_list_object).to receive(:display_info).with(/https/).exactly(3).times
+          key_list_object.run
+        end
+
+        it "displays the expired status" do
+          expect(key_list_object).to receive(:display_info).with(/\(expired\)/).once
+          key_list_object.run
+        end
+      end # when with_details is true
+
+    end # when the command is run
+
+  end # key list run command
+
+  context "when list_method is :list_by_user" do
+    it_should_behave_like "key list run command" do
+      let(:list_method) { :list_by_user }
+      let(:http_response) {
+        [
+          { "uri" => "https://api.opscode.piab/users/charmander/keys/non-expired1", "name" => "non-expired1", "expired" => false },
+          { "uri" => "https://api.opscode.piab/users/charmander/keys/non-expired2", "name" => "non-expired2", "expired" => false },
+          { "uri" => "https://api.opscode.piab/users/mary/keys/out-of-date",        "name" => "out-of-date", "expired" => true },
+        ]
+      }
+    end
+  end
+
+  context "when list_method is :list_by_client" do
+    it_should_behave_like "key list run command" do
+      let(:list_method) { :list_by_client }
+      let(:http_response) {
+        [
+          { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired1", "name" => "non-expired1", "expired" => false },
+          { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/charmander/keys/non-expired2", "name" => "non-expired2", "expired" => false },
+          { "uri" => "https://api.opscode.piab/organizations/pokemon/clients/mary/keys/out-of-date",        "name" => "out-of-date", "expired" => true },
+        ]
+      }
+    end
+  end
+end
diff --git a/spec/unit/knife/key_show_spec.rb b/spec/unit/knife/key_show_spec.rb
new file mode 100644
index 0000000..c161efb
--- /dev/null
+++ b/spec/unit/knife/key_show_spec.rb
@@ -0,0 +1,126 @@
+#
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/knife/user_key_show"
+require "chef/knife/client_key_show"
+require "chef/knife/key_show"
+require "chef/key"
+
+describe "key show commands that inherit knife" do
+  shared_examples_for "a key show command" do
+    let(:stderr) { StringIO.new }
+    let(:params) { [] }
+    let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+    let(:command) do
+      c = described_class.new([])
+      c.ui.config[:disable_editing] = true
+      allow(c.ui).to receive(:stderr).and_return(stderr)
+      allow(c.ui).to receive(:stdout).and_return(stderr)
+      allow(c).to receive(:show_usage)
+      c
+    end
+
+    context "after apply_params! is called with valid args" do
+      let(:params) { ["charmander", "charmander-key"] }
+      before do
+        command.apply_params!(params)
+      end
+
+      context "when the service object is called" do
+        it "creates a new instance of Chef::Knife::KeyShow with the correct args" do
+          expect(Chef::Knife::KeyShow).to receive(:new).
+            with("charmander-key", "charmander", command.load_method, command.ui).
+            and_return(service_object)
+          command.service_object
+        end
+      end # when the service object is called
+    end # after apply_params! is called with valid args
+  end # a key show command
+
+  describe Chef::Knife::UserKeyShow do
+    it_should_behave_like "a key show command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+
+  describe Chef::Knife::ClientKeyShow do
+    it_should_behave_like "a key show command"
+    # defined in key_helpers.rb
+    it_should_behave_like "a knife key command with a keyname as the second arg"
+    it_should_behave_like "a knife key command" do
+      let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+      let(:params) { ["charmander", "charmander-key"] }
+    end
+  end
+end
+
+describe Chef::Knife::KeyShow do
+  let(:actor) { "charmander" }
+  let(:keyname) { "charmander" }
+  let(:ui) { instance_double("Chef::Knife::UI") }
+  let(:expected_hash) {
+    {
+      actor_field_name => "charmander",
+      "name" => "charmander-key",
+      "public_key" => "some-public-key",
+      "expiration_date" => "infinity",
+    }
+  }
+
+  shared_examples_for "key show run command" do
+    let(:key_show_object) {
+      described_class.new(keyname, actor, load_method, ui)
+    }
+
+    before do
+      allow(key_show_object).to receive(:display_output)
+      allow(Chef::Key).to receive(load_method).and_return(Chef::Key.from_hash(expected_hash))
+    end
+
+    context "when the command is run" do
+      it "loads the key using the proper method and args" do
+        expect(Chef::Key).to receive(load_method).with(actor, keyname)
+        key_show_object.run
+      end
+
+      it "displays the key" do
+        expect(key_show_object).to receive(:display_output)
+        key_show_object.run
+      end
+    end
+  end
+
+  context "when load_method is :load_by_user" do
+    it_should_behave_like "key show run command" do
+      let(:load_method) { :load_by_user }
+      let(:actor_field_name) { "user" }
+    end
+  end
+
+  context "when load_method is :load_by_client" do
+    it_should_behave_like "key show run command" do
+      let(:load_method) { :load_by_client }
+      let(:actor_field_name) { "user" }
+    end
+  end
+end
diff --git a/spec/unit/knife/knife_help.rb b/spec/unit/knife/knife_help.rb
index 293bae1..0369951 100644
--- a/spec/unit/knife/knife_help.rb
+++ b/spec/unit/knife/knife_help.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::Help do
   before(:each) do
diff --git a/spec/unit/knife/node_bulk_delete_spec.rb b/spec/unit/knife/node_bulk_delete_spec.rb
index 57a8d0b..2a3563e 100644
--- a/spec/unit/knife/node_bulk_delete_spec.rb
+++ b/spec/unit/knife/node_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeBulkDelete do
   before(:each) do
     Chef::Log.logger = Logger.new(StringIO.new)
 
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeBulkDelete.new
     @knife.name_args = ["."]
     @stdout = StringIO.new
@@ -37,14 +37,14 @@ describe Chef::Knife::NodeBulkDelete do
   describe "when creating the list of nodes" do
     it "fetches the node list" do
       expected = @nodes.inject({}) do |inflatedish, (name, uri)|
-        inflatedish[name] = Chef::Node.new.tap {|n| n.name(name)}
+        inflatedish[name] = Chef::Node.new.tap { |n| n.name(name) }
         inflatedish
       end
       expect(Chef::Node).to receive(:list).and_return(@nodes)
       # I hate not having == defined for anything :(
       actual = @knife.all_nodes
       expect(actual.keys).to match_array(expected.keys)
-      expect(actual.values.map {|n| n.name }).to match_array(%w[adam brent jacob])
+      expect(actual.values.map { |n| n.name }).to match_array(%w{adam brent jacob})
     end
   end
 
@@ -78,10 +78,10 @@ describe Chef::Knife::NodeBulkDelete do
     end
 
     it "should only delete nodes that match the regex" do
-      @knife.name_args = ['adam']
-      expect(@inflatedish_list['adam']).to receive(:destroy)
-      expect(@inflatedish_list['brent']).not_to receive(:destroy)
-      expect(@inflatedish_list['jacob']).not_to receive(:destroy)
+      @knife.name_args = ["adam"]
+      expect(@inflatedish_list["adam"]).to receive(:destroy)
+      expect(@inflatedish_list["brent"]).not_to receive(:destroy)
+      expect(@inflatedish_list["jacob"]).not_to receive(:destroy)
       @knife.run
     end
 
@@ -92,6 +92,3 @@ describe Chef::Knife::NodeBulkDelete do
 
   end
 end
-
-
-
diff --git a/spec/unit/knife/node_delete_spec.rb b/spec/unit/knife/node_delete_spec.rb
index 0941d85..e2cda87 100644
--- a/spec/unit/knife/node_delete_spec.rb
+++ b/spec/unit/knife/node_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeDelete do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeDelete.new
     @knife.config = {
       :print_after => nil
diff --git a/spec/unit/knife/node_edit_spec.rb b/spec/unit/knife/node_edit_spec.rb
index 58e2da2..dedb5c9 100644
--- a/spec/unit/knife/node_edit_spec.rb
+++ b/spec/unit/knife/node_edit_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 Chef::Knife::NodeEdit.load_deps
 
 describe Chef::Knife::NodeEdit do
@@ -27,12 +27,12 @@ describe Chef::Knife::NodeEdit do
   end
 
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeEdit.new
     @knife.config = {
-      :editor => 'cat',
+      :editor => "cat",
       :attribute => nil,
-      :print_after => nil
+      :print_after => nil,
     }
     @knife.name_args = [ "adam" ]
     @node = Chef::Node.new()
@@ -46,10 +46,10 @@ describe Chef::Knife::NodeEdit do
   describe "after loading the node" do
     before do
       allow(@knife).to receive(:node).and_return(@node)
-      @node.automatic_attrs = {:go => :away}
-      @node.default_attrs = {:hide => :me}
-      @node.override_attrs = {:dont => :show}
-      @node.normal_attrs = {:do_show => :these}
+      @node.automatic_attrs = { :go => :away }
+      @node.default_attrs = { :hide => :me }
+      @node.override_attrs = { :dont => :show }
+      @node.normal_attrs = { :do_show => :these }
       @node.chef_environment("prod")
       @node.run_list("recipe[foo]")
     end
@@ -59,7 +59,7 @@ describe Chef::Knife::NodeEdit do
       expect(actual).not_to have_key("automatic")
       expect(actual).not_to have_key("override")
       expect(actual).not_to have_key("default")
-      expect(actual["normal"]).to eq({"do_show" => "these"})
+      expect(actual["normal"]).to eq({ "do_show" => "these" })
       expect(actual["run_list"]).to eq(["recipe[foo]"])
       expect(actual["chef_environment"]).to eq("prod")
     end
@@ -68,10 +68,10 @@ describe Chef::Knife::NodeEdit do
       @knife.config[:all_attributes] = true
 
       actual = deserialized_json_view
-      expect(actual["automatic"]).to eq({"go" => "away"})
-      expect(actual["override"]).to eq({"dont" => "show"})
-      expect(actual["default"]).to eq({"hide" => "me"})
-      expect(actual["normal"]).to eq({"do_show" => "these"})
+      expect(actual["automatic"]).to eq({ "go" => "away" })
+      expect(actual["override"]).to eq({ "dont" => "show" })
+      expect(actual["default"]).to eq({ "hide" => "me" })
+      expect(actual["normal"]).to eq({ "do_show" => "these" })
       expect(actual["run_list"]).to eq(["recipe[foo]"])
       expect(actual["chef_environment"]).to eq("prod")
     end
@@ -101,15 +101,14 @@ describe Chef::Knife::NodeEdit do
 
     it "raises an exception when editing is disabled" do
       @knife.config[:disable_editing] = true
-      expect{ subject }.to raise_error(SystemExit)
+      expect { subject }.to raise_error(SystemExit)
     end
 
     it "raises an exception when the editor is not set" do
       @knife.config[:editor] = nil
-      expect{ subject }.to raise_error(SystemExit)
+      expect { subject }.to raise_error(SystemExit)
     end
 
   end
 
 end
-
diff --git a/spec/unit/knife/node_environment_set_spec.rb b/spec/unit/knife/node_environment_set_spec.rb
index 1026791..13dd376 100644
--- a/spec/unit/knife/node_environment_set_spec.rb
+++ b/spec/unit/knife/node_environment_set_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jimmy McCrory (<jimmy.mccrory at gmail.com>)
-# Copyright:: Copyright (c) 2014 Jimmy McCrory
+# Copyright:: Copyright 2014-2016, Jimmy McCrory
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeEnvironmentSet do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeEnvironmentSet.new
     @knife.name_args = [ "adam", "bar" ]
     allow(@knife).to receive(:output).and_return(true)
@@ -39,7 +39,7 @@ describe Chef::Knife::NodeEnvironmentSet do
 
     it "should update the environment" do
       @knife.run
-      expect(@node.chef_environment).to eq('bar')
+      expect(@node.chef_environment).to eq("bar")
     end
 
     it "should save the node" do
diff --git a/spec/unit/knife/node_from_file_spec.rb b/spec/unit/knife/node_from_file_spec.rb
index 6239047..89b2b81 100644
--- a/spec/unit/knife/node_from_file_spec.rb
+++ b/spec/unit/knife/node_from_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::NodeFromFile.load_deps
 
 describe Chef::Knife::NodeFromFile do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeFromFile.new
     @knife.config = {
       :print_after => nil
@@ -39,7 +39,7 @@ describe Chef::Knife::NodeFromFile do
 
   describe "run" do
     it "should load from a file" do
-      expect(@knife.loader).to receive(:load_from).with('nodes', 'adam.rb').and_return(@node)
+      expect(@knife.loader).to receive(:load_from).with("nodes", "adam.rb").and_return(@node)
       @knife.run
     end
 
diff --git a/spec/unit/knife/node_list_spec.rb b/spec/unit/knife/node_list_spec.rb
index 71edea7..ab17a45 100644
--- a/spec/unit/knife/node_list_spec.rb
+++ b/spec/unit/knife/node_list_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeList do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     Chef::Config[:environment] = nil # reset this value each time, as it is not reloaded
     @knife = Chef::Knife::NodeList.new
     allow(@knife).to receive(:output).and_return(true)
     @list = {
       "foo" => "http://example.com/foo",
-      "bar" => "http://example.com/foo"
+      "bar" => "http://example.com/foo",
     }
     allow(Chef::Node).to receive(:list).and_return(@list)
     allow(Chef::Node).to receive(:list_by_environment).and_return(@list)
@@ -60,4 +60,3 @@ describe Chef::Knife::NodeList do
     end
   end
 end
-
diff --git a/spec/unit/knife/node_run_list_add_spec.rb b/spec/unit/knife/node_run_list_add_spec.rb
index 92fbfd2..eb897c1 100644
--- a/spec/unit/knife/node_run_list_add_spec.rb
+++ b/spec/unit/knife/node_run_list_add_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeRunListAdd do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeRunListAdd.new
     @knife.config = {
       :after => nil
@@ -40,7 +40,7 @@ describe Chef::Knife::NodeRunListAdd do
 
     it "should add to the run list" do
       @knife.run
-      expect(@node.run_list[0]).to eq('role[monkey]')
+      expect(@node.run_list[0]).to eq("role[monkey]")
     end
 
     it "should save the node" do
@@ -143,6 +143,3 @@ describe Chef::Knife::NodeRunListAdd do
     end
   end
 end
-
-
-
diff --git a/spec/unit/knife/node_run_list_remove_spec.rb b/spec/unit/knife/node_run_list_remove_spec.rb
index ceceef7..e741f51 100644
--- a/spec/unit/knife/node_run_list_remove_spec.rb
+++ b/spec/unit/knife/node_run_list_remove_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeRunListRemove do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeRunListRemove.new
     @knife.config[:print_after] = nil
     @knife.name_args = [ "adam", "role[monkey]" ]
@@ -43,7 +43,7 @@ describe Chef::Knife::NodeRunListRemove do
 
     it "should remove the item from the run list" do
       @knife.run
-      expect(@node.run_list[0]).not_to eq('role[monkey]')
+      expect(@node.run_list[0]).not_to eq("role[monkey]")
     end
 
     it "should save the node" do
@@ -53,36 +53,53 @@ describe Chef::Knife::NodeRunListRemove do
 
     it "should print the run list" do
       @knife.config[:print_after] = true
-      expect(@knife.ui).to receive(:output).with({ "knifetest-node" => { 'run_list' => [] } })
+      expect(@knife.ui).to receive(:output).with({ "knifetest-node" => { "run_list" => [] } })
       @knife.run
     end
 
     describe "run with a list of roles and recipes" do
       it "should remove the items from the run list" do
-        @node.run_list << 'role[monkey]'
-        @node.run_list << 'recipe[duck::type]'
-        @knife.name_args = [ 'adam', 'role[monkey],recipe[duck::type]' ]
+        @node.run_list << "role[monkey]"
+        @node.run_list << "recipe[duck::type]"
+        @knife.name_args = [ "adam", "role[monkey],recipe[duck::type]" ]
         @knife.run
-        expect(@node.run_list).not_to include('role[monkey]')
-        expect(@node.run_list).not_to include('recipe[duck::type]')
+        expect(@node.run_list).not_to include("role[monkey]")
+        expect(@node.run_list).not_to include("recipe[duck::type]")
       end
 
       it "should remove the items from the run list when name args contains whitespace" do
-        @node.run_list << 'role[monkey]'
-        @node.run_list << 'recipe[duck::type]'
-        @knife.name_args = [ 'adam', 'role[monkey], recipe[duck::type]' ]
+        @node.run_list << "role[monkey]"
+        @node.run_list << "recipe[duck::type]"
+        @knife.name_args = [ "adam", "role[monkey], recipe[duck::type]" ]
         @knife.run
-        expect(@node.run_list).not_to include('role[monkey]')
-        expect(@node.run_list).not_to include('recipe[duck::type]')
+        expect(@node.run_list).not_to include("role[monkey]")
+        expect(@node.run_list).not_to include("recipe[duck::type]")
       end
 
       it "should remove the items from the run list when name args contains multiple run lists" do
-        @node.run_list << 'role[blah]'
-        @node.run_list << 'recipe[duck::type]'
-        @knife.name_args = [ 'adam', 'role[monkey], recipe[duck::type]', 'role[blah]' ]
+        @node.run_list << "role[blah]"
+        @node.run_list << "recipe[duck::type]"
+        @knife.name_args = [ "adam", "role[monkey], recipe[duck::type]", "role[blah]" ]
+        @knife.run
+        expect(@node.run_list).not_to include("role[monkey]")
+        expect(@node.run_list).not_to include("recipe[duck::type]")
+      end
+
+      it "should warn when the thing to remove is not in the runlist" do
+        @node.run_list << "role[blah]"
+        @node.run_list << "recipe[duck::type]"
+        @knife.name_args = [ "adam", "role[blork]" ]
+        expect(@knife.ui).to receive(:warn).with("role[blork] is not in the run list")
+        @knife.run
+      end
+
+      it "should warn even more when the thing to remove is not in the runlist and unqualified" do
+        @node.run_list << "role[blah]"
+        @node.run_list << "recipe[duck::type]"
+        @knife.name_args = [ "adam", "blork" ]
+        expect(@knife.ui).to receive(:warn).with("blork is not in the run list")
+        expect(@knife.ui).to receive(:warn).with(/did you forget recipe\[\] or role\[\]/)
         @knife.run
-        expect(@node.run_list).not_to include('role[monkey]')
-        expect(@node.run_list).not_to include('recipe[duck::type]')
       end
     end
   end
diff --git a/spec/unit/knife/node_run_list_set_spec.rb b/spec/unit/knife/node_run_list_set_spec.rb
index 68daaaf..1bbaa7d 100644
--- a/spec/unit/knife/node_run_list_set_spec.rb
+++ b/spec/unit/knife/node_run_list_set_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mike Fiedler (<miketheman at gmail.com>)
-# Copyright:: Copyright (c) 2013 Mike Fiedler
+# Copyright:: Copyright 2013-2016, Mike Fiedler
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeRunListSet do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::NodeRunListSet.new
     @knife.config = {}
     @knife.name_args = [ "adam", "role[monkey]" ]
@@ -38,7 +38,7 @@ describe Chef::Knife::NodeRunListSet do
 
     it "should set the run list" do
       @knife.run
-      expect(@node.run_list[0]).to eq('role[monkey]')
+      expect(@node.run_list[0]).to eq("role[monkey]")
     end
 
     it "should save the node" do
diff --git a/spec/unit/knife/node_show_spec.rb b/spec/unit/knife/node_show_spec.rb
index 4806354..b3fc78c 100644
--- a/spec/unit/knife/node_show_spec.rb
+++ b/spec/unit/knife/node_show_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::NodeShow do
 
   let(:node) do
     node = Chef::Node.new()
     node.name("adam")
-    node.run_list = ['role[base]']
+    node.run_list = ["role[base]"]
     node
   end
 
@@ -54,10 +54,10 @@ describe Chef::Knife::NodeShow do
     end
 
     it "should pretty print json" do
-      knife.config[:format] = 'json'
+      knife.config[:format] = "json"
       stdout = StringIO.new
       allow(knife.ui).to receive(:stdout).and_return(stdout)
-      expect(Chef::Node).to receive(:load).with('adam').and_return(node)
+      expect(Chef::Node).to receive(:load).with("adam").and_return(node)
       knife.run
       expect(stdout.string).to eql("{\n  \"name\": \"adam\",\n  \"chef_environment\": \"_default\",\n  \"run_list\": [\n\n]\n,\n  \"normal\": {\n\n  }\n}\n")
     end
diff --git a/spec/unit/knife/osc_user_create_spec.rb b/spec/unit/knife/osc_user_create_spec.rb
new file mode 100644
index 0000000..a52ba54
--- /dev/null
+++ b/spec/unit/knife/osc_user_create_spec.rb
@@ -0,0 +1,93 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+Chef::Knife::OscUserCreate.load_deps
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_create_spec.rb.
+
+describe Chef::Knife::OscUserCreate do
+  before(:each) do
+    @knife = Chef::Knife::OscUserCreate.new
+
+    @stdout = StringIO.new
+    @stderr = StringIO.new
+    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+    allow(@knife.ui).to receive(:stderr).and_return(@stderr)
+
+    @knife.name_args = [ "a_user" ]
+    @knife.config[:user_password] = "foobar"
+    @user = Chef::User.new
+    @user.name "a_user"
+    @user_with_private_key = Chef::User.new
+    @user_with_private_key.name "a_user"
+    @user_with_private_key.private_key "private_key"
+    allow(@user).to receive(:create).and_return(@user_with_private_key)
+    allow(Chef::User).to receive(:new).and_return(@user)
+    allow(Chef::User).to receive(:from_hash).and_return(@user)
+    allow(@knife).to receive(:edit_data).and_return(@user.to_hash)
+  end
+
+  it "creates a new user" do
+    expect(Chef::User).to receive(:new).and_return(@user)
+    expect(@user).to receive(:create)
+    @knife.run
+    expect(@stderr.string).to match /created user.+a_user/i
+  end
+
+  it "sets the password" do
+    @knife.config[:user_password] = "a_password"
+    expect(@user).to receive(:password).with("a_password")
+    @knife.run
+  end
+
+  it "exits with an error if password is blank" do
+    @knife.config[:user_password] = ""
+    expect { @knife.run }.to raise_error SystemExit
+    expect(@stderr.string).to match /You must specify a non-blank password/
+  end
+
+  it "sets the user name" do
+    expect(@user).to receive(:name).with("a_user")
+    @knife.run
+  end
+
+  it "sets the public key if given" do
+    @knife.config[:user_key] = "/a/filename"
+    allow(File).to receive(:read).with(File.expand_path("/a/filename")).and_return("a_key")
+    expect(@user).to receive(:public_key).with("a_key")
+    @knife.run
+  end
+
+  it "allows you to edit the data" do
+    expect(@knife).to receive(:edit_data).with(@user)
+    @knife.run
+  end
+
+  it "writes the private key to a file when --file is specified" do
+    @knife.config[:file] = "/tmp/a_file"
+    filehandle = double("filehandle")
+    expect(filehandle).to receive(:print).with("private_key")
+    expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
+    @knife.run
+  end
+end
diff --git a/spec/unit/knife/osc_user_delete_spec.rb b/spec/unit/knife/osc_user_delete_spec.rb
new file mode 100644
index 0000000..6e90988
--- /dev/null
+++ b/spec/unit/knife/osc_user_delete_spec.rb
@@ -0,0 +1,44 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_delete_spec.rb.
+
+describe Chef::Knife::OscUserDelete do
+  before(:each) do
+    Chef::Knife::OscUserDelete.load_deps
+    @knife = Chef::Knife::OscUserDelete.new
+    @knife.name_args = [ "my_user" ]
+  end
+
+  it "deletes the user" do
+    expect(@knife).to receive(:delete_object).with(Chef::User, "my_user")
+    @knife.run
+  end
+
+  it "prints usage and exits when a user name is not provided" do
+    @knife.name_args = []
+    expect(@knife).to receive(:show_usage)
+    expect(@knife.ui).to receive(:fatal)
+    expect { @knife.run }.to raise_error(SystemExit)
+  end
+end
diff --git a/spec/unit/knife/osc_user_edit_spec.rb b/spec/unit/knife/osc_user_edit_spec.rb
new file mode 100644
index 0000000..4dc92d6
--- /dev/null
+++ b/spec/unit/knife/osc_user_edit_spec.rb
@@ -0,0 +1,52 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_edit_spec.rb.
+
+describe Chef::Knife::OscUserEdit do
+  before(:each) do
+    @stderr = StringIO.new
+    @stdout = StringIO.new
+
+    Chef::Knife::OscUserEdit.load_deps
+    @knife = Chef::Knife::OscUserEdit.new
+    allow(@knife.ui).to receive(:stderr).and_return(@stderr)
+    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+    @knife.name_args = [ "my_user" ]
+    @knife.config[:disable_editing] = true
+  end
+
+  it "loads and edits the user" do
+    data = { :name => "my_user" }
+    allow(Chef::User).to receive(:load).with("my_user").and_return(data)
+    expect(@knife).to receive(:edit_data).with(data).and_return(data)
+    @knife.run
+  end
+
+  it "prints usage and exits when a user name is not provided" do
+    @knife.name_args = []
+    expect(@knife).to receive(:show_usage)
+    expect(@knife.ui).to receive(:fatal)
+    expect { @knife.run }.to raise_error(SystemExit)
+  end
+end
diff --git a/spec/unit/knife/osc_user_list_spec.rb b/spec/unit/knife/osc_user_list_spec.rb
new file mode 100644
index 0000000..10682eb
--- /dev/null
+++ b/spec/unit/knife/osc_user_list_spec.rb
@@ -0,0 +1,37 @@
+#
+# Author:: Steven Danna
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# DEPRECATION NOTE
+# This code only remains to support users still operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_list_spec.rb.
+
+describe Chef::Knife::OscUserList do
+  before(:each) do
+    Chef::Knife::OscUserList.load_deps
+    @knife = Chef::Knife::OscUserList.new
+  end
+
+  it "lists the users" do
+    expect(Chef::User).to receive(:list)
+    expect(@knife).to receive(:format_list_for_display)
+    @knife.run
+  end
+end
diff --git a/spec/unit/knife/osc_user_reregister_spec.rb b/spec/unit/knife/osc_user_reregister_spec.rb
new file mode 100644
index 0000000..ae6b4be
--- /dev/null
+++ b/spec/unit/knife/osc_user_reregister_spec.rb
@@ -0,0 +1,58 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# DEPRECATION NOTE
+# This code only remains to support users still	operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_reregister_spec.rb.
+
+describe Chef::Knife::OscUserReregister do
+  before(:each) do
+    Chef::Knife::OscUserReregister.load_deps
+    @knife = Chef::Knife::OscUserReregister.new
+    @knife.name_args = [ "a_user" ]
+    @user_mock = double("user_mock", :private_key => "private_key")
+    allow(Chef::User).to receive(:load).and_return(@user_mock)
+    @stdout = StringIO.new
+    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+  end
+
+  it "prints usage and exits when a user name is not provided" do
+    @knife.name_args = []
+    expect(@knife).to receive(:show_usage)
+    expect(@knife.ui).to receive(:fatal)
+    expect { @knife.run }.to raise_error(SystemExit)
+  end
+
+  it "reregisters the user and prints the key" do
+    expect(@user_mock).to receive(:reregister).and_return(@user_mock)
+    @knife.run
+    expect(@stdout.string).to match( /private_key/ )
+  end
+
+  it "writes the private key to a file when --file is specified" do
+    expect(@user_mock).to receive(:reregister).and_return(@user_mock)
+    @knife.config[:file] = "/tmp/a_file"
+    filehandle = StringIO.new
+    expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
+    @knife.run
+    expect(filehandle.string).to eq("private_key")
+  end
+end
diff --git a/spec/unit/knife/osc_user_show_spec.rb b/spec/unit/knife/osc_user_show_spec.rb
new file mode 100644
index 0000000..d6efbef
--- /dev/null
+++ b/spec/unit/knife/osc_user_show_spec.rb
@@ -0,0 +1,46 @@
+#
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+# DEPRECATION NOTE
+# This code only remains to support users still	operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur user_show_spec.rb.
+
+describe Chef::Knife::OscUserShow do
+  before(:each) do
+    Chef::Knife::OscUserShow.load_deps
+    @knife = Chef::Knife::OscUserShow.new
+    @knife.name_args = [ "my_user" ]
+    @user_mock = double("user_mock")
+  end
+
+  it "loads and displays the user" do
+    expect(Chef::User).to receive(:load).with("my_user").and_return(@user_mock)
+    expect(@knife).to receive(:format_for_display).with(@user_mock)
+    @knife.run
+  end
+
+  it "prints usage and exits when a user name is not provided" do
+    @knife.name_args = []
+    expect(@knife).to receive(:show_usage)
+    expect(@knife.ui).to receive(:fatal)
+    expect { @knife.run }.to raise_error(SystemExit)
+  end
+end
diff --git a/spec/unit/knife/raw_spec.rb b/spec/unit/knife/raw_spec.rb
index ab929ab..9202998 100644
--- a/spec/unit/knife/raw_spec.rb
+++ b/spec/unit/knife/raw_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +15,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::Raw do
   let(:rest) do
-    r = double('Chef::Knife::Raw::RawInputServerAPI')
+    r = double("Chef::Knife::Raw::RawInputServerAPI")
     allow(Chef::Knife::Raw::RawInputServerAPI).to receive(:new).and_return(r)
     r
   end
@@ -35,8 +35,8 @@ describe Chef::Knife::Raw do
     it "should set the x-ops-request-source header when --proxy-auth is set" do
       knife.config[:proxy_auth] = true
       expect(rest).to receive(:request).with(:GET, "/nodes",
-                                              { 'Content-Type' => 'application/json',
-                                                'x-ops-request-source' => 'web'}, false)
+                                              { "Content-Type" => "application/json",
+                                                "x-ops-request-source" => "web" }, false)
       knife.run
     end
   end
diff --git a/spec/unit/knife/role_bulk_delete_spec.rb b/spec/unit/knife/role_bulk_delete_spec.rb
index 5b79e52..9a4a1a0 100644
--- a/spec/unit/knife/role_bulk_delete_spec.rb
+++ b/spec/unit/knife/role_bulk_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleBulkDelete do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleBulkDelete.new
     @knife.config = {
       :print_after => nil
diff --git a/spec/unit/knife/role_create_spec.rb b/spec/unit/knife/role_create_spec.rb
index fb748c5..d414e5a 100644
--- a/spec/unit/knife/role_create_spec.rb
+++ b/spec/unit/knife/role_create_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleCreate do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleCreate.new
     @knife.config = {
       :description => nil
diff --git a/spec/unit/knife/role_delete_spec.rb b/spec/unit/knife/role_delete_spec.rb
index b1a0d90..cc65674 100644
--- a/spec/unit/knife/role_delete_spec.rb
+++ b/spec/unit/knife/role_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleDelete do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleDelete.new
     @knife.config = {
       :print_after => nil
diff --git a/spec/unit/knife/role_edit_spec.rb b/spec/unit/knife/role_edit_spec.rb
index 0975c64..71d6980 100644
--- a/spec/unit/knife/role_edit_spec.rb
+++ b/spec/unit/knife/role_edit_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEdit do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleEdit.new
     @knife.config[:print_after] = nil
     @knife.name_args = [ "adam" ]
@@ -75,5 +75,3 @@ describe Chef::Knife::RoleEdit do
     end
   end
 end
-
-
diff --git a/spec/unit/knife/role_env_run_list_add_spec.rb b/spec/unit/knife/role_env_run_list_add_spec.rb
index f286d5f..fe4cb6d 100644
--- a/spec/unit/knife/role_env_run_list_add_spec.rb
+++ b/spec/unit/knife/role_env_run_list_add_spec.rb
@@ -1,15 +1,15 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 #     http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEnvRunListAdd do
   before(:each) do
@@ -29,7 +29,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
     }
     @knife.name_args = [ "will", "QA", "role[monkey]" ]
     allow(@knife).to receive(:output).and_return(true)
-    @role = Chef::Role.new() 
+    @role = Chef::Role.new()
     allow(@role).to receive(:save).and_return(true)
     allow(Chef::Role).to receive(:load).and_return(@role)
   end
@@ -48,7 +48,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
 
     it "should have a QA environment" do
       @knife.run
-      expect(@role.active_run_list_for('QA')).to eq('QA')
+      expect(@role.active_run_list_for("QA")).to eq("QA")
     end
 
     it "should load the role named will" do
@@ -58,7 +58,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
 
     it "should be able to add an environment specific run list" do
       @knife.run
-      expect(@role.run_list_for('QA')[0]).to eq('role[monkey]')
+      expect(@role.run_list_for("QA")[0]).to eq("role[monkey]")
     end
 
     it "should save the role" do
@@ -180,7 +180,7 @@ describe Chef::Knife::RoleEnvRunListAdd do
         expect(@role.run_list[1]).to be_nil
       end
     end
-    
+
     describe "with more than one command" do
       it "should be able to the environment run list by running multiple knife commands" do
         @knife.name_args = [ "will", "QA", "role[blue]," ]
diff --git a/spec/unit/knife/role_env_run_list_clear_spec.rb b/spec/unit/knife/role_env_run_list_clear_spec.rb
index 525376c..1fb2f1f 100644
--- a/spec/unit/knife/role_env_run_list_clear_spec.rb
+++ b/spec/unit/knife/role_env_run_list_clear_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEnvRunListClear do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
-    Chef::Config[:env_name]  = "QA"
+    Chef::Config[:role_name] = "will"
+    Chef::Config[:env_name] = "QA"
     @setup = Chef::Knife::RoleEnvRunListAdd.new
     @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ]
 
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListClear do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -57,44 +54,41 @@ describe Chef::Knife::RoleEnvRunListClear do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list_for('QA')[0]).to be_nil
-       expect(@role.run_list[0]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list_for("QA")[0]).to be_nil
+      expect(@role.run_list[0]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "should clear an environmental run list of roles and recipes" do
-       it "should remove the items from the run list" do
-         @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will', 'QA' ]
-         @knife.run
-         expect(@role.run_list_for('QA')[0]).to be_nil
-         expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
-         expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
-         expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
-         expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
-         expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
-       end
-     end
+    describe "should clear an environmental run list of roles and recipes" do
+      it "should remove the items from the run list" do
+        @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will", "QA" ]
+        @knife.run
+        expect(@role.run_list_for("QA")[0]).to be_nil
+        expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+        expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+        expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+        expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+        expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+      end
+    end
   end
 end
-
-
-
diff --git a/spec/unit/knife/role_env_run_list_remove_spec.rb b/spec/unit/knife/role_env_run_list_remove_spec.rb
index a15d0af..180dbf1 100644
--- a/spec/unit/knife/role_env_run_list_remove_spec.rb
+++ b/spec/unit/knife/role_env_run_list_remove_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEnvRunListRemove do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
-    Chef::Config[:env_name]  = "QA"
+    Chef::Config[:role_name] = "will"
+    Chef::Config[:env_name] = "QA"
     @setup = Chef::Knife::RoleEnvRunListAdd.new
     @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]" ]
 
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListRemove do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -57,52 +54,49 @@ describe Chef::Knife::RoleEnvRunListRemove do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list_for('QA')[0]).not_to eq('role[monkey]')
-       expect(@role.run_list_for('QA')[0]).to eq('role[person]')
-       expect(@role.run_list[0]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list_for("QA")[0]).not_to eq("role[monkey]")
+      expect(@role.run_list_for("QA")[0]).to eq("role[person]")
+      expect(@role.run_list[0]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "run with a list of roles and recipes" do
-       it "should remove the items from the run list" do
-         @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will', 'QA', 'role[monkey]' ]
-         @knife.run
-         @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]' ]
-         @knife.run
-         expect(@role.run_list_for('QA')).not_to include('role[monkey]')
-         expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]')
-         expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list_for('QA')[1]).to eq('role[person]')
-         expect(@role.run_list_for('QA')[2]).to eq('role[bird]')
-         expect(@role.run_list_for('QA')[3]).to eq('role[town]')
-         expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
-         expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
-         expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
-         expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
-         expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
-       end
-     end
+    describe "run with a list of roles and recipes" do
+      it "should remove the items from the run list" do
+        @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will", "QA", "role[monkey]" ]
+        @knife.run
+        @knife.name_args = [ "will", "QA", "recipe[duck::type]" ]
+        @knife.run
+        expect(@role.run_list_for("QA")).not_to include("role[monkey]")
+        expect(@role.run_list_for("QA")).not_to include("recipe[duck::type]")
+        expect(@role.run_list_for("QA")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("QA")[1]).to eq("role[person]")
+        expect(@role.run_list_for("QA")[2]).to eq("role[bird]")
+        expect(@role.run_list_for("QA")[3]).to eq("role[town]")
+        expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+        expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+        expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+        expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+        expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+      end
+    end
   end
 end
-
-
-
diff --git a/spec/unit/knife/role_env_run_list_replace_spec.rb b/spec/unit/knife/role_env_run_list_replace_spec.rb
index ea48601..fcfbe99 100644
--- a/spec/unit/knife/role_env_run_list_replace_spec.rb
+++ b/spec/unit/knife/role_env_run_list_replace_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEnvRunListReplace do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
-    Chef::Config[:env_name]  = "QA"
+    Chef::Config[:role_name] = "will"
+    Chef::Config[:env_name] = "QA"
     @setup = Chef::Knife::RoleEnvRunListAdd.new
     @setup.name_args = [ "will", "QA", "role[monkey]", "role[dude]", "role[fixer]" ]
 
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListReplace do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -57,52 +54,52 @@ describe Chef::Knife::RoleEnvRunListReplace do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list_for('QA')[1]).not_to eq('role[dude]')
-       expect(@role.run_list_for('QA')[1]).to eq('role[person]')
-       expect(@role.run_list[0]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list_for("QA")[1]).not_to eq("role[dude]")
+      expect(@role.run_list_for("QA")[1]).to eq("role[person]")
+      expect(@role.run_list[0]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "run with a list of roles and recipes" do
-       it "should replace the items from the run list" do
-         @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will', 'QA', 'role[monkey]', 'role[gibbon]' ]
-         @knife.run
-         @knife.name_args = [ 'will', 'QA', 'recipe[duck::type]', 'recipe[duck::mallard]' ]
-         @knife.run
-         expect(@role.run_list_for('QA')).not_to include('role[monkey]')
-         expect(@role.run_list_for('QA')).not_to include('recipe[duck::type]')
-         expect(@role.run_list_for('QA')[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list_for('QA')[1]).to eq('role[gibbon]')
-         expect(@role.run_list_for('QA')[2]).to eq('recipe[duck::mallard]')
-         expect(@role.run_list_for('QA')[3]).to eq('role[person]')
-         expect(@role.run_list_for('QA')[4]).to eq('role[bird]')
-         expect(@role.run_list_for('QA')[5]).to eq('role[town]')
-         expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
-         expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
-         expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
-         expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
-         expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
-         expect(@role.run_list[0]).to be_nil
-       end
-     end
+    describe "run with a list of roles and recipes" do
+      it "should replace the items from the run list" do
+        @setup.name_args = [ "will", "QA", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @setup.name_args = [ "will", "PRD", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will", "QA", "role[monkey]", "role[gibbon]" ]
+        @knife.run
+        @knife.name_args = [ "will", "QA", "recipe[duck::type]", "recipe[duck::mallard]" ]
+        @knife.run
+        expect(@role.run_list_for("QA")).not_to include("role[monkey]")
+        expect(@role.run_list_for("QA")).not_to include("recipe[duck::type]")
+        expect(@role.run_list_for("QA")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("QA")[1]).to eq("role[gibbon]")
+        expect(@role.run_list_for("QA")[2]).to eq("recipe[duck::mallard]")
+        expect(@role.run_list_for("QA")[3]).to eq("role[person]")
+        expect(@role.run_list_for("QA")[4]).to eq("role[bird]")
+        expect(@role.run_list_for("QA")[5]).to eq("role[town]")
+        expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+        expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+        expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+        expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+        expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
+        expect(@role.run_list[0]).to be_nil
+      end
+    end
   end
 end
diff --git a/spec/unit/knife/role_env_run_list_set_spec.rb b/spec/unit/knife/role_env_run_list_set_spec.rb
index f3abb86..6fb1874 100644
--- a/spec/unit/knife/role_env_run_list_set_spec.rb
+++ b/spec/unit/knife/role_env_run_list_set_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleEnvRunListSet do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
-    Chef::Config[:env_name]  = "QA"
+    Chef::Config[:role_name] = "will"
+    Chef::Config[:env_name] = "QA"
     @setup = Chef::Knife::RoleEnvRunListAdd.new
     @setup.name_args = [ "will", "QA", "role[monkey]", "role[person]", "role[bucket]" ]
 
@@ -42,11 +42,8 @@ describe Chef::Knife::RoleEnvRunListSet do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -60,9 +57,9 @@ describe Chef::Knife::RoleEnvRunListSet do
     it "should replace all the items in the runlist with what is specified" do
       @setup.run
       @knife.run
-      expect(@role.run_list_for('QA')[0]).to eq("role[owen]") 
-      expect(@role.run_list_for('QA')[1]).to eq("role[mauntel]") 
-      expect(@role.run_list_for('QA')[2]).to be_nil
+      expect(@role.run_list_for("QA")[0]).to eq("role[owen]")
+      expect(@role.run_list_for("QA")[1]).to eq("role[mauntel]")
+      expect(@role.run_list_for("QA")[2]).to be_nil
       expect(@role.run_list[0]).to be_nil
     end
 
@@ -86,15 +83,15 @@ describe Chef::Knife::RoleEnvRunListSet do
         @setup.run
         @knife.name_args = [ "will", "QA", "role[coke]", "role[pepsi]" ]
         @knife.run
-        expect(@role.run_list_for('QA')[0]).to eq("role[coke]")
-        expect(@role.run_list_for('QA')[1]).to eq("role[pepsi]")
-        expect(@role.run_list_for('QA')[2]).to be_nil
-        expect(@role.run_list_for('PRD')[0]).to eq('recipe[orange::chicken]')
-        expect(@role.run_list_for('PRD')[1]).to eq('role[monkey]')
-        expect(@role.run_list_for('PRD')[2]).to eq('recipe[duck::type]')
-        expect(@role.run_list_for('PRD')[3]).to eq('role[person]')
-        expect(@role.run_list_for('PRD')[4]).to eq('role[bird]')
-        expect(@role.run_list_for('PRD')[5]).to eq('role[town]')
+        expect(@role.run_list_for("QA")[0]).to eq("role[coke]")
+        expect(@role.run_list_for("QA")[1]).to eq("role[pepsi]")
+        expect(@role.run_list_for("QA")[2]).to be_nil
+        expect(@role.run_list_for("PRD")[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list_for("PRD")[1]).to eq("role[monkey]")
+        expect(@role.run_list_for("PRD")[2]).to eq("recipe[duck::type]")
+        expect(@role.run_list_for("PRD")[3]).to eq("role[person]")
+        expect(@role.run_list_for("PRD")[4]).to eq("role[bird]")
+        expect(@role.run_list_for("PRD")[5]).to eq("role[town]")
         expect(@role.run_list[0]).to be_nil
       end
     end
diff --git a/spec/unit/knife/role_from_file_spec.rb b/spec/unit/knife/role_from_file_spec.rb
index 9379f08..741ff99 100644
--- a/spec/unit/knife/role_from_file_spec.rb
+++ b/spec/unit/knife/role_from_file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::RoleFromFile.load_deps
 
 describe Chef::Knife::RoleFromFile do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleFromFile.new
     @knife.config = {
       :print_after => nil
@@ -39,7 +39,7 @@ describe Chef::Knife::RoleFromFile do
 
   describe "run" do
     it "should load from a file" do
-      expect(@knife.loader).to receive(:load_from).with('roles', 'adam.rb').and_return(@role)
+      expect(@knife.loader).to receive(:load_from).with("roles", "adam.rb").and_return(@role)
       @knife.run
     end
 
@@ -60,8 +60,8 @@ describe Chef::Knife::RoleFromFile do
   describe "run with multiple arguments" do
     it "should load each file" do
       @knife.name_args = [ "adam.rb", "caleb.rb" ]
-      expect(@knife.loader).to receive(:load_from).with('roles', 'adam.rb').and_return(@role)
-      expect(@knife.loader).to receive(:load_from).with('roles', 'caleb.rb').and_return(@role)
+      expect(@knife.loader).to receive(:load_from).with("roles", "adam.rb").and_return(@role)
+      expect(@knife.loader).to receive(:load_from).with("roles", "caleb.rb").and_return(@role)
       @knife.run
     end
   end
diff --git a/spec/unit/knife/role_list_spec.rb b/spec/unit/knife/role_list_spec.rb
index 808a04d..bfbba30 100644
--- a/spec/unit/knife/role_list_spec.rb
+++ b/spec/unit/knife/role_list_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleList do
   before(:each) do
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
     @knife = Chef::Knife::RoleList.new
     allow(@knife).to receive(:output).and_return(true)
     @list = {
       "foo" => "http://example.com/foo",
-      "bar" => "http://example.com/foo"
+      "bar" => "http://example.com/foo",
     }
     allow(Chef::Role).to receive(:list).and_return(@list)
   end
@@ -52,5 +52,3 @@ describe Chef::Knife::RoleList do
     end
   end
 end
-
-
diff --git a/spec/unit/knife/role_run_list_add_spec.rb b/spec/unit/knife/role_run_list_add_spec.rb
index d61c114..419fbdf 100644
--- a/spec/unit/knife/role_run_list_add_spec.rb
+++ b/spec/unit/knife/role_run_list_add_spec.rb
@@ -1,15 +1,15 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 #     http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleRunListAdd do
   before(:each) do
@@ -29,7 +29,7 @@ describe Chef::Knife::RoleRunListAdd do
     }
     @knife.name_args = [ "will", "role[monkey]" ]
     allow(@knife).to receive(:output).and_return(true)
-    @role = Chef::Role.new() 
+    @role = Chef::Role.new()
     allow(@role).to receive(:save).and_return(true)
     allow(Chef::Role).to receive(:load).and_return(@role)
   end
@@ -162,7 +162,7 @@ describe Chef::Knife::RoleRunListAdd do
         expect(@role.run_list[2]).to be_nil
       end
     end
-    
+
     describe "with more than one command" do
       it "should be able to the environment run list by running multiple knife commands" do
         @knife.name_args = [ "will", "role[blue]," ]
diff --git a/spec/unit/knife/role_run_list_clear_spec.rb b/spec/unit/knife/role_run_list_clear_spec.rb
index e5a6e18..61dfc8f 100644
--- a/spec/unit/knife/role_run_list_clear_spec.rb
+++ b/spec/unit/knife/role_run_list_clear_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleRunListClear do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
+    Chef::Config[:role_name] = "will"
     @setup = Chef::Knife::RoleRunListAdd.new
     @setup.name_args = [ "will", "role[monkey]", "role[person]" ]
 
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListClear do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -56,35 +53,32 @@ describe Chef::Knife::RoleRunListClear do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list[0]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list[0]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "should clear an environmental run list of roles and recipes" do
-       it "should remove the items from the run list" do
-         @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will' ]
-         @knife.run
-         expect(@role.run_list[0]).to be_nil
-       end
-     end
+    describe "should clear an environmental run list of roles and recipes" do
+      it "should remove the items from the run list" do
+        @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will" ]
+        @knife.run
+        expect(@role.run_list[0]).to be_nil
+      end
+    end
   end
 end
-
-
-
diff --git a/spec/unit/knife/role_run_list_remove_spec.rb b/spec/unit/knife/role_run_list_remove_spec.rb
index 0f4adf2..704c3d3 100644
--- a/spec/unit/knife/role_run_list_remove_spec.rb
+++ b/spec/unit/knife/role_run_list_remove_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleRunListRemove do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
+    Chef::Config[:role_name] = "will"
     @setup = Chef::Knife::RoleRunListAdd.new
     @setup.name_args = [ "will", "role[monkey]", "role[person]" ]
 
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListRemove do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -56,43 +53,40 @@ describe Chef::Knife::RoleRunListRemove do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list[0]).to eq('role[person]')
-       expect(@role.run_list[1]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list[0]).to eq("role[person]")
+      expect(@role.run_list[1]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "run with a list of roles and recipes" do
-       it "should remove the items from the run list" do
-         @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will', 'role[monkey]' ]
-         @knife.run
-         @knife.name_args = [ 'will', 'recipe[duck::type]' ]
-         @knife.run
-         expect(@role.run_list).not_to include('role[monkey]')
-         expect(@role.run_list).not_to include('recipe[duck::type]')
-         expect(@role.run_list[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list[1]).to eq('role[person]')
-         expect(@role.run_list[2]).to eq('role[bird]')
-         expect(@role.run_list[3]).to eq('role[town]')
-       end
-     end
+    describe "run with a list of roles and recipes" do
+      it "should remove the items from the run list" do
+        @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will", "role[monkey]" ]
+        @knife.run
+        @knife.name_args = [ "will", "recipe[duck::type]" ]
+        @knife.run
+        expect(@role.run_list).not_to include("role[monkey]")
+        expect(@role.run_list).not_to include("recipe[duck::type]")
+        expect(@role.run_list[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list[1]).to eq("role[person]")
+        expect(@role.run_list[2]).to eq("role[bird]")
+        expect(@role.run_list[3]).to eq("role[town]")
+      end
+    end
   end
 end
-
-
-
diff --git a/spec/unit/knife/role_run_list_replace_spec.rb b/spec/unit/knife/role_run_list_replace_spec.rb
index 2ff38f5..91e4993 100644
--- a/spec/unit/knife/role_run_list_replace_spec.rb
+++ b/spec/unit/knife/role_run_list_replace_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleRunListReplace do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
+    Chef::Config[:role_name] = "will"
     @setup = Chef::Knife::RoleRunListAdd.new
     @setup.name_args = [ "will", "role[monkey]", "role[dude]", "role[fixer]" ]
 
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListReplace do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -56,46 +53,46 @@ describe Chef::Knife::RoleRunListReplace do
       @knife.run
     end
 
-     it "should remove the item from the run list" do
-       @setup.run
-       @knife.run
-       expect(@role.run_list[0]).to eq('role[monkey]')
-       expect(@role.run_list[1]).not_to eq('role[dude]')
-       expect(@role.run_list[1]).to eq('role[person]')
-       expect(@role.run_list[2]).to eq('role[fixer]')
-       expect(@role.run_list[3]).to be_nil
-     end
+    it "should remove the item from the run list" do
+      @setup.run
+      @knife.run
+      expect(@role.run_list[0]).to eq("role[monkey]")
+      expect(@role.run_list[1]).not_to eq("role[dude]")
+      expect(@role.run_list[1]).to eq("role[person]")
+      expect(@role.run_list[2]).to eq("role[fixer]")
+      expect(@role.run_list[3]).to be_nil
+    end
 
-     it "should save the node" do
-       expect(@role).to receive(:save).and_return(true)
-       @knife.run
-     end
+    it "should save the node" do
+      expect(@role).to receive(:save).and_return(true)
+      @knife.run
+    end
 
-     it "should print the run list" do
-       expect(@knife).to receive(:output).and_return(true)
-       @knife.config[:print_after] = true
-       @setup.run
-       @knife.run
-     end
+    it "should print the run list" do
+      expect(@knife).to receive(:output).and_return(true)
+      @knife.config[:print_after] = true
+      @setup.run
+      @knife.run
+    end
 
-     describe "run with a list of roles and recipes" do
-       it "should replace the items from the run list" do
-         @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
-         @setup.run
-         @knife.name_args = [ 'will', 'role[monkey]', 'role[gibbon]' ]
-         @knife.run
-         @knife.name_args = [ 'will', 'recipe[duck::type]', 'recipe[duck::mallard]' ]
-         @knife.run
-         expect(@role.run_list).not_to include('role[monkey]')
-         expect(@role.run_list).not_to include('recipe[duck::type]')
-         expect(@role.run_list[0]).to eq('recipe[orange::chicken]')
-         expect(@role.run_list[1]).to eq('role[gibbon]')
-         expect(@role.run_list[2]).to eq('recipe[duck::mallard]')
-         expect(@role.run_list[3]).to eq('role[person]')
-         expect(@role.run_list[4]).to eq('role[bird]')
-         expect(@role.run_list[5]).to eq('role[town]')
-         expect(@role.run_list[6]).to be_nil
-       end
-     end
+    describe "run with a list of roles and recipes" do
+      it "should replace the items from the run list" do
+        @setup.name_args = [ "will", "recipe[orange::chicken]", "role[monkey]", "recipe[duck::type]", "role[person]", "role[bird]", "role[town]" ]
+        @setup.run
+        @knife.name_args = [ "will", "role[monkey]", "role[gibbon]" ]
+        @knife.run
+        @knife.name_args = [ "will", "recipe[duck::type]", "recipe[duck::mallard]" ]
+        @knife.run
+        expect(@role.run_list).not_to include("role[monkey]")
+        expect(@role.run_list).not_to include("recipe[duck::type]")
+        expect(@role.run_list[0]).to eq("recipe[orange::chicken]")
+        expect(@role.run_list[1]).to eq("role[gibbon]")
+        expect(@role.run_list[2]).to eq("recipe[duck::mallard]")
+        expect(@role.run_list[3]).to eq("role[person]")
+        expect(@role.run_list[4]).to eq("role[bird]")
+        expect(@role.run_list[5]).to eq("role[town]")
+        expect(@role.run_list[6]).to be_nil
+      end
+    end
   end
 end
diff --git a/spec/unit/knife/role_run_list_set_spec.rb b/spec/unit/knife/role_run_list_set_spec.rb
index 1350741..ad088e5 100644
--- a/spec/unit/knife/role_run_list_set_spec.rb
+++ b/spec/unit/knife/role_run_list_set_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Will Albenzi (<walbenzi at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +17,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleRunListSet do
   before(:each) do
-    Chef::Config[:role_name]  = "will"
+    Chef::Config[:role_name] = "will"
     @setup = Chef::Knife::RoleRunListAdd.new
     @setup.name_args = [ "will", "role[monkey]", "role[person]", "role[bucket]" ]
 
@@ -41,11 +41,8 @@ describe Chef::Knife::RoleRunListSet do
 
   end
 
-
-
   describe "run" do
 
-
 #    it "should display all the things" do
 #      @knife.run
 #      @role.to_json.should == 'show all the things'
@@ -59,8 +56,8 @@ describe Chef::Knife::RoleRunListSet do
     it "should replace all the items in the runlist with what is specified" do
       @setup.run
       @knife.run
-      expect(@role.run_list[0]).to eq("role[owen]") 
-      expect(@role.run_list[1]).to eq("role[mauntel]") 
+      expect(@role.run_list[0]).to eq("role[owen]")
+      expect(@role.run_list[1]).to eq("role[mauntel]")
       expect(@role.run_list[2]).to be_nil
     end
 
diff --git a/spec/unit/knife/role_show_spec.rb b/spec/unit/knife/role_show_spec.rb
index b086136..fe48e2f 100644
--- a/spec/unit/knife/role_show_spec.rb
+++ b/spec/unit/knife/role_show_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2014 Lamont Granquist
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2014-2016, Lamont Granquist
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::RoleShow do
-  let(:role) { 'base' }
+  let(:role) { "base" }
 
   let(:knife) do
     knife = Chef::Knife::RoleShow.new
@@ -27,29 +27,29 @@ describe Chef::Knife::RoleShow do
     knife
   end
 
-  let(:role_mock) { double('role_mock') }
+  let(:role_mock) { double("role_mock") }
 
-  describe 'run' do
-    it 'should list the role' do
-      expect(Chef::Role).to receive(:load).with('base').and_return(role_mock)
+  describe "run" do
+    it "should list the role" do
+      expect(Chef::Role).to receive(:load).with("base").and_return(role_mock)
       expect(knife).to receive(:format_for_display).with(role_mock)
       knife.run
     end
 
-    it 'should pretty print json' do
-      knife.config[:format] = 'json'
+    it "should pretty print json" do
+      knife.config[:format] = "json"
       stdout = StringIO.new
       allow(knife.ui).to receive(:stdout).and_return(stdout)
-      fake_role_contents = {"foo"=>"bar", "baz"=>"qux"}
-      expect(Chef::Role).to receive(:load).with('base').and_return(fake_role_contents)
+      fake_role_contents = { "foo" => "bar", "baz" => "qux" }
+      expect(Chef::Role).to receive(:load).with("base").and_return(fake_role_contents)
       knife.run
       expect(stdout.string).to eql("{\n  \"foo\": \"bar\",\n  \"baz\": \"qux\"\n}\n")
     end
 
     context "without a role name" do
-      let(:role) { }
+      let(:role) {}
 
-      it 'should print usage and exit when a role name is not provided' do
+      it "should print usage and exit when a role name is not provided" do
         expect(knife).to receive(:show_usage)
         expect(knife.ui).to receive(:fatal)
         expect { knife.run }.to raise_error(SystemExit)
diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb
index a838a21..3a87285 100644
--- a/spec/unit/knife/ssh_spec.rb
+++ b/spec/unit/knife/ssh_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Bryan McLellan <btm at opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm at chef.io>
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'net/ssh'
-require 'net/ssh/multi'
+require "spec_helper"
+require "net/ssh"
+require "net/ssh/multi"
 
 describe Chef::Knife::Ssh do
   before(:each) do
@@ -28,10 +28,10 @@ describe Chef::Knife::Ssh do
   before do
     @knife = Chef::Knife::Ssh.new
     @knife.merge_configs
-    @knife.config[:attribute] = "fqdn"
     @node_foo = Chef::Node.new
     @node_foo.automatic_attrs[:fqdn] = "foo.example.org"
     @node_foo.automatic_attrs[:ipaddress] = "10.0.0.1"
+
     @node_bar = Chef::Node.new
     @node_bar.automatic_attrs[:fqdn] = "bar.example.org"
     @node_bar.automatic_attrs[:ipaddress] = "10.0.0.2"
@@ -52,17 +52,17 @@ describe Chef::Knife::Ssh do
       def self.should_return_specified_attributes
         it "returns an array of the attributes specified on the command line OR config file, if only one is set" do
           @knife.config[:attribute] = "ipaddress"
-          @knife.config[:attribute_from_cli] = "ipaddress"
+          Chef::Config[:knife][:ssh_attribute] = "ipaddress" # this value will be in the config file
           configure_query([@node_foo, @node_bar])
-          expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
+          expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]])
           @knife.configure_session
         end
 
         it "returns an array of the attributes specified on the command line even when a config value is set" do
-          @knife.config[:attribute] = "config_file" # this value will be the config file
-          @knife.config[:attribute_from_cli] = "ipaddress" # this is the value of the command line via #configure_attribute
+          Chef::Config[:knife][:ssh_attribute] = "config_file" # this value will be in the config file
+          @knife.config[:attribute] = "ipaddress" # this is the value of the command line via #configure_attribute
           configure_query([@node_foo, @node_bar])
-          expect(@knife).to receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]])
+          expect(@knife).to receive(:session_from_list).with([["10.0.0.1", nil], ["10.0.0.2", nil]])
           @knife.configure_session
         end
       end
@@ -70,8 +70,8 @@ describe Chef::Knife::Ssh do
       it "searchs for and returns an array of fqdns" do
         configure_query([@node_foo, @node_bar])
         expect(@knife).to receive(:session_from_list).with([
-          ['foo.example.org', nil],
-          ['bar.example.org', nil]
+          ["foo.example.org", nil],
+          ["bar.example.org", nil],
         ])
         @knife.configure_session
       end
@@ -83,12 +83,11 @@ describe Chef::Knife::Ssh do
           @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
           @node_bar.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-2.compute-1.amazonaws.com"
         end
-
         it "returns an array of cloud public hostnames" do
           configure_query([@node_foo, @node_bar])
           expect(@knife).to receive(:session_from_list).with([
-            ['ec2-10-0-0-1.compute-1.amazonaws.com', nil],
-            ['ec2-10-0-0-2.compute-1.amazonaws.com', nil]
+            ["ec2-10-0-0-1.compute-1.amazonaws.com", nil],
+            ["ec2-10-0-0-2.compute-1.amazonaws.com", nil],
           ])
           @knife.configure_session
         end
@@ -98,15 +97,15 @@ describe Chef::Knife::Ssh do
 
       context "when cloud hostnames are available but empty" do
         before do
-          @node_foo.automatic_attrs[:cloud][:public_hostname] = ''
-          @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
+          @node_foo.automatic_attrs[:cloud][:public_hostname] = ""
+          @node_bar.automatic_attrs[:cloud][:public_hostname] = ""
         end
 
         it "returns an array of fqdns" do
           configure_query([@node_foo, @node_bar])
           expect(@knife).to receive(:session_from_list).with([
-            ['foo.example.org', nil],
-            ['bar.example.org', nil]
+            ["foo.example.org", nil],
+            ["bar.example.org", nil],
           ])
           @knife.configure_session
         end
@@ -115,10 +114,10 @@ describe Chef::Knife::Ssh do
       end
 
       it "should raise an error if no host are found" do
-          configure_query([ ])
-          expect(@knife.ui).to receive(:fatal)
-          expect(@knife).to receive(:exit).with(10)
-          @knife.configure_session
+        configure_query([ ])
+        expect(@knife.ui).to receive(:fatal)
+        expect(@knife).to receive(:exit).with(10)
+        @knife.configure_session
       end
 
       context "when there are some hosts found but they do not have an attribute to connect with" do
@@ -144,80 +143,78 @@ describe Chef::Knife::Ssh do
 
       it "returns an array of provided values" do
         @knife.instance_variable_set(:@name_args, ["foo.example.org bar.example.org"])
-        expect(@knife).to receive(:session_from_list).with(['foo.example.org', 'bar.example.org'])
+        expect(@knife).to receive(:session_from_list).with(["foo.example.org", "bar.example.org"])
         @knife.configure_session
       end
     end
   end
 
-  describe "#configure_attribute" do
+  describe "#get_ssh_attribute" do
+    # Order of precedence for ssh target
+    # 1) command line attribute
+    # 2) configuration file
+    # 3) cloud attribute
+    # 4) fqdn
     before do
       Chef::Config[:knife][:ssh_attribute] = nil
       @knife.config[:attribute] = nil
+      @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com"
+      @node_bar.automatic_attrs[:cloud][:public_hostname] = ""
     end
 
     it "should return fqdn by default" do
-      @knife.configure_attribute
-      expect(@knife.config[:attribute]).to eq("fqdn")
+      expect(@knife.get_ssh_attribute(Chef::Node.new)).to eq("fqdn")
     end
 
-    it "should return the value set in the configuration file" do
-      Chef::Config[:knife][:ssh_attribute] = "config_file"
-      @knife.configure_attribute
-      expect(@knife.config[:attribute]).to eq("config_file")
+    it "should return cloud.public_hostname attribute if available" do
+      expect(@knife.get_ssh_attribute(@node_foo)).to eq("cloud.public_hostname")
     end
 
-    it "should return the value set on the command line" do
+    it "should favor to attribute_from_cli over config file and cloud" do
       @knife.config[:attribute] = "command_line"
-      @knife.configure_attribute
-      expect(@knife.config[:attribute]).to eq("command_line")
+      Chef::Config[:knife][:ssh_attribute] = "config_file"
+      expect( @knife.get_ssh_attribute(@node_foo)).to eq("command_line")
     end
 
-    it "should set attribute_from_cli to the value of attribute from the command line" do
-      @knife.config[:attribute] = "command_line"
-      @knife.configure_attribute
-      expect(@knife.config[:attribute]).to eq("command_line")
-      expect(@knife.config[:attribute_from_cli]).to eq("command_line")
+    it "should favor config file over cloud and default" do
+      Chef::Config[:knife][:ssh_attribute] = "config_file"
+      expect( @knife.get_ssh_attribute(@node_foo)).to eq("config_file")
     end
 
-    it "should prefer the command line over the config file for the value of attribute_from_cli" do
-      Chef::Config[:knife][:ssh_attribute] = "config_file"
-      @knife.config[:attribute] = "command_line"
-      @knife.configure_attribute
-      expect(@knife.config[:attribute]).to eq("command_line")
-      expect(@knife.config[:attribute_from_cli]).to eq("command_line")
+    it "should return fqdn if cloud.hostname is empty" do
+      expect( @knife.get_ssh_attribute(@node_bar)).to eq("fqdn")
     end
   end
 
   describe "#session_from_list" do
     before :each do
       @knife.instance_variable_set(:@longest, 0)
-      ssh_config = {:timeout => 50, :user => "locutus", :port => 23 }
-      allow(Net::SSH).to receive(:configuration_for).with('the.b.org').and_return(ssh_config)
+      ssh_config = { :timeout => 50, :user => "locutus", :port => 23 }
+      allow(Net::SSH).to receive(:configuration_for).with("the.b.org").and_return(ssh_config)
     end
 
     it "uses the port from an ssh config file" do
-      @knife.session_from_list([['the.b.org', nil]])
+      @knife.session_from_list([["the.b.org", nil]])
       expect(@knife.session.servers[0].port).to eq(23)
     end
 
     it "uses the port from a cloud attr" do
-      @knife.session_from_list([['the.b.org', 123]])
+      @knife.session_from_list([["the.b.org", 123]])
       expect(@knife.session.servers[0].port).to eq(123)
     end
 
     it "uses the user from an ssh config file" do
-      @knife.session_from_list([['the.b.org', 123]])
+      @knife.session_from_list([["the.b.org", 123]])
       expect(@knife.session.servers[0].user).to eq("locutus")
     end
   end
 
   describe "#ssh_command" do
     let(:execution_channel) { double(:execution_channel, :on_data => nil) }
-    let(:session_channel) { double(:session_channel, :request_pty => nil)}
+    let(:session_channel) { double(:session_channel, :request_pty => nil) }
 
     let(:execution_channel2) { double(:execution_channel, :on_data => nil) }
-    let(:session_channel2) { double(:session_channel, :request_pty => nil)}
+    let(:session_channel2) { double(:session_channel, :request_pty => nil) }
 
     let(:session) { double(:session, :loop => nil) }
 
@@ -282,7 +279,7 @@ describe Chef::Knife::Ssh do
       expect(@query).to receive(:search).and_return([[@node_foo]])
       allow(Chef::Search::Query).to receive(:new).and_return(@query)
       allow(@knife).to receive(:ssh_command).and_return(exit_code)
-      @knife.name_args = ['*:*', 'false']
+      @knife.name_args = ["*:*", "false"]
     end
 
     context "with an error" do
@@ -312,14 +309,14 @@ describe Chef::Knife::Ssh do
 
     context "when setting ssh_password_ng from knife ssh" do
       # in this case ssh_password_ng exists, but ssh_password does not
-      it "should prompt for a password when ssh_passsword_ng is nil"  do
+      it "should prompt for a password when ssh_passsword_ng is nil" do
         @knife.config[:ssh_password_ng] = nil
         expect(@knife).to receive(:get_password).and_return("mysekretpassw0rd")
         @knife.configure_password
         expect(@knife.config[:ssh_password]).to eq("mysekretpassw0rd")
       end
 
-      it "should set ssh_password to false if ssh_password_ng is false"  do
+      it "should set ssh_password to false if ssh_password_ng is false" do
         @knife.config[:ssh_password_ng] = false
         expect(@knife).not_to receive(:get_password)
         @knife.configure_password
@@ -363,14 +360,14 @@ describe Chef::Knife::Ssh do
       end
       context "when setting ssh_password_ng from knife ssh" do
         # in this case ssh_password_ng exists, but ssh_password does not
-        it "should prompt for a password when ssh_passsword_ng is nil"  do
+        it "should prompt for a password when ssh_passsword_ng is nil" do
           @knife.config[:ssh_password_ng] = nil
           expect(@knife).to receive(:get_password).and_return("mysekretpassw0rd")
           @knife.configure_password
           expect(@knife.config[:ssh_password]).to eq("mysekretpassw0rd")
         end
 
-        it "should set ssh_password to the configured knife.rb value if ssh_password_ng is false"  do
+        it "should set ssh_password to the configured knife.rb value if ssh_password_ng is false" do
           @knife.config[:ssh_password_ng] = false
           expect(@knife).not_to receive(:get_password)
           @knife.configure_password
diff --git a/spec/unit/knife/ssl_check_spec.rb b/spec/unit/knife/ssl_check_spec.rb
index 8eda555..180d798 100644
--- a/spec/unit/knife/ssl_check_spec.rb
+++ b/spec/unit/knife/ssl_check_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 #
 
 require "spec_helper"
-require 'stringio'
+require "stringio"
 
 describe Chef::Knife::SslCheck do
 
@@ -67,10 +67,10 @@ describe Chef::Knife::SslCheck do
 
     it "prints an error and exits" do
       expect { ssl_check.run }.to raise_error(SystemExit)
-      expected_stdout=<<-E
+      expected_stdout = <<-E
 USAGE: knife ssl check [URL] (options)
 E
-      expected_stderr=<<-E
+      expected_stderr = <<-E
 ERROR: Given URI: `foo.test' is invalid
 E
       expect(stdout_io.string).to eq(expected_stdout)
@@ -83,10 +83,10 @@ E
 
       it "prints an error and exits" do
         expect { ssl_check.run }.to raise_error(SystemExit)
-        expected_stdout=<<-E
+        expected_stdout = <<-E
 USAGE: knife ssl check [URL] (options)
 E
-        expected_stderr=<<-E
+        expected_stderr = <<-E
 ERROR: Given URI: `#{name_args[0]}' is invalid
 E
         expect(stdout_io.string).to eq(expected_stdout)
@@ -145,7 +145,7 @@ E
     let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket) }
 
     before do
-      expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket)
+      expect(ssl_check).to receive(:proxified_socket).with("foo.example.com", 8443).and_return(tcp_socket)
       expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_check.verify_peer_ssl_context).and_return(ssl_socket)
     end
 
@@ -163,6 +163,7 @@ E
         expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs (no warn)
         expect(ssl_socket).to receive(:connect) # no error
         expect(ssl_socket).to receive(:post_connection_check).with("foo.example.com") # no error
+        expect(ssl_socket).to receive(:hostname=).with("foo.example.com") # no error
       end
 
       it "prints a success message" do
@@ -180,9 +181,9 @@ E
       let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) }
 
       before do
-        trap(:INT, "DEFAULT")
+        @old_signal = trap(:INT, "DEFAULT")
 
-        expect(TCPSocket).to receive(:new).
+        expect(ssl_check).to receive(:proxified_socket).
           with("foo.example.com", 8443).
           and_return(tcp_socket_for_debug)
         expect(OpenSSL::SSL::SSLSocket).to receive(:new).
@@ -190,6 +191,10 @@ E
           and_return(ssl_socket_for_debug)
       end
 
+      after do
+        trap(:INT, @old_signal)
+      end
+
       context "when the certificate's CN does not match the hostname" do
         before do
           expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs
@@ -197,6 +202,7 @@ E
           expect(ssl_socket).to receive(:post_connection_check).
             with("foo.example.com").
             and_raise(OpenSSL::SSL::SSLError)
+          expect(ssl_socket).to receive(:hostname=).with("foo.example.com") # no error
           expect(ssl_socket_for_debug).to receive(:connect)
           expect(ssl_socket_for_debug).to receive(:peer_cert).and_return(self_signed_crt)
         end
@@ -215,6 +221,8 @@ E
           expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs
           expect(ssl_socket).to receive(:connect).
             and_raise(OpenSSL::SSL::SSLError)
+          expect(ssl_socket).to receive(:hostname=).
+            with("foo.example.com") # no error
           expect(ssl_socket_for_debug).to receive(:connect)
           expect(ssl_socket_for_debug).to receive(:peer_cert).and_return(self_signed_crt)
         end
diff --git a/spec/unit/knife/ssl_fetch_spec.rb b/spec/unit/knife/ssl_fetch_spec.rb
index cd0e423..8bb4810 100644
--- a/spec/unit/knife/ssl_fetch_spec.rb
+++ b/spec/unit/knife/ssl_fetch_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/knife/ssl_fetch'
+require "spec_helper"
+require "chef/knife/ssl_fetch"
 
 describe Chef::Knife::SslFetch do
 
@@ -68,10 +68,10 @@ describe Chef::Knife::SslFetch do
 
     it "prints an error and exits" do
       expect { ssl_fetch.run }.to raise_error(SystemExit)
-      expected_stdout=<<-E
+      expected_stdout = <<-E
 USAGE: knife ssl fetch [URL] (options)
 E
-      expected_stderr=<<-E
+      expected_stderr = <<-E
 ERROR: Given URI: `foo.test' is invalid
 E
       expect(stdout_io.string).to eq(expected_stdout)
@@ -84,10 +84,10 @@ E
 
       it "prints an error and exits" do
         expect { ssl_fetch.run }.to raise_error(SystemExit)
-        expected_stdout=<<-E
+        expected_stdout = <<-E
 USAGE: knife ssl fetch [URL] (options)
 E
-        expected_stderr=<<-E
+        expected_stderr = <<-E
 ERROR: Given URI: `#{name_args[0]}' is invalid
 E
         expect(stdout_io.string).to eq(expected_stdout)
@@ -139,7 +139,7 @@ E
     context "when the TLS connection is successful" do
 
       before do
-        expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket)
+        expect(ssl_fetch).to receive(:proxified_socket).with("foo.example.com", 8443).and_return(tcp_socket)
         expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket)
         expect(ssl_socket).to receive(:connect)
         expect(ssl_socket).to receive(:peer_cert_chain).and_return([self_signed_crt])
@@ -161,7 +161,7 @@ E
       let(:unknown_protocol_error) { OpenSSL::SSL::SSLError.new("SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol") }
 
       before do
-        expect(TCPSocket).to receive(:new).with("foo.example.com", 80).and_return(tcp_socket)
+        expect(ssl_fetch).to receive(:proxified_socket).with("foo.example.com", 80).and_return(tcp_socket)
         expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket)
         expect(ssl_socket).to receive(:connect).and_raise(unknown_protocol_error)
 
diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb
index ee44f3b..473598f 100644
--- a/spec/unit/knife/status_spec.rb
+++ b/spec/unit/knife/status_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Sahil Muthoo (<sahil.muthoo at gmail.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::Status do
   before(:each) do
@@ -34,19 +34,19 @@ describe Chef::Knife::Status do
   end
 
   describe "run" do
-    let(:opts) {{filter_result:
+    let(:opts) {{ filter_result:
                  { name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
-                  ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
-                  platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}}
+                   ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
+                   platform_version: ["platform_version"], chef_environment: ["chef_environment"] } }}
 
     it "should default to searching for everything" do
       expect(@query).to receive(:search).with(:node, "*:*", opts)
       @knife.run
     end
 
-    it "should filter healthy nodes" do
-      @knife.config[:hide_healthy] = true
-      expect(@query).to receive(:search).with(:node, "NOT ohai_time:[1428569820 TO 1428573420]", opts)
+    it "should filter by nodes older than some mins" do
+      @knife.config[:hide_by_mins] = 59
+      expect(@query).to receive(:search).with(:node, "NOT ohai_time:[1428569880 TO 1428573420]", opts)
       @knife.run
     end
 
@@ -56,10 +56,10 @@ describe Chef::Knife::Status do
       @knife.run
     end
 
-    it "should filter by environment and health" do
+    it "should filter by environment and nodes older than some mins" do
       @knife.config[:environment] = "production"
-      @knife.config[:hide_healthy] = true
-      expect(@query).to receive(:search).with(:node, "chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
+      @knife.config[:hide_by_mins] = 59
+      expect(@query).to receive(:search).with(:node, "chef_environment:production NOT ohai_time:[1428569880 TO 1428573420]", opts)
       @knife.run
     end
 
@@ -79,22 +79,22 @@ describe Chef::Knife::Status do
         @knife.run
       end
 
-      it "should filter healthy nodes" do
-        @knife.config[:hide_healthy] = true
-        expect(@query).to receive(:search).with(:node, "name:my_custom_name NOT ohai_time:[1428569820 TO 1428573420]", opts)
+      it "should filter by nodes older than some mins with nodename specified" do
+        @knife.config[:hide_by_mins] = 59
+        expect(@query).to receive(:search).with(:node, "name:my_custom_name NOT ohai_time:[1428569880 TO 1428573420]", opts)
         @knife.run
       end
 
-      it "should filter by environment" do
+      it "should filter by environment with nodename specified" do
         @knife.config[:environment] = "production"
         expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production", opts)
         @knife.run
       end
 
-      it "should filter by environment and health" do
+      it "should filter by environment and nodes older than some mins with nodename specified" do
         @knife.config[:environment] = "production"
-        @knife.config[:hide_healthy] = true
-        expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
+        @knife.config[:hide_by_mins] = 59
+        expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production NOT ohai_time:[1428569880 TO 1428573420]", opts)
         @knife.run
       end
     end
diff --git a/spec/unit/knife/tag_create_spec.rb b/spec/unit/knife/tag_create_spec.rb
index 586ec11..6a3ced3 100644
--- a/spec/unit/knife/tag_create_spec.rb
+++ b/spec/unit/knife/tag_create_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::TagCreate do
   before(:each) do
diff --git a/spec/unit/knife/tag_delete_spec.rb b/spec/unit/knife/tag_delete_spec.rb
index e7fa108..3095eda 100644
--- a/spec/unit/knife/tag_delete_spec.rb
+++ b/spec/unit/knife/tag_delete_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::TagDelete do
   before(:each) do
diff --git a/spec/unit/knife/tag_list_spec.rb b/spec/unit/knife/tag_list_spec.rb
index 9c71d22..dceec9a 100644
--- a/spec/unit/knife/tag_list_spec.rb
+++ b/spec/unit/knife/tag_list_spec.rb
@@ -1,4 +1,4 @@
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::TagList do
   before(:each) do
@@ -14,7 +14,7 @@ describe Chef::Knife::TagList do
 
   describe "run" do
     it "can list tags on a node" do
-      expected = %w(sadtag happytag)
+      expected = %w{sadtag happytag}
       expect(@node.tags).to eq(expected)
       expect(@knife).to receive(:output).with(expected)
       @knife.run
diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb
index ad8821c..5ab77d2 100644
--- a/spec/unit/knife/user_create_spec.rb
+++ b/spec/unit/knife/user_create_spec.rb
@@ -1,6 +1,7 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (<steve at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,73 +17,198 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 Chef::Knife::UserCreate.load_deps
 
 describe Chef::Knife::UserCreate do
+  let(:knife) { Chef::Knife::UserCreate.new }
+
+  let(:stderr) {
+    StringIO.new
+  }
+
+  let(:stdout) {
+    StringIO.new
+  }
+
   before(:each) do
-    @knife = Chef::Knife::UserCreate.new
-
-    @stdout = StringIO.new
-    @stderr = StringIO.new
-    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
-    allow(@knife.ui).to receive(:stderr).and_return(@stderr)
-
-    @knife.name_args = [ 'a_user' ]
-    @knife.config[:user_password] = "foobar"
-    @user = Chef::User.new
-    @user.name "a_user"
-    @user_with_private_key = Chef::User.new
-    @user_with_private_key.name "a_user"
-    @user_with_private_key.private_key 'private_key'
-    allow(@user).to receive(:create).and_return(@user_with_private_key)
-    allow(Chef::User).to receive(:new).and_return(@user)
-    allow(Chef::User).to receive(:from_hash).and_return(@user)
-    allow(@knife).to receive(:edit_data).and_return(@user.to_hash)
+    allow(knife.ui).to receive(:stdout).and_return(stdout)
+    allow(knife.ui).to receive(:stderr).and_return(stderr)
+    allow(knife.ui).to receive(:warn)
   end
 
-  it "creates a new user" do
-    expect(Chef::User).to receive(:new).and_return(@user)
-    expect(@user).to receive(:create)
-    @knife.run
-    expect(@stderr.string).to match /created user.+a_user/i
-  end
+  # delete this once OSC11 support is gone
+  context "when only one name_arg is passed" do
+    before do
+      knife.name_args = ["some_user"]
+      allow(knife).to receive(:run_osc_11_user_create).and_raise(SystemExit)
+    end
+
+    it "displays the osc warning" do
+      expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "calls knife osc_user create" do
+      expect(knife).to receive(:run_osc_11_user_create)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
 
-  it "sets the password" do
-    @knife.config[:user_password] = "a_password"
-    expect(@user).to receive(:password).with("a_password")
-    @knife.run
   end
 
-  it "exits with an error if password is blank" do
-    @knife.config[:user_password] = ''
-    expect { @knife.run }.to raise_error SystemExit
-    expect(@stderr.string).to match /You must specify a non-blank password/
+  context "when USERNAME isn't specified" do
+    # from spec/support/shared/unit/knife_shared.rb
+    it_should_behave_like "mandatory field missing" do
+      let(:name_args) { [] }
+      let(:fieldname) { "username" }
+    end
   end
 
-  it "sets the user name" do
-    expect(@user).to receive(:name).with("a_user")
-    @knife.run
+  # uncomment once OSC11 support is gone,
+  # pending doesn't work for shared_examples_for by default
+  #
+  # context "when DISPLAY_NAME isn't specified" do
+  #   # from spec/support/shared/unit/knife_shared.rb
+  #   it_should_behave_like "mandatory field missing" do
+  #     let(:name_args) { ['some_user'] }
+  #     let(:fieldname) { 'display name' }
+  #   end
+  # end
+
+  context "when FIRST_NAME isn't specified" do
+    # from spec/support/shared/unit/knife_shared.rb
+    it_should_behave_like "mandatory field missing" do
+      let(:name_args) { ["some_user", "some_display_name"] }
+      let(:fieldname) { "first name" }
+    end
   end
 
-  it "sets the public key if given" do
-    @knife.config[:user_key] = "/a/filename"
-    allow(File).to receive(:read).with(File.expand_path("/a/filename")).and_return("a_key")
-    expect(@user).to receive(:public_key).with("a_key")
-    @knife.run
+  context "when LAST_NAME isn't specified" do
+    # from spec/support/shared/unit/knife_shared.rb
+    it_should_behave_like "mandatory field missing" do
+      let(:name_args) { ["some_user", "some_display_name", "some_first_name"] }
+      let(:fieldname) { "last name" }
+    end
   end
 
-  it "allows you to edit the data" do
-    expect(@knife).to receive(:edit_data).with(@user)
-    @knife.run
+  context "when EMAIL isn't specified" do
+    # from spec/support/shared/unit/knife_shared.rb
+    it_should_behave_like "mandatory field missing" do
+      let(:name_args) { ["some_user", "some_display_name", "some_first_name", "some_last_name"] }
+      let(:fieldname) { "email" }
+    end
   end
 
-  it "writes the private key to a file when --file is specified" do
-    @knife.config[:file] = "/tmp/a_file"
-    filehandle = double("filehandle")
-    expect(filehandle).to receive(:print).with('private_key')
-    expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
-    @knife.run
+  context "when PASSWORD isn't specified" do
+    # from spec/support/shared/unit/knife_shared.rb
+    it_should_behave_like "mandatory field missing" do
+      let(:name_args) { ["some_user", "some_display_name", "some_first_name", "some_last_name", "some_email"] }
+      let(:fieldname) { "password" }
+    end
   end
+
+  context "when all mandatory fields are validly specified" do
+    before do
+      knife.name_args = ["some_user", "some_display_name", "some_first_name", "some_last_name", "some_email", "some_password"]
+      allow(knife).to receive(:edit_data).and_return(knife.user.to_hash)
+      allow(knife).to receive(:create_user_from_hash).and_return(knife.user)
+    end
+
+    before(:each) do
+      # reset the user field every run
+      knife.user_field = nil
+    end
+
+    it "sets all the mandatory fields" do
+      knife.run
+      expect(knife.user.username).to eq("some_user")
+      expect(knife.user.display_name).to eq("some_display_name")
+      expect(knife.user.first_name).to eq("some_first_name")
+      expect(knife.user.last_name).to eq("some_last_name")
+      expect(knife.user.email).to eq("some_email")
+      expect(knife.user.password).to eq("some_password")
+    end
+
+    context "when user_key and prevent_keygen are passed" do
+      before do
+        knife.config[:user_key] = "some_key"
+        knife.config[:prevent_keygen] = true
+      end
+      it "prints the usage" do
+        expect(knife).to receive(:show_usage)
+        expect { knife.run }.to raise_error(SystemExit)
+      end
+
+      it "prints a relevant error message" do
+        expect { knife.run }.to raise_error(SystemExit)
+        expect(stderr.string).to match /You cannot pass --user-key and --prevent-keygen/
+      end
+    end
+
+    context "when --prevent-keygen is passed" do
+      before do
+        knife.config[:prevent_keygen] = true
+      end
+
+      it "does not set user.create_key" do
+        knife.run
+        expect(knife.user.create_key).to be_falsey
+      end
+    end
+
+    context "when --prevent-keygen is not passed" do
+      it "sets user.create_key to true" do
+        knife.run
+        expect(knife.user.create_key).to be_truthy
+      end
+    end
+
+    context "when --user-key is passed" do
+      before do
+        knife.config[:user_key] = "some_key"
+        allow(File).to receive(:read).and_return("some_key")
+        allow(File).to receive(:expand_path)
+      end
+
+      it "sets user.public_key" do
+        knife.run
+        expect(knife.user.public_key).to eq("some_key")
+      end
+    end
+
+    context "when --user-key is not passed" do
+      it "does not set user.public_key" do
+        knife.run
+        expect(knife.user.public_key).to be_nil
+      end
+    end
+
+    context "when a private_key is returned" do
+      before do
+        allow(knife).to receive(:create_user_from_hash).and_return(Chef::UserV1.from_hash(knife.user.to_hash.merge({ "private_key" => "some_private_key" })))
+      end
+
+      context "when --file is passed" do
+        before do
+          knife.config[:file] = "/some/path"
+        end
+
+        it "creates a new file of the path passed" do
+          filehandle = double("filehandle")
+          expect(filehandle).to receive(:print).with("some_private_key")
+          expect(File).to receive(:open).with("/some/path", "w").and_yield(filehandle)
+          knife.run
+        end
+      end
+
+      context "when --file is not passed" do
+        it "prints the private key to stdout" do
+          expect(knife.ui).to receive(:msg).with("some_private_key")
+          knife.run
+        end
+      end
+    end
+
+  end # when all mandatory fields are validly specified
 end
diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb
index 94cfbf3..0f71b39 100644
--- a/spec/unit/knife/user_delete_spec.rb
+++ b/spec/unit/knife/user_delete_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,50 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UserDelete do
+  let(:knife) { Chef::Knife::UserDelete.new }
+  let(:user) { double("user_object") }
+  let(:stdout) { StringIO.new }
+
   before(:each) do
     Chef::Knife::UserDelete.load_deps
-    @knife = Chef::Knife::UserDelete.new
-    @knife.name_args = [ 'my_user' ]
+    knife.name_args = [ "my_user" ]
+    allow(Chef::UserV1).to receive(:load).and_return(user)
+    allow(user).to receive(:username).and_return("my_user")
+    allow(knife.ui).to receive(:stderr).and_return(stdout)
+    allow(knife.ui).to receive(:stdout).and_return(stdout)
+  end
+
+  # delete this once OSC11 support is gone
+  context "when the username field is not supported by the server" do
+    before do
+      allow(knife).to receive(:run_osc_11_user_delete).and_raise(SystemExit)
+      allow(user).to receive(:username).and_return(nil)
+    end
+
+    it "displays the osc warning" do
+      expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "forwards the command to knife osc_user edit" do
+      expect(knife).to receive(:run_osc_11_user_delete)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
   end
 
-  it 'deletes the user' do
-    expect(@knife).to receive(:delete_object).with(Chef::User, 'my_user')
-    @knife.run
+  it "deletes the user" do
+    #expect(knife).to receive(:delete_object).with(Chef::UserV1, 'my_user')
+    expect(knife).to receive(:delete_object).with("my_user")
+    knife.run
   end
 
-  it 'prints usage and exits when a user name is not provided' do
-    @knife.name_args = []
-    expect(@knife).to receive(:show_usage)
-    expect(@knife.ui).to receive(:fatal)
-    expect { @knife.run }.to raise_error(SystemExit)
+  it "prints usage and exits when a user name is not provided" do
+    knife.name_args = []
+    expect(knife).to receive(:show_usage)
+    expect(knife.ui).to receive(:fatal)
+    expect { knife.run }.to raise_error(SystemExit)
   end
 end
diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb
index 0eb75cf..ec118ed 100644
--- a/spec/unit/knife/user_edit_spec.rb
+++ b/spec/unit/knife/user_edit_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,51 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UserEdit do
+  let(:knife) { Chef::Knife::UserEdit.new }
+
   before(:each) do
     @stderr = StringIO.new
     @stdout = StringIO.new
 
     Chef::Knife::UserEdit.load_deps
-    @knife = Chef::Knife::UserEdit.new
-    allow(@knife.ui).to receive(:stderr).and_return(@stderr)
-    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
-    @knife.name_args = [ 'my_user' ]
-    @knife.config[:disable_editing] = true
+    allow(knife.ui).to receive(:stderr).and_return(@stderr)
+    allow(knife.ui).to receive(:stdout).and_return(@stdout)
+    knife.name_args = [ "my_user" ]
+    knife.config[:disable_editing] = true
+  end
+
+  # delete this once OSC11 support is gone
+  context "when the username field is not supported by the server" do
+    before do
+      allow(knife).to receive(:run_osc_11_user_edit).and_raise(SystemExit)
+      allow(Chef::UserV1).to receive(:load).and_return({ "username" => nil })
+    end
+
+    it "displays the osc warning" do
+      expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "forwards the command to knife osc_user edit" do
+      expect(knife).to receive(:run_osc_11_user_edit)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
   end
 
-  it 'loads and edits the user' do
-    data = { :name => "my_user" }
-    allow(Chef::User).to receive(:load).with("my_user").and_return(data)
-    expect(@knife).to receive(:edit_data).with(data).and_return(data)
-    @knife.run
+  it "loads and edits the user" do
+    data = { "username" => "my_user" }
+    allow(Chef::UserV1).to receive(:load).with("my_user").and_return(data)
+    expect(knife).to receive(:edit_data).with(data).and_return(data)
+    knife.run
   end
 
-  it 'prints usage and exits when a user name is not provided' do
-    @knife.name_args = []
-    expect(@knife).to receive(:show_usage)
-    expect(@knife.ui).to receive(:fatal)
-    expect { @knife.run }.to raise_error(SystemExit)
+  it "prints usage and exits when a user name is not provided" do
+    knife.name_args = []
+    expect(knife).to receive(:show_usage)
+    expect(knife.ui).to receive(:fatal)
+    expect { knife.run }.to raise_error(SystemExit)
   end
 end
diff --git a/spec/unit/knife/user_list_spec.rb b/spec/unit/knife/user_list_spec.rb
index db097a5..bb135db 100644
--- a/spec/unit/knife/user_list_spec.rb
+++ b/spec/unit/knife/user_list_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Steven Danna
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,21 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UserList do
+  let(:knife) { Chef::Knife::UserList.new }
+  let(:stdout) { StringIO.new }
+
   before(:each) do
     Chef::Knife::UserList.load_deps
-    @knife = Chef::Knife::UserList.new
+    allow(knife.ui).to receive(:stderr).and_return(stdout)
+    allow(knife.ui).to receive(:stdout).and_return(stdout)
   end
 
-  it 'lists the users' do
-    expect(Chef::User).to receive(:list)
-    expect(@knife).to receive(:format_list_for_display)
-    @knife.run
+  it "lists the users" do
+    expect(Chef::UserV1).to receive(:list)
+    expect(knife).to receive(:format_list_for_display)
+    knife.run
   end
 end
diff --git a/spec/unit/knife/user_reregister_spec.rb b/spec/unit/knife/user_reregister_spec.rb
index 1268716..d650ff9 100644
--- a/spec/unit/knife/user_reregister_spec.rb
+++ b/spec/unit/knife/user_reregister_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,38 +16,59 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UserReregister do
-  before(:each) do
+  let(:knife) { Chef::Knife::UserReregister.new }
+  let(:user_mock) { double("user_mock", :private_key => "private_key") }
+  let(:stdout) { StringIO.new }
+
+  before do
     Chef::Knife::UserReregister.load_deps
-    @knife = Chef::Knife::UserReregister.new
-    @knife.name_args = [ 'a_user' ]
-    @user_mock = double('user_mock', :private_key => "private_key")
-    allow(Chef::User).to receive(:load).and_return(@user_mock)
-    @stdout = StringIO.new
-    allow(@knife.ui).to receive(:stdout).and_return(@stdout)
+    knife.name_args = [ "a_user" ]
+    allow(Chef::UserV1).to receive(:load).and_return(user_mock)
+    allow(knife.ui).to receive(:stdout).and_return(stdout)
+    allow(knife.ui).to receive(:stderr).and_return(stdout)
+    allow(user_mock).to receive(:username).and_return("a_user")
+  end
+
+  # delete this once OSC11 support is gone
+  context "when the username field is not supported by the server" do
+    before do
+      allow(knife).to receive(:run_osc_11_user_reregister).and_raise(SystemExit)
+      allow(user_mock).to receive(:username).and_return(nil)
+    end
+
+    it "displays the osc warning" do
+      expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "forwards the command to knife osc_user edit" do
+      expect(knife).to receive(:run_osc_11_user_reregister)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
   end
 
-  it 'prints usage and exits when a user name is not provided' do
-    @knife.name_args = []
-    expect(@knife).to receive(:show_usage)
-    expect(@knife.ui).to receive(:fatal)
-    expect { @knife.run }.to raise_error(SystemExit)
+  it "prints usage and exits when a user name is not provided" do
+    knife.name_args = []
+    expect(knife).to receive(:show_usage)
+    expect(knife.ui).to receive(:fatal)
+    expect { knife.run }.to raise_error(SystemExit)
   end
 
-  it 'reregisters the user and prints the key' do
-    expect(@user_mock).to receive(:reregister).and_return(@user_mock)
-    @knife.run
-    expect(@stdout.string).to match( /private_key/ )
+  it "reregisters the user and prints the key" do
+    expect(user_mock).to receive(:reregister).and_return(user_mock)
+    knife.run
+    expect(stdout.string).to match( /private_key/ )
   end
 
-  it 'writes the private key to a file when --file is specified' do
-    expect(@user_mock).to receive(:reregister).and_return(@user_mock)
-    @knife.config[:file] = '/tmp/a_file'
+  it "writes the private key to a file when --file is specified" do
+    expect(user_mock).to receive(:reregister).and_return(user_mock)
+    knife.config[:file] = "/tmp/a_file"
     filehandle = StringIO.new
-    expect(File).to receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle)
-    @knife.run
+    expect(File).to receive(:open).with("/tmp/a_file", "w").and_yield(filehandle)
+    knife.run
     expect(filehandle.string).to eq("private_key")
   end
 end
diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb
index f97cbc3..3a38161 100644
--- a/spec/unit/knife/user_show_spec.rb
+++ b/spec/unit/knife/user_show_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (<steve at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc
+# Author:: Steven Danna (<steve at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,50 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Knife::UserShow do
-  before(:each) do
+  let(:knife) { Chef::Knife::UserShow.new }
+  let(:user_mock) { double("user_mock") }
+  let(:stdout) { StringIO.new }
+
+  before do
     Chef::Knife::UserShow.load_deps
-    @knife = Chef::Knife::UserShow.new
-    @knife.name_args = [ 'my_user' ]
-    @user_mock = double('user_mock')
+    knife.name_args = [ "my_user" ]
+    allow(user_mock).to receive(:username).and_return("my_user")
+    allow(knife.ui).to receive(:stderr).and_return(stdout)
+    allow(knife.ui).to receive(:stdout).and_return(stdout)
+  end
+
+  # delete this once OSC11 support is gone
+  context "when the username field is not supported by the server" do
+    before do
+      allow(knife).to receive(:run_osc_11_user_show).and_raise(SystemExit)
+      allow(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock)
+      allow(user_mock).to receive(:username).and_return(nil)
+    end
+
+    it "displays the osc warning" do
+      expect(knife.ui).to receive(:warn).with(knife.osc_11_warning)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
+
+    it "forwards the command to knife osc_user edit" do
+      expect(knife).to receive(:run_osc_11_user_show)
+      expect { knife.run }.to raise_error(SystemExit)
+    end
   end
 
-  it 'loads and displays the user' do
-    expect(Chef::User).to receive(:load).with('my_user').and_return(@user_mock)
-    expect(@knife).to receive(:format_for_display).with(@user_mock)
-    @knife.run
+  it "loads and displays the user" do
+    expect(Chef::UserV1).to receive(:load).with("my_user").and_return(user_mock)
+    expect(knife).to receive(:format_for_display).with(user_mock)
+    knife.run
   end
 
-  it 'prints usage and exits when a user name is not provided' do
-    @knife.name_args = []
-    expect(@knife).to receive(:show_usage)
-    expect(@knife.ui).to receive(:fatal)
-    expect { @knife.run }.to raise_error(SystemExit)
+  it "prints usage and exits when a user name is not provided" do
+    knife.name_args = []
+    expect(knife).to receive(:show_usage)
+    expect(knife.ui).to receive(:fatal)
+    expect { knife.run }.to raise_error(SystemExit)
   end
 end
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index b748232..698ae20 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@
 module KnifeSpecs
 end
 
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
 
 describe Chef::Knife do
 
@@ -30,10 +30,22 @@ describe Chef::Knife do
 
   let(:knife) { Chef::Knife.new }
 
+  let(:config_location) { File.expand_path("~/.chef/config.rb") }
+
+  let(:config_loader) do
+    instance_double("WorkstationConfigLoader",
+                    load: nil, no_config_found?: false,
+                    config_location: config_location,
+                    :chef_config_dir => "/etc/chef")
+  end
+
   before(:each) do
     Chef::Log.logger = Logger.new(StringIO.new)
 
-    Chef::Config[:node_name]  = "webmonkey.example.com"
+    Chef::Config[:node_name] = "webmonkey.example.com"
+
+    allow(Chef::WorkstationConfigLoader).to receive(:new).and_return(config_loader)
+    allow(config_loader).to receive(:explicit_config_file=)
 
     # Prevent gratuitous code reloading:
     allow(Chef::Knife).to receive(:load_commands)
@@ -51,6 +63,12 @@ describe Chef::Knife do
     Chef::Knife.reset_config_loader!
   end
 
+  it "does not reset Chef::Config[:verbosity to nil if config[:verbosity] is nil" do
+    Chef::Config[:verbosity] = 2
+    Chef::Knife.new
+    expect(Chef::Config[:verbosity]).to eq(2)
+  end
+
   describe "after loading a subcommand" do
     before do
       Chef::Knife.reset_subcommands!
@@ -63,28 +81,28 @@ describe Chef::Knife do
         KnifeSpecs.send(:remove_const, :TestExplicitCategory)
       end
 
-      Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_name_mapping.rb'))
-      Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_explicit_category.rb'))
+      Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_name_mapping.rb"))
+      Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_explicit_category.rb"))
     end
 
     it "has a category based on its name" do
-      expect(KnifeSpecs::TestNameMapping.subcommand_category).to eq('test')
+      expect(KnifeSpecs::TestNameMapping.subcommand_category).to eq("test")
     end
 
     it "has an explicitly defined category if set" do
-      expect(KnifeSpecs::TestExplicitCategory.subcommand_category).to eq('cookbook site')
+      expect(KnifeSpecs::TestExplicitCategory.subcommand_category).to eq("cookbook site")
     end
 
     it "can reference the subcommand by its snake cased name" do
-      expect(Chef::Knife.subcommands['test_name_mapping']).to equal(KnifeSpecs::TestNameMapping)
+      expect(Chef::Knife.subcommands["test_name_mapping"]).to equal(KnifeSpecs::TestNameMapping)
     end
 
     it "lists subcommands by category" do
-      expect(Chef::Knife.subcommands_by_category['test']).to include('test_name_mapping')
+      expect(Chef::Knife.subcommands_by_category["test"]).to include("test_name_mapping")
     end
 
     it "lists subcommands by category when the subcommands have explicit categories" do
-      expect(Chef::Knife.subcommands_by_category['cookbook site']).to include('test_explicit_category')
+      expect(Chef::Knife.subcommands_by_category["cookbook site"]).to include("test_explicit_category")
     end
 
     it "has empty dependency_loader list by default" do
@@ -108,12 +126,20 @@ describe Chef::Knife do
       expect(Chef::Knife.subcommands["super_awesome_command"]).to eq(SuperAwesomeCommand)
     end
 
+    it "records the location of ChefFS-based commands correctly" do
+      class AwesomeCheffsCommand < Chef::ChefFS::Knife
+      end
+
+      Chef::Knife.load_commands
+      expect(Chef::Knife.subcommand_files["awesome_cheffs_command"]).to eq([__FILE__])
+    end
+
     it "guesses a category from a given ARGV" do
       Chef::Knife.subcommands_by_category["cookbook"] << :cookbook
       Chef::Knife.subcommands_by_category["cookbook site"] << :cookbook_site
-      expect(Chef::Knife.guess_category(%w{cookbook foo bar baz})).to eq('cookbook')
-      expect(Chef::Knife.guess_category(%w{cookbook site foo bar baz})).to eq('cookbook site')
-      expect(Chef::Knife.guess_category(%w{cookbook site --help})).to eq('cookbook site')
+      expect(Chef::Knife.guess_category(%w{cookbook foo bar baz})).to eq("cookbook")
+      expect(Chef::Knife.guess_category(%w{cookbook site foo bar baz})).to eq("cookbook site")
+      expect(Chef::Knife.guess_category(%w{cookbook site --help})).to eq("cookbook site")
     end
 
     it "finds a subcommand class based on ARGV" do
@@ -126,13 +152,14 @@ describe Chef::Knife do
 
   describe "the headers include X-Remote-Request-Id" do
 
-    let(:headers) {{"Accept"=>"application/json",
-                    "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
-                    'X-Chef-Version' => Chef::VERSION,
-                    "Host"=>"api.opscode.piab",
-                    "X-REMOTE-REQUEST-ID"=>request_id}}
+    let(:headers) {{ "Accept" => "application/json",
+                     "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
+                     "X-Chef-Version" => Chef::VERSION,
+                     "Host" => "api.opscode.piab",
+                     "X-REMOTE-REQUEST-ID" => request_id,
+    }}
 
-    let(:request_id) {"1234"}
+    let(:request_id) { "1234" }
 
     let(:request_mock) { {} }
 
@@ -168,13 +195,13 @@ describe Chef::Knife do
       if KnifeSpecs.const_defined?(:TestYourself)
         KnifeSpecs.send :remove_const, :TestYourself
       end
-      Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+      Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
       Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) }
     end
 
     it "confirms that the headers include X-Remote-Request-Id" do
       expect(Net::HTTP::Get).to receive(:new).with("/monkey", headers).and_return(request_mock)
-      rest.get_rest("monkey")
+      rest.get("monkey")
     end
   end
 
@@ -183,16 +210,16 @@ describe Chef::Knife do
       if KnifeSpecs.const_defined?(:TestYourself)
         KnifeSpecs.send :remove_const, :TestYourself
       end
-      Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+      Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
       Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) }
     end
 
     it "merges the global knife CLI options" do
       extra_opts = {}
-      extra_opts[:editor] = {:long=>"--editor EDITOR",
-                             :description=>"Set the editor to use for interactive commands",
-                             :short=>"-e EDITOR",
-                             :default=>"/usr/bin/vim"}
+      extra_opts[:editor] = { :long => "--editor EDITOR",
+                              :description => "Set the editor to use for interactive commands",
+                              :short => "-e EDITOR",
+                              :default => "/usr/bin/vim" }
 
       # there is special hackery to return the subcommand instance going on here.
       command = Chef::Knife.run(%w{test yourself}, extra_opts)
@@ -225,7 +252,7 @@ describe Chef::Knife do
       allow(Chef::Knife.ui).to receive(:stderr).and_return(stderr)
       allow(Chef::Knife.ui).to receive(:stdout).and_return(stdout)
       expect(Chef::Knife.ui).to receive(:fatal)
-      expect {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.to raise_error(SystemExit) { |e| expect(e.status).not_to eq(0) }
+      expect { Chef::Knife.run(%w{fuuu uuuu fuuuu}) }.to raise_error(SystemExit) { |e| expect(e.status).not_to eq(0) }
     end
 
     it "loads lazy dependencies" do
@@ -251,6 +278,18 @@ describe Chef::Knife do
                                         :default => "default-value")
       end
 
+      it "sets the default log_location to STDERR for Chef::Log warnings" do
+        knife_command = KnifeSpecs::TestYourself.new([])
+        knife_command.configure_chef
+        expect(Chef::Config[:log_location]).to eq(STDERR)
+      end
+
+      it "sets the default log_level to warn so we can issue Chef::Log.warn" do
+        knife_command = KnifeSpecs::TestYourself.new([])
+        knife_command.configure_chef
+        expect(Chef::Config[:log_level]).to eql(:warn)
+      end
+
       it "prefers the default value if no config or command line value is present" do
         knife_command = KnifeSpecs::TestYourself.new([]) #empty argv
         knife_command.configure_chef
@@ -272,11 +311,11 @@ describe Chef::Knife do
       end
 
       it "merges `listen` config to Chef::Config" do
-        Chef::Knife.run(%w[test yourself --no-listen], Chef::Application::Knife.options)
+        Chef::Knife.run(%w{test yourself --no-listen}, Chef::Application::Knife.options)
         expect(Chef::Config[:listen]).to be(false)
       end
 
-      context "verbosity is greater than zero" do
+      context "verbosity is one" do
         let(:fake_config) { "/does/not/exist/knife.rb" }
 
         before do
@@ -294,6 +333,13 @@ describe Chef::Knife do
           knife.configure_chef
         end
       end
+
+      it "does not humanize the exception if Chef::Config[:verbosity] is two" do
+        Chef::Config[:verbosity] = 2
+        allow(knife).to receive(:run).and_raise(Exception)
+        expect(knife).not_to receive(:humanize_exception)
+        expect { knife.run_with_pretty_exceptions }.to raise_error(Exception)
+      end
     end
   end
 
@@ -303,12 +349,12 @@ describe Chef::Knife do
 
     before do
       unless KnifeSpecs.const_defined?(:TestYourself)
-        Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb'))
+        Kernel.load(File.join(CHEF_SPEC_DATA, "knife_subcommand", "test_yourself.rb"))
       end
     end
 
     it "it parses the options passed to it" do
-      expect(knife.config[:scro]).to eq('scrogramming')
+      expect(knife.config[:scro]).to eq("scrogramming")
     end
 
     it "extracts its command specific args from the full arg list" do
@@ -350,8 +396,8 @@ describe Chef::Knife do
       allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("403 Forbidden", response))
       allow(knife).to receive(:username).and_return("sadpanda")
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action])
-      expect(stderr.string).to match(%r[Response:  y u no administrator])
+      expect(stderr.string).to match(%r{ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action})
+      expect(stderr.string).to match(%r{Response:  y u no administrator})
     end
 
     it "formats 400s nicely" do
@@ -360,8 +406,8 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "y u search wrong"))
       allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: The data in your request was invalid])
-      expect(stderr.string).to match(%r[Response: y u search wrong])
+      expect(stderr.string).to match(%r{ERROR: The data in your request was invalid})
+      expect(stderr.string).to match(%r{Response: y u search wrong})
     end
 
     it "formats 404s nicely" do
@@ -370,8 +416,24 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nothing to see here"))
       allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: The object you are looking for could not be found])
-      expect(stderr.string).to match(%r[Response: nothing to see here])
+      expect(stderr.string).to match(%r{ERROR: The object you are looking for could not be found})
+      expect(stderr.string).to match(%r{Response: nothing to see here})
+    end
+
+    it "formats 406s (non-supported API version error) nicely" do
+      response = Net::HTTPNotAcceptable.new("1.1", "406", "Not Acceptable")
+      response.instance_variable_set(:@read, true) # I hate you, net/http.
+
+      # set the header
+      response["x-ops-server-api-version"] = Chef::JSONCompat.to_json(:min_version => "0", :max_version => "1", :request_version => "10000000")
+
+      allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone"))
+      allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("406 Not Acceptable", response))
+
+      knife.run_with_pretty_exceptions
+      expect(stderr.string).to include("The request that Knife sent was using API version 10000000")
+      expect(stderr.string).to include("The Chef server you sent the request to supports a min API verson of 0 and a max API version of 1")
+      expect(stderr.string).to include("Please either update your Chef client or server to be a compatible set")
     end
 
     it "formats 500s nicely" do
@@ -380,8 +442,8 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone"))
       allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: internal server error])
-      expect(stderr.string).to match(%r[Response: sad trombone])
+      expect(stderr.string).to match(%r{ERROR: internal server error})
+      expect(stderr.string).to match(%r{Response: sad trombone})
     end
 
     it "formats 502s nicely" do
@@ -390,8 +452,8 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "sadder trombone"))
       allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: bad gateway])
-      expect(stderr.string).to match(%r[Response: sadder trombone])
+      expect(stderr.string).to match(%r{ERROR: bad gateway})
+      expect(stderr.string).to match(%r{Response: sadder trombone})
     end
 
     it "formats 503s nicely" do
@@ -400,8 +462,8 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "saddest trombone"))
       allow(knife).to receive(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: Service temporarily unavailable])
-      expect(stderr.string).to match(%r[Response: saddest trombone])
+      expect(stderr.string).to match(%r{ERROR: Service temporarily unavailable})
+      expect(stderr.string).to match(%r{Response: saddest trombone})
     end
 
     it "formats other HTTP errors nicely" do
@@ -410,34 +472,34 @@ describe Chef::Knife do
       allow(response).to receive(:body).and_return(Chef::JSONCompat.to_json(:error => "nobugfixtillyoubuy"))
       allow(knife).to receive(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: Payment Required])
-      expect(stderr.string).to match(%r[Response: nobugfixtillyoubuy])
+      expect(stderr.string).to match(%r{ERROR: Payment Required})
+      expect(stderr.string).to match(%r{Response: nobugfixtillyoubuy})
     end
 
     it "formats NameError and NoMethodError nicely" do
       allow(knife).to receive(:run).and_raise(NameError.new("Undefined constant FUUU"))
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: knife encountered an unexpected error])
-      expect(stderr.string).to match(%r[This may be a bug in the 'knife' knife command or plugin])
-      expect(stderr.string).to match(%r[Exception: NameError: Undefined constant FUUU])
+      expect(stderr.string).to match(%r{ERROR: knife encountered an unexpected error})
+      expect(stderr.string).to match(%r{This may be a bug in the 'knife' knife command or plugin})
+      expect(stderr.string).to match(%r{Exception: NameError: Undefined constant FUUU})
     end
 
     it "formats missing private key errors nicely" do
-      allow(knife).to receive(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new('key not there'))
+      allow(knife).to receive(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new("key not there"))
       allow(knife).to receive(:api_key).and_return("/home/root/.chef/no-key-here.pem")
       knife.run_with_pretty_exceptions
-      expect(stderr.string).to match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem])
-      expect(stderr.string).to match(%r[Check your configuration file and ensure that your private key is readable])
+      expect(stderr.string).to match(%r{ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem})
+      expect(stderr.string).to match(%r{Check your configuration file and ensure that your private key is readable})
     end
 
     it "formats connection refused errors nicely" do
-      allow(knife).to receive(:run).and_raise(Errno::ECONNREFUSED.new('y u no shut up'))
+      allow(knife).to receive(:run).and_raise(Errno::ECONNREFUSED.new("y u no shut up"))
       knife.run_with_pretty_exceptions
       # Errno::ECONNREFUSED message differs by platform
       # *nix = Errno::ECONNREFUSED: Connection refused
       # win32: Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it.
-      expect(stderr.string).to match(%r[ERROR: Network Error: .* - y u no shut up])
-      expect(stderr.string).to match(%r[Check your knife configuration and network settings])
+      expect(stderr.string).to match(%r{ERROR: Network Error: .* - y u no shut up})
+      expect(stderr.string).to match(%r{Check your knife configuration and network settings})
     end
 
     it "formats SSL errors nicely and suggests to use `knife ssl check` and `knife ssl fetch`" do
@@ -446,7 +508,7 @@ describe Chef::Knife do
 
       knife.run_with_pretty_exceptions
 
-      expected_message=<<-MSG
+      expected_message = <<-MSG
 ERROR: Could not establish a secure connection to the server.
 Use `knife ssl check` to troubleshoot your SSL configuration.
 If your Chef Server uses a self-signed certificate, you can use
diff --git a/spec/unit/lib_backcompat_spec.rb b/spec/unit/lib_backcompat_spec.rb
new file mode 100644
index 0000000..c7dfee5
--- /dev/null
+++ b/spec/unit/lib_backcompat_spec.rb
@@ -0,0 +1,34 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe "lib-backcompat" do
+  it "require 'chef/chef_fs/file_system/chef_server_root_dir' yields the proper class" do
+    require "chef/chef_fs/file_system/chef_server_root_dir"
+    expect(Chef::ChefFS::FileSystem::ChefServerRootDir).to eq(Chef::ChefFS::FileSystem::ChefServer::ChefServerRootDir)
+  end
+  it "require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir' yields the proper class" do
+    require "chef/chef_fs/file_system/chef_repository_file_system_root_dir"
+    expect(Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir).to eq(Chef::ChefFS::FileSystem::Repository::ChefRepositoryFileSystemRootDir)
+  end
+  it "require 'chef/chef_fs/file_system/acl_entry' yields the proper class" do
+    require "chef/chef_fs/file_system/acl_entry"
+    expect(Chef::ChefFS::FileSystem::AclEntry).to eq(Chef::ChefFS::FileSystem::ChefServer::AclEntry)
+  end
+end
diff --git a/spec/unit/log/syslog_spec.rb b/spec/unit/log/syslog_spec.rb
new file mode 100644
index 0000000..ebf1418
--- /dev/null
+++ b/spec/unit/log/syslog_spec.rb
@@ -0,0 +1,53 @@
+#
+# Author:: SAWANOBORI Yukihiko (<sawanoboriyu at higanworks.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef"
+
+describe "Chef::Log::Syslog", :unix_only => true do
+  let(:syslog) { Chef::Log::Syslog.new }
+  let(:app) { Chef::Application.new }
+
+  before do
+    Chef::Log.init(MonoLogger.new(syslog))
+    @old_log_level = Chef::Log.level
+    Chef::Log.level = :info
+    @old_loggers = Chef::Log.loggers
+    Chef::Log.use_log_devices([syslog])
+  end
+
+  after do
+    Chef::Log.level = @old_log_level
+    Chef::Log.use_log_devices(@old_loggers)
+  end
+
+  it "should send message with severity info to syslog." do
+    expect(syslog).to receive(:info).with("*** Chef 12.4.0.dev.0 ***")
+    Chef::Log.info("*** Chef 12.4.0.dev.0 ***")
+  end
+
+  it "should send message with severity warning to syslog." do
+    expect(syslog).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+    Chef::Log.warn("No config file found or specified on command line, using command line options.")
+  end
+
+  it "should fallback into send message with severity info to syslog when wrong format." do
+    expect(syslog).to receive(:info).with("chef message")
+    syslog.write("chef message")
+  end
+end
diff --git a/spec/unit/log/winevt_spec.rb b/spec/unit/log/winevt_spec.rb
new file mode 100644
index 0000000..d5d4521
--- /dev/null
+++ b/spec/unit/log/winevt_spec.rb
@@ -0,0 +1,55 @@
+#
+# Author:: Jay Mundrawala (jdm at chef.io)
+# Author:: SAWANOBORI Yukihiko (<sawanoboriyu at higanworks.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Log::WinEvt do
+  let(:evtlog) { instance_double("Win32::EventLog") }
+  let(:winevt) { Chef::Log::WinEvt.new(evtlog) }
+  let(:app) { Chef::Application.new }
+
+  before do
+
+    Chef::Log.init(MonoLogger.new(winevt))
+    @old_log_level = Chef::Log.level
+    Chef::Log.level = :info
+    @old_loggers = Chef::Log.loggers
+    Chef::Log.use_log_devices([winevt])
+  end
+
+  after do
+    Chef::Log.level = @old_log_level
+    Chef::Log.use_log_devices(@old_loggers)
+  end
+
+  it "should send message with severity info to Windows Event Log." do
+    expect(winevt).to receive(:info).with("*** Chef 12.4.0.dev.0 ***")
+    Chef::Log.info("*** Chef 12.4.0.dev.0 ***")
+  end
+
+  it "should send message with severity warning to Windows Event Log." do
+    expect(winevt).to receive(:warn).with("No config file found or specified on command line, using command line options.")
+    Chef::Log.warn("No config file found or specified on command line, using command line options.")
+  end
+
+  it "should fallback into send message with severity info to Windows Event Log when wrong format." do
+    expect(winevt).to receive(:info).with("chef message")
+    winevt.write("chef message")
+  end
+end
diff --git a/spec/unit/log_spec.rb b/spec/unit/log_spec.rb
index 7be40f7..929a24a 100644
--- a/spec/unit/log_spec.rb
+++ b/spec/unit/log_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'tempfile'
-require 'logger'
-require 'spec_helper'
+require "tempfile"
+require "logger"
+require "spec_helper"
 
 describe Chef::Log do
 end
diff --git a/spec/unit/lwrp_spec.rb b/spec/unit/lwrp_spec.rb
index ec39174..5afd838 100644
--- a/spec/unit/lwrp_spec.rb
+++ b/spec/unit/lwrp_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,44 +16,62 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "tmpdir"
+require "fileutils"
+require "chef/mixin/convert_to_class_name"
 
 module LwrpConstScopingConflict
 end
 
 describe "LWRP" do
+  include Chef::Mixin::ConvertToClassName
+
   before do
     @original_VERBOSE = $VERBOSE
     $VERBOSE = nil
+    Chef::Resource::LWRPBase.class_eval { @loaded_lwrps = {} }
   end
 
   after do
     $VERBOSE = @original_VERBOSE
   end
 
+  def get_lwrp(name)
+    Chef::ResourceResolver.resolve(name)
+  end
+
+  def get_lwrp_provider(name)
+    old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+    Chef::Config[:treat_deprecation_warnings_as_errors] = false
+    begin
+      Chef::Provider.const_get(convert_to_class_name(name.to_s))
+    ensure
+      Chef::Config[:treat_deprecation_warnings_as_errors] = old_treat_deprecation_warnings_as_errors
+    end
+  end
+
   describe "when overriding an existing class" do
     before :each do
       allow($stderr).to receive(:write)
     end
 
     it "should not skip loading a resource when there's a top level symbol of the same name" do
-      Object.const_set('LwrpFoo', Class.new)
+      Object.const_set("LwrpFoo", Class.new)
       file = File.expand_path( "lwrp/resources/foo.rb", CHEF_SPEC_DATA)
       expect(Chef::Log).not_to receive(:info).with(/Skipping/)
       expect(Chef::Log).not_to receive(:debug).with(/anymore/)
       Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
-      Object.send(:remove_const, 'LwrpFoo')
-      Chef::Resource.send(:remove_const, 'LwrpFoo')
+      Object.send(:remove_const, "LwrpFoo")
     end
 
     it "should not skip loading a provider when there's a top level symbol of the same name" do
-      Object.const_set('LwrpBuckPasser', Class.new)
+      Object.const_set("LwrpBuckPasser", Class.new)
       file = File.expand_path( "lwrp/providers/buck_passer.rb", CHEF_SPEC_DATA)
       expect(Chef::Log).not_to receive(:info).with(/Skipping/)
       expect(Chef::Log).not_to receive(:debug).with(/anymore/)
       Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
-      Object.send(:remove_const, 'LwrpBuckPasser')
-      Chef::Provider.send(:remove_const, 'LwrpBuckPasser')
+      Object.send(:remove_const, "LwrpBuckPasser")
     end
 
     # @todo: we need a before block to manually remove_const all of the LWRPs that we
@@ -66,8 +84,7 @@ describe "LWRP" do
       end
 
       Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
-        expect(Chef::Log).to receive(:info).with(/Skipping/)
-        expect(Chef::Log).to receive(:debug).with(/anymore/)
+        expect(Chef::Log).to receive(:debug).with(/Skipping/)
         Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
       end
     end
@@ -78,8 +95,7 @@ describe "LWRP" do
       end
 
       Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file|
-        expect(Chef::Log).to receive(:info).with(/Skipping/)
-        expect(Chef::Log).to receive(:debug).with(/anymore/)
+        expect(Chef::Log).to receive(:debug).with(/Skipping/)
         Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil)
       end
     end
@@ -90,7 +106,7 @@ describe "LWRP" do
       Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
         Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
       end
-      first_lwr_foo_class = Chef::Resource::LwrpFoo
+      first_lwr_foo_class = get_lwrp(:lwrp_foo)
       expect(Chef::Resource.resource_classes).to include(first_lwr_foo_class)
       Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file|
         Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
@@ -106,40 +122,91 @@ describe "LWRP" do
 
   end
 
-  describe "Lightweight Chef::Resource" do
+  context "When an LWRP resource in cookbook l-w-r-p is loaded" do
+    before do
+      @tmpdir = Dir.mktmpdir("lwrp_test")
+      resource_path = File.join(@tmpdir, "foo.rb")
+      IO.write(resource_path, "default_action :create")
+      provider_path = File.join(@tmpdir, "foo.rb")
+      IO.write(provider_path, <<-EOM)
+        action :create do
+          raise "hi"
+        end
+      EOM
+    end
+
+    it "Can find the resource at l_w_r_p_foo" do
+    end
+  end
 
+  context "When an LWRP resource lwrp_foo is loaded" do
     before do
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file|
-        Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
+      @tmpdir = Dir.mktmpdir("lwrp_test")
+      @lwrp_path = File.join(@tmpdir, "foo.rb")
+      content = IO.read(File.expand_path("../../data/lwrp/resources/foo.rb", __FILE__))
+      IO.write(@lwrp_path, content)
+      Chef::Resource::LWRPBase.build_from_file("lwrp", @lwrp_path, nil)
+      @original_resource = Chef::ResourceResolver.resolve(:lwrp_foo)
+    end
+
+    after do
+      FileUtils.remove_entry @tmpdir
+    end
+
+    context "And the LWRP is asked to load again, this time with different code" do
+      before do
+        content = IO.read(File.expand_path("../../data/lwrp_override/resources/foo.rb", __FILE__))
+        IO.write(@lwrp_path, content)
+        Chef::Resource::LWRPBase.build_from_file("lwrp", @lwrp_path, nil)
       end
 
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file|
+      it "Should load the old content, and not the new" do
+        resource = Chef::ResourceResolver.resolve(:lwrp_foo)
+        expect(resource).to eq @original_resource
+        expect(resource.default_action).to eq([:pass_buck])
+        expect(Chef.method_defined?(:method_created_by_override_lwrp_foo)).to be_falsey
+      end
+    end
+  end
+
+  describe "Lightweight Chef::Resource" do
+
+    before do
+      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file|
         Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil)
       end
     end
 
-    it "should load the resource into a properly-named class" do
-      expect(Chef::Resource.const_get("LwrpFoo")).to be_kind_of(Class)
+    it "should be resolvable with Chef::ResourceResolver.resolve(:lwrp_foo)" do
+      expect(Chef::ResourceResolver.resolve(:lwrp_foo, node: Chef::Node.new)).to eq(get_lwrp(:lwrp_foo))
     end
 
     it "should set resource_name" do
-      expect(Chef::Resource::LwrpFoo.new("blah").resource_name).to eql(:lwrp_foo)
+      expect(get_lwrp(:lwrp_foo).new("blah").resource_name).to eql(:lwrp_foo)
+    end
+
+    it "should output the resource_name in .to_s" do
+      expect(get_lwrp(:lwrp_foo).new("blah").to_s).to eq "lwrp_foo[blah]"
+    end
+
+    it "should have a class that outputs a reasonable string" do
+      expect(get_lwrp(:lwrp_foo).to_s).to eq "Custom resource lwrp_foo from cookbook lwrp"
     end
 
     it "should add the specified actions to the allowed_actions array" do
-      expect(Chef::Resource::LwrpFoo.new("blah").allowed_actions).to include(:pass_buck, :twiddle_thumbs)
+      expect(get_lwrp(:lwrp_foo).new("blah").allowed_actions).to include(:pass_buck, :twiddle_thumbs)
     end
 
     it "should set the specified action as the default action" do
-      expect(Chef::Resource::LwrpFoo.new("blah").action).to eq(:pass_buck)
+      expect(get_lwrp(:lwrp_foo).new("blah").action).to eq([:pass_buck])
     end
 
     it "should create a method for each attribute" do
-      expect(Chef::Resource::LwrpFoo.new("blah").methods.map{ |m| m.to_sym}).to include(:monkey)
+      expect(get_lwrp(:lwrp_foo).new("blah").methods.map { |m| m.to_sym }).to include(:monkey)
     end
 
     it "should build attribute methods that respect validation rules" do
-      expect { Chef::Resource::LwrpFoo.new("blah").monkey(42) }.to raise_error(ArgumentError)
+      expect { get_lwrp(:lwrp_foo).new("blah").monkey(42) }.to raise_error(ArgumentError)
     end
 
     it "should have access to the run context and node during class definition" do
@@ -151,7 +218,7 @@ describe "LWRP" do
         Chef::Resource::LWRPBase.build_from_file("lwrp", file, run_context)
       end
 
-      cls = Chef::Resource.const_get("LwrpNodeattr")
+      cls = get_lwrp(:lwrp_nodeattr)
       expect(cls.node).to be_kind_of(Chef::Node)
       expect(cls.run_context).to be_kind_of(Chef::RunContext)
       expect(cls.node[:penguin_name]).to eql("jackass")
@@ -175,31 +242,23 @@ describe "LWRP" do
         expect(klass.resource_name).to eq(:foo)
       end
 
-      context "when creating a new instance" do
-        it "raises an exception if resource_name is nil" do
-          expect {
-            klass.new('blah')
-          }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
-        end
-      end
-
       context "lazy default values" do
         let(:klass) do
           Class.new(Chef::Resource::LWRPBase) do
             self.resource_name = :sample_resource
-            attribute :food,  :default => lazy { 'BACON!'*3 }
-            attribute :drink, :default => lazy { |r| "Drink after #{r.food}!"}
+            attribute :food,  :default => lazy { "BACON!" * 3 }
+            attribute :drink, :default => lazy { |r| "Drink after #{r.food}!" }
           end
         end
 
-        let(:instance) { klass.new('kitchen') }
+        let(:instance) { klass.new("kitchen") }
 
         it "evaluates the default value when requested" do
-          expect(instance.food).to eq('BACON!BACON!BACON!')
+          expect(instance.food).to eq("BACON!BACON!BACON!")
         end
 
         it "evaluates yields self to the block" do
-          expect(instance.drink).to eq('Drink after BACON!BACON!BACON!!')
+          expect(instance.drink).to eq("Drink after BACON!BACON!BACON!!")
         end
       end
     end
@@ -225,17 +284,17 @@ describe "LWRP" do
         end
       end
 
-      context "when the child does not defined the methods" do
+      context "when the child does not define the methods" do
         let(:child) do
           Class.new(parent)
         end
 
         it "delegates #actions to the parent" do
-          expect(child.actions).to eq([:eat, :sleep])
+          expect(child.actions).to eq([:nothing, :eat, :sleep])
         end
 
         it "delegates #default_action to the parent" do
-          expect(child.default_action).to eq(:eat)
+          expect(child.default_action).to eq([:eat])
         end
       end
 
@@ -248,11 +307,11 @@ describe "LWRP" do
         end
 
         it "does not delegate #actions to the parent" do
-          expect(child.actions).to eq([:dont_eat, :dont_sleep])
+          expect(child.actions).to eq([:nothing, :dont_eat, :dont_sleep])
         end
 
         it "does not delegate #default_action to the parent" do
-          expect(child.default_action).to eq(:dont_eat)
+          expect(child.default_action).to eq([:dont_eat])
         end
       end
 
@@ -266,117 +325,200 @@ describe "LWRP" do
         end
 
         def raise_if_deprecated!
-          if Chef::VERSION.split('.').first.to_i > 12
+          if Chef::VERSION.split(".").first.to_i > 12
             raise "This test should be removed and the associated code should be removed!"
           end
         end
 
         it "amends actions when they are already defined" do
           raise_if_deprecated!
-          expect(child.actions).to eq([:eat, :sleep, :drink])
+          expect(child.actions).to eq([:nothing, :eat, :sleep, :drink])
+        end
+      end
+    end
+
+    describe "when actions is set to an array" do
+      let(:resource_class) do
+        Class.new(Chef::Resource::LWRPBase) do
+          actions [ :eat, :sleep ]
         end
       end
+      let(:resource) do
+        resource_class.new("blah")
+      end
+      it "actions includes those actions" do
+        expect(resource_class.actions).to eq [ :nothing, :eat, :sleep ]
+      end
+      it "allowed_actions includes those actions" do
+        expect(resource_class.allowed_actions).to eq [ :nothing, :eat, :sleep ]
+      end
+      it "resource.allowed_actions includes those actions" do
+        expect(resource.allowed_actions).to eq [ :nothing, :eat, :sleep ]
+      end
     end
 
+    describe "when allowed_actions is set to an array" do
+      let(:resource_class) do
+        Class.new(Chef::Resource::LWRPBase) do
+          allowed_actions [ :eat, :sleep ]
+        end
+      end
+      let(:resource) do
+        resource_class.new("blah")
+      end
+      it "actions includes those actions" do
+        expect(resource_class.actions).to eq [ :nothing, :eat, :sleep ]
+      end
+      it "allowed_actions includes those actions" do
+        expect(resource_class.allowed_actions).to eq [ :nothing, :eat, :sleep ]
+      end
+      it "resource.allowed_actions includes those actions" do
+        expect(resource.allowed_actions).to eq [ :nothing, :eat, :sleep ]
+      end
+    end
   end
 
   describe "Lightweight Chef::Provider" do
-    before do
-      @node = Chef::Node.new
-      @node.automatic[:platform] = :ubuntu
-      @node.automatic[:platform_version] = '8.10'
-      @events = Chef::EventDispatch::Dispatcher.new
-      @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events)
-      @runner = Chef::Runner.new(@run_context)
-    end
 
-    before(:each) do
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file|
-        Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context)
+    let(:node) do
+      Chef::Node.new.tap do |n|
+        n.automatic[:platform] = :ubuntu
+        n.automatic[:platform_version] = "8.10"
       end
+    end
 
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file|
-        Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context)
-      end
+    let(:events) { Chef::EventDispatch::Dispatcher.new }
 
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "providers", "*"))].each do |file|
-        Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context)
-      end
+    let(:run_context) { Chef::RunContext.new(node, Chef::CookbookCollection.new({}), events) }
 
-      Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "providers", "*"))].each do |file|
-        Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context)
+    let(:runner) { Chef::Runner.new(run_context) }
+
+    let(:lwrp_cookbok_name) { "lwrp" }
+
+    before do
+      Chef::Provider::LWRPBase.class_eval { @loaded_lwrps = {} }
+    end
+
+    before(:each) do
+      Dir[File.expand_path(File.expand_path("../../data/lwrp/resources/*", __FILE__))].each do |file|
+        Chef::Resource::LWRPBase.build_from_file(lwrp_cookbok_name, file, run_context)
       end
 
+      Dir[File.expand_path(File.expand_path("../../data/lwrp/providers/*", __FILE__))].each do |file|
+        Chef::Provider::LWRPBase.build_from_file(lwrp_cookbok_name, file, run_context)
+      end
     end
 
     it "should properly handle a new_resource reference" do
-      resource = Chef::Resource::LwrpFoo.new("morpheus")
+      resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
       resource.monkey("bob")
-      resource.provider(:lwrp_monkey_name_printer)
-      resource.run_context = @run_context
+      resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
 
       provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
       provider.action_twiddle_thumbs
     end
 
-    it "should load the provider into a properly-named class" do
-      expect(Chef::Provider.const_get("LwrpBuckPasser")).to be_kind_of(Class)
-    end
+    context "provider class created" do
+      before do
+        @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      end
 
-    it "should create a method for each attribute" do
-      new_resource = double("new resource").as_null_object
-      expect(Chef::Provider::LwrpBuckPasser.new(nil, new_resource).methods.map{|m|m.to_sym}).to include(:action_pass_buck)
-      expect(Chef::Provider::LwrpThumbTwiddler.new(nil, new_resource).methods.map{|m|m.to_sym}).to include(:action_twiddle_thumbs)
+      after do
+        Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors
+      end
+
+      it "should load the provider into a properly-named class" do
+        expect(Chef::Provider.const_get("LwrpBuckPasser")).to be_kind_of(Class)
+        expect(Chef::Provider::LwrpBuckPasser <= Chef::Provider::LWRPBase).to be_truthy
+      end
+
+      it "should create a method for each action" do
+        expect(get_lwrp_provider(:lwrp_buck_passer).instance_methods).to include(:action_pass_buck)
+        expect(get_lwrp_provider(:lwrp_thumb_twiddler).instance_methods).to include(:action_twiddle_thumbs)
+      end
+
+      it "sets itself as a provider for a resource of the same name" do
+        found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :lwrp_buck_passer)
+        # we bypass the per-file loading to get the file to load each time,
+        # which creates the LWRP class repeatedly. New things get prepended to
+        # the list of providers.
+        expect(found_providers.first).to eq(get_lwrp_provider(:lwrp_buck_passer))
+      end
+
+      context "with a cookbook with an underscore in the name" do
+
+        let(:lwrp_cookbok_name) { "l_w_r_p" }
+
+        it "sets itself as a provider for a resource of the same name" do
+          found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer)
+          expect(found_providers.size).to eq(1)
+          expect(found_providers.last).to eq(get_lwrp_provider(:l_w_r_p_buck_passer))
+        end
+      end
+
+      context "with a cookbook with a hypen in the name" do
+
+        let(:lwrp_cookbok_name) { "l-w-r-p" }
+
+        it "sets itself as a provider for a resource of the same name" do
+          incorrect_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :'l-w-r-p_buck_passer')
+          expect(incorrect_providers).to eq([])
+
+          found_providers = Chef::Platform::ProviderHandlerMap.instance.list(node, :l_w_r_p_buck_passer)
+          expect(found_providers.first).to eq(get_lwrp_provider(:l_w_r_p_buck_passer))
+        end
+      end
     end
 
     it "should insert resources embedded in the provider into the middle of the resource collection" do
-      injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+      injector = get_lwrp(:lwrp_foo).new("morpheus", run_context)
       injector.action(:pass_buck)
-      injector.provider(:lwrp_buck_passer)
-      dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context)
+      injector.provider(get_lwrp_provider(:lwrp_buck_passer))
+      dummy = Chef::Resource::ZenMaster.new("keanu reeves", run_context)
       dummy.provider(Chef::Provider::Easy)
-      @run_context.resource_collection.insert(injector)
-      @run_context.resource_collection.insert(dummy)
+      run_context.resource_collection.insert(injector)
+      run_context.resource_collection.insert(dummy)
 
-      Chef::Runner.new(@run_context).converge
+      Chef::Runner.new(run_context).converge
 
-      expect(@run_context.resource_collection[0]).to eql(injector)
-      expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs')
-      expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs')
-      expect(@run_context.resource_collection[3]).to eql(dummy)
+      expect(run_context.resource_collection[0]).to eql(injector)
+      expect(run_context.resource_collection[1].name).to eql("prepared_thumbs")
+      expect(run_context.resource_collection[2].name).to eql("twiddled_thumbs")
+      expect(run_context.resource_collection[3]).to eql(dummy)
     end
 
     it "should insert embedded resources from multiple providers, including from the last position, properly into the resource collection" do
-      injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+      injector = get_lwrp(:lwrp_foo).new("morpheus", run_context)
       injector.action(:pass_buck)
-      injector.provider(:lwrp_buck_passer)
+      injector.provider(get_lwrp_provider(:lwrp_buck_passer))
 
-      injector2 = Chef::Resource::LwrpBar.new("tank", @run_context)
+      injector2 = get_lwrp(:lwrp_bar).new("tank", run_context)
       injector2.action(:pass_buck)
-      injector2.provider(:lwrp_buck_passer_2)
+      injector2.provider(get_lwrp_provider(:lwrp_buck_passer_2))
 
-      dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context)
+      dummy = Chef::Resource::ZenMaster.new("keanu reeves", run_context)
       dummy.provider(Chef::Provider::Easy)
 
-      @run_context.resource_collection.insert(injector)
-      @run_context.resource_collection.insert(dummy)
-      @run_context.resource_collection.insert(injector2)
+      run_context.resource_collection.insert(injector)
+      run_context.resource_collection.insert(dummy)
+      run_context.resource_collection.insert(injector2)
 
-      Chef::Runner.new(@run_context).converge
+      Chef::Runner.new(run_context).converge
 
-      expect(@run_context.resource_collection[0]).to eql(injector)
-      expect(@run_context.resource_collection[1].name).to eql('prepared_thumbs')
-      expect(@run_context.resource_collection[2].name).to eql('twiddled_thumbs')
-      expect(@run_context.resource_collection[3]).to eql(dummy)
-      expect(@run_context.resource_collection[4]).to eql(injector2)
-      expect(@run_context.resource_collection[5].name).to eql('prepared_eyes')
-      expect(@run_context.resource_collection[6].name).to eql('dried_paint_watched')
+      expect(run_context.resource_collection[0]).to eql(injector)
+      expect(run_context.resource_collection[1].name).to eql("prepared_thumbs")
+      expect(run_context.resource_collection[2].name).to eql("twiddled_thumbs")
+      expect(run_context.resource_collection[3]).to eql(dummy)
+      expect(run_context.resource_collection[4]).to eql(injector2)
+      expect(run_context.resource_collection[5].name).to eql("prepared_eyes")
+      expect(run_context.resource_collection[6].name).to eql("dried_paint_watched")
     end
 
     it "should properly handle a new_resource reference" do
-      resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+      resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
       resource.monkey("bob")
-      resource.provider(:lwrp_monkey_name_printer)
+      resource.provider(get_lwrp_provider(:lwrp_monkey_name_printer))
 
       provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
       provider.action_twiddle_thumbs
@@ -385,15 +527,15 @@ describe "LWRP" do
     end
 
     it "should properly handle an embedded Resource accessing the enclosing Provider's scope" do
-      resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+      resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
       resource.monkey("bob")
-      resource.provider(:lwrp_embedded_resource_accesses_providers_scope)
+      resource.provider(get_lwrp_provider(:lwrp_embedded_resource_accesses_providers_scope))
 
       provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs)
       #provider = @runner.build_provider(resource)
       provider.action_twiddle_thumbs
 
-      expect(provider.enclosed_resource.monkey).to eq('bob, the monkey')
+      expect(provider.enclosed_resource.monkey).to eq("bob, the monkey")
     end
 
     describe "when using inline compilation" do
@@ -404,15 +546,15 @@ describe "LWRP" do
         # Side effect of lwrp_inline_compiler provider for testing notifications.
         $interior_ruby_block_2 = nil
         # resource type doesn't matter, so make an existing resource type work with provider.
-        @resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context)
+        @resource = get_lwrp(:lwrp_foo).new("morpheus", run_context)
         @resource.allowed_actions << :test
         @resource.action(:test)
-        @resource.provider(:lwrp_inline_compiler)
+        @resource.provider(get_lwrp_provider(:lwrp_inline_compiler))
       end
 
       it "does not add interior resources to the exterior resource collection" do
         @resource.run_action(:test)
-        expect(@run_context.resource_collection).to be_empty
+        expect(run_context.resource_collection).to be_empty
       end
 
       context "when interior resources are updated" do
@@ -437,7 +579,142 @@ describe "LWRP" do
       end
 
     end
-
   end
 
+  context "resource class created" do
+    before(:context) do
+      @tmpdir = Dir.mktmpdir("lwrp_test")
+      resource_path = File.join(@tmpdir, "once.rb")
+      IO.write(resource_path, "default_action :create")
+
+      @old_treat_deprecation_warnings_as_errors = Chef::Config[:treat_deprecation_warnings_as_errors]
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      Chef::Resource::LWRPBase.build_from_file("lwrp", resource_path, nil)
+    end
+
+    after(:context) do
+      FileUtils.remove_entry @tmpdir
+      Chef::Config[:treat_deprecation_warnings_as_errors] = @old_treat_deprecation_warnings_as_errors
+    end
+
+    it "should load the resource into a properly-named class" do
+      expect(Chef::Resource::LwrpOnce).to be_kind_of(Class)
+      expect(Chef::Resource::LwrpOnce <= Chef::Resource::LWRPBase).to be_truthy
+    end
+
+    it "get_lwrp(:lwrp_once).new is a Chef::Resource::LwrpOnce" do
+      lwrp = get_lwrp(:lwrp_once).new("hi")
+      expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
+      expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
+      expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
+      expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
+    end
+
+    it "Chef::Resource::LwrpOnce.new is a get_lwrp(:lwrp_once)" do
+      lwrp = Chef::Resource::LwrpOnce.new("hi")
+      expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
+      expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
+      expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
+      expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
+    end
+
+    it "works even if LwrpOnce exists in the top level" do
+      module ::LwrpOnce
+      end
+      expect(Chef::Resource::LwrpOnce).not_to eq(::LwrpOnce)
+    end
+
+    it "allows monkey patching of the lwrp through Chef::Resource" do
+      monkey = Module.new do
+        def issue_3607
+        end
+      end
+      Chef::Resource::LwrpOnce.send(:include, monkey)
+      expect { get_lwrp(:lwrp_once).new("blah").issue_3607 }.not_to raise_error
+    end
+
+    context "with a subclass of get_lwrp(:lwrp_once)" do
+      let(:subclass) do
+        Class.new(get_lwrp(:lwrp_once))
+      end
+
+      it "subclass.new is a subclass" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_truthy
+        expect(lwrp.is_a?(subclass)).to be_truthy
+        expect(subclass === lwrp).to be_truthy
+        expect(lwrp.class === subclass)
+      end
+      it "subclass.new is a Chef::Resource::LwrpOnce" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
+        expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
+        expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
+        expect(lwrp.class === Chef::Resource::LwrpOnce)
+      end
+      it "subclass.new is a get_lwrp(:lwrp_once)" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
+        expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
+        expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
+        expect(lwrp.class === get_lwrp(:lwrp_once))
+      end
+      it "Chef::Resource::LwrpOnce.new is *not* a subclass" do
+        lwrp = Chef::Resource::LwrpOnce.new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_falsey
+        expect(lwrp.is_a?(subclass)).to be_falsey
+        expect(subclass === lwrp.class).to be_falsey
+        expect(subclass === Chef::Resource::LwrpOnce).to be_falsey
+      end
+      it "get_lwrp(:lwrp_once).new is *not* a subclass" do
+        lwrp = get_lwrp(:lwrp_once).new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_falsey
+        expect(lwrp.is_a?(subclass)).to be_falsey
+        expect(subclass === lwrp.class).to be_falsey
+        expect(subclass === get_lwrp(:lwrp_once)).to be_falsey
+      end
+    end
+
+    context "with a subclass of Chef::Resource::LwrpOnce" do
+      let(:subclass) do
+        Class.new(Chef::Resource::LwrpOnce)
+      end
+
+      it "subclass.new is a subclass" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_truthy
+        expect(lwrp.is_a?(subclass)).to be_truthy
+        expect(subclass === lwrp).to be_truthy
+        expect(lwrp.class === subclass)
+      end
+      it "subclass.new is a Chef::Resource::LwrpOnce" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(Chef::Resource::LwrpOnce)).to be_truthy
+        expect(lwrp.is_a?(Chef::Resource::LwrpOnce)).to be_truthy
+        expect(Chef::Resource::LwrpOnce === lwrp).to be_truthy
+        expect(lwrp.class === Chef::Resource::LwrpOnce)
+      end
+      it "subclass.new is a get_lwrp(:lwrp_once)" do
+        lwrp = subclass.new("hi")
+        expect(lwrp.kind_of?(get_lwrp(:lwrp_once))).to be_truthy
+        expect(lwrp.is_a?(get_lwrp(:lwrp_once))).to be_truthy
+        expect(get_lwrp(:lwrp_once) === lwrp).to be_truthy
+        expect(lwrp.class === get_lwrp(:lwrp_once))
+      end
+      it "Chef::Resource::LwrpOnce.new is *not* a subclass" do
+        lwrp = Chef::Resource::LwrpOnce.new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_falsey
+        expect(lwrp.is_a?(subclass)).to be_falsey
+        expect(subclass === lwrp.class).to be_falsey
+        expect(subclass === Chef::Resource::LwrpOnce).to be_falsey
+      end
+      it "get_lwrp(:lwrp_once).new is *not* a subclass" do
+        lwrp = get_lwrp(:lwrp_once).new("hi")
+        expect(lwrp.kind_of?(subclass)).to be_falsey
+        expect(lwrp.is_a?(subclass)).to be_falsey
+        expect(subclass === lwrp.class).to be_falsey
+        expect(subclass === get_lwrp(:lwrp_once)).to be_falsey
+      end
+    end
+  end
 end
diff --git a/spec/unit/mash_spec.rb b/spec/unit/mash_spec.rb
index b8f4c2d..e58f6b8 100644
--- a/spec/unit/mash_spec.rb
+++ b/spec/unit/mash_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Matthew Kent (<mkent at magoazul.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mash'
+require "spec_helper"
+require "chef/mash"
 
 describe Mash do
   it "should duplicate a simple key/value mash to a new mash" do
-    data = {:x=>"one", :y=>"two", :z=>"three"}
+    data = { :x => "one", :y => "two", :z => "three" }
     @orig = Mash.new(data)
     @copy = @orig.dup
     expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
@@ -30,21 +30,21 @@ describe Mash do
   end
 
   it "should duplicate a mash with an array to a new mash" do
-    data = {:x=>"one", :y=>"two", :z=>[1,2,3]}
+    data = { :x => "one", :y => "two", :z => [1, 2, 3] }
     @orig = Mash.new(data)
     @copy = @orig.dup
     expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
     @copy[:z] << 4
-    expect(@orig[:z]).to eq([1,2,3])
+    expect(@orig[:z]).to eq([1, 2, 3])
   end
 
   it "should duplicate a nested mash to a new mash" do
-    data = {:x=>"one", :y=>"two", :z=>Mash.new({:a=>[1,2,3]})}
+    data = { :x => "one", :y => "two", :z => Mash.new({ :a => [1, 2, 3] }) }
     @orig = Mash.new(data)
     @copy = @orig.dup
     expect(@copy.to_hash).to eq(Mash.new(data).to_hash)
     @copy[:z][:a] << 4
-    expect(@orig[:z][:a]).to eq([1,2,3])
+    expect(@orig[:z][:a]).to eq([1, 2, 3])
   end
 
   # add more!
diff --git a/spec/unit/mixin/api_version_request_handling_spec.rb b/spec/unit/mixin/api_version_request_handling_spec.rb
new file mode 100644
index 0000000..13b7295
--- /dev/null
+++ b/spec/unit/mixin/api_version_request_handling_spec.rb
@@ -0,0 +1,126 @@
+#
+# Author:: Tyler Cloke (tyler at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Mixin::ApiVersionRequestHandling do
+  let(:dummy_class) { Class.new { include Chef::Mixin::ApiVersionRequestHandling } }
+  let(:object) { dummy_class.new }
+
+  describe ".server_client_api_version_intersection" do
+    let(:default_supported_client_versions) { [0, 1, 2] }
+
+    context "when the response code is not 406" do
+      let(:response) { OpenStruct.new(:code => "405") }
+      let(:exception) { Net::HTTPServerException.new("405 Something Else", response) }
+
+      it "returns nil" do
+        expect(object.server_client_api_version_intersection(exception, default_supported_client_versions)).
+          to be_nil
+      end
+
+    end # when the response code is not 406
+
+    context "when the response code is 406" do
+      let(:response) { OpenStruct.new(:code => "406") }
+      let(:exception) { Net::HTTPServerException.new("406 Not Acceptable", response) }
+
+      context "when x-ops-server-api-version header does not exist" do
+        it "returns nil" do
+          expect(object.server_client_api_version_intersection(exception, default_supported_client_versions)).
+            to be_nil
+        end
+      end # when x-ops-server-api-version header does not exist
+
+      context "when x-ops-server-api-version header exists" do
+        let(:min_server_version) { 2 }
+        let(:max_server_version) { 4 }
+        let(:return_hash) {
+          {
+            "min_version" => min_server_version,
+            "max_version" => max_server_version,
+          }
+        }
+
+        before(:each) do
+          allow(response).to receive(:[]).with("x-ops-server-api-version").and_return(Chef::JSONCompat.to_json(return_hash))
+        end
+
+        context "when there is no intersection between client and server versions" do
+          shared_examples_for "no intersection between client and server versions" do
+            it "return an array" do
+              expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+                to be_a_kind_of(Array)
+            end
+
+            it "returns an empty array" do
+              expect(object.server_client_api_version_intersection(exception, supported_client_versions).length).
+                to eq(0)
+            end
+
+          end
+
+          context "when all the versions are higher than the max" do
+            it_should_behave_like "no intersection between client and server versions" do
+              let(:supported_client_versions) { [5, 6, 7] }
+            end
+          end
+
+          context "when all the versions are lower than the min" do
+            it_should_behave_like "no intersection between client and server versions" do
+              let(:supported_client_versions) { [0, 1] }
+            end
+          end
+
+        end # when there is no intersection between client and server versions
+
+        context "when there is an intersection between client and server versions" do
+          context "when multiple versions intersect" do
+            let(:supported_client_versions) { [1, 2, 3, 4, 5] }
+
+            it "includes all of the intersection" do
+              expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+                to eq([2, 3, 4])
+            end
+          end # when multiple versions intersect
+
+          context "when only the min client version intersects" do
+            let(:supported_client_versions) { [0, 1, 2] }
+
+            it "includes the intersection" do
+              expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+                to eq([2])
+            end
+          end # when only the min client version intersects
+
+          context "when only the max client version intersects" do
+            let(:supported_client_versions) { [4, 5, 6] }
+
+            it "includes the intersection" do
+              expect(object.server_client_api_version_intersection(exception, supported_client_versions)).
+                to eq([4])
+            end
+          end # when only the max client version intersects
+
+        end # when there is an intersection between client and server versions
+
+      end # when x-ops-server-api-version header exists
+    end # when the response code is 406
+
+  end # .server_client_api_version_intersection
+end # Chef::Mixin::ApiVersionRequestHandling
diff --git a/spec/unit/mixin/checksum_spec.rb b/spec/unit/mixin/checksum_spec.rb
index 864b15f..997dcd5 100644
--- a/spec/unit/mixin/checksum_spec.rb
+++ b/spec/unit/mixin/checksum_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/checksum'
-require 'stringio'
+require "spec_helper"
+require "chef/mixin/checksum"
+require "stringio"
 
 class Chef::CMCCheck
   include Chef::Mixin::Checksum
@@ -38,4 +38,3 @@ describe Chef::Mixin::Checksum do
   end
 
 end
-
diff --git a/spec/unit/mixin/command_spec.rb b/spec/unit/mixin/command_spec.rb
index e198e3a..0c2f6da 100644
--- a/spec/unit/mixin/command_spec.rb
+++ b/spec/unit/mixin/command_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Hongli Lai (hongli at phusion.nl)
-# Copyright:: Copyright (c) 2009 Phusion
+# Copyright:: Copyright 2009-2016, Phusion
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Mixin::Command, :volatile do
 
   if windows?
 
-    pending("TODO MOVE: this is a platform specific integration test.")
+    skip("TODO MOVE: this is a platform specific integration test.")
 
   else
 
@@ -43,17 +43,17 @@ describe Chef::Mixin::Command, :volatile do
       end
 
       it "should respect locale when specified explicitly" do
-        popen4("echo $LC_ALL", :environment => {"LC_ALL" => "es"}) do |pid, stdin, stdout, stderr|
+        popen4("echo $LC_ALL", :environment => { "LC_ALL" => "es" }) do |pid, stdin, stdout, stderr|
           expect(stdout.read.strip).to eq("es")
         end
       end
 
       it "should end when the child process reads from STDIN and a block is given" do
         expect {Timeout.timeout(10) do
-            popen4("ruby -e 'while gets; end'", :waitlast => true) do |pid, stdin, stdout, stderr|
-              (1..5).each { |i| stdin.puts "#{i}" }
-            end
+          popen4("ruby -e 'while gets; end'", :waitlast => true) do |pid, stdin, stdout, stderr|
+            (1..5).each { |i| stdin.puts "#{i}" }
           end
+        end
         }.not_to raise_error
       end
 
@@ -61,9 +61,8 @@ describe Chef::Mixin::Command, :volatile do
 
         it "returns immediately after the first child process exits" do
           expect {Timeout.timeout(10) do
-            pid, stdin,stdout,stderr = nil,nil,nil,nil
-            evil_forker="exit if fork; 10.times { sleep 1}"
-            popen4("ruby -e '#{evil_forker}'") do |pid,stdin,stdout,stderr|
+            evil_forker = "exit if fork; 10.times { sleep 1}"
+            popen4("ruby -e '#{evil_forker}'") do |pid, stdin, stdout, stderr|
             end
           end}.not_to raise_error
         end
@@ -94,7 +93,7 @@ describe Chef::Mixin::Command, :volatile do
           # Serdar - During Solaris tests, we've seen that processes
           # are taking a long time to exit. Bumping timeout now to 10.
           expect {Timeout.timeout(10) do
-            evil_forker="exit if fork; 10.times { sleep 1}"
+            evil_forker = "exit if fork; 10.times { sleep 1}"
             run_command(:command => "ruby -e '#{evil_forker}'")
           end}.not_to raise_error
         end
diff --git a/spec/unit/mixin/convert_to_class_name_spec.rb b/spec/unit/mixin/convert_to_class_name_spec.rb
index 4cf6728..27c9ac6 100644
--- a/spec/unit/mixin/convert_to_class_name_spec.rb
+++ b/spec/unit/mixin/convert_to_class_name_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class ConvertToClassTestHarness
   include Chef::Mixin::ConvertToClassName
diff --git a/spec/unit/mixin/deep_merge_spec.rb b/spec/unit/mixin/deep_merge_spec.rb
index d107323..2850193 100644
--- a/spec/unit/mixin/deep_merge_spec.rb
+++ b/spec/unit/mixin/deep_merge_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Matthew Kent (<mkent at magoazul.com>)
 # Author:: Steve Midgley (http://www.misuse.org/science)
-# Copyright:: Copyright (c) 2010 Matthew Kent
-# Copyright:: Copyright (c) 2008 Steve Midgley
+# Copyright:: Copyright 2010-2016, Matthew Kent
+# Copyright:: Copyright 2008-2016, Steve Midgley
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,26 +22,26 @@
 # available under the MIT license from
 # http://trac.misuse.org/science/wiki/DeepMerge
 
-require 'spec_helper'
+require "spec_helper"
 
 # Test coverage from the original author converted to rspec
 describe Chef::Mixin::DeepMerge, "deep_merge!" do
   before do
     @dm = Chef::Mixin::DeepMerge
-    @field_ko_prefix = '!merge'
+    @field_ko_prefix = "!merge"
   end
 
   # deep_merge core tests - moving from basic to more complex
 
   it "tests merging an hash w/array into blank hash" do
-    hash_src = {'id' => '2'}
+    hash_src = { "id" => "2" }
     hash_dst = {}
     @dm.deep_merge!(hash_src.dup, hash_dst)
     expect(hash_dst).to eq(hash_src)
   end
 
   it "tests merging an hash w/array into blank hash" do
-    hash_src = {'region' => {'id' => ['227', '2']}}
+    hash_src = { "region" => { "id" => ["227", "2"] } }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
     expect(hash_dst).to eq(hash_src)
@@ -49,192 +49,192 @@ describe Chef::Mixin::DeepMerge, "deep_merge!" do
 
   it "tests merge from empty hash" do
     hash_src = {}
-    hash_dst = {"property" => ["2","4"]}
+    hash_dst = { "property" => ["2", "4"] }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => ["2","4"]})
+    expect(hash_dst).to eq({ "property" => ["2", "4"] })
   end
 
   it "tests merge to empty hash" do
-    hash_src = {"property" => ["2","4"]}
+    hash_src = { "property" => ["2", "4"] }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => ["2","4"]})
+    expect(hash_dst).to eq({ "property" => ["2", "4"] })
   end
 
   it "tests simple string overwrite" do
-    hash_src = {"name" => "value"}
-    hash_dst = {"name" => "value1"}
+    hash_src = { "name" => "value" }
+    hash_dst = { "name" => "value1" }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"name" => "value"})
+    expect(hash_dst).to eq({ "name" => "value" })
   end
 
   it "tests simple string overwrite of empty hash" do
-    hash_src = {"name" => "value"}
+    hash_src = { "name" => "value" }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
     expect(hash_dst).to eq(hash_src)
   end
 
   it "tests hashes holding array" do
-    hash_src = {"property" => ["1","3"]}
-    hash_dst = {"property" => ["2","4"]}
+    hash_src = { "property" => ["1", "3"] }
+    hash_dst = { "property" => ["2", "4"] }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => ["2","4","1","3"]})
+    expect(hash_dst).to eq({ "property" => ["2", "4", "1", "3"] })
   end
 
   it "tests hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src" do
-    hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => ["3", "2"], "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => ["3", "2", "1"], "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests hash holding hash holding array v string (string is overwritten by array)" do
-    hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => "3", "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => ["1", "2"], "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests hash holding hash holding string v array (array is overwritten by string)" do
-    hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => "3", "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => ["1", "2"], "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => "3", "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests hash holding hash holding hash v array (array is overwritten by hash)" do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => ["1", "2"], "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests 3 hash layers holding integers (integers are overwritten by source)" do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => 2, "queen_bed" => 4 }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => 1 }, "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests 3 hash layers holding arrays of int (arrays are merged)" do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3], "queen_bed" => [1] }, "bathroom_count" => ["1", "4+"] } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4, 1] }, "bathroom_count" => ["2", "1", "4+"] } })
   end
 
   it "tests 1 hash overwriting 3 hash layers holding arrays of int" do
-    hash_src = {"property" => "1"}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => "1" }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => "1"})
+    expect(hash_dst).to eq({ "property" => "1" })
   end
 
   it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten" do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3], "queen_bed" => [1] }, "bathroom_count" => "1" } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4, 1] }, "bathroom_count" => "1" } })
   end
 
   it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge" do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => [1] }, "bathroom_count" => ["1"] } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => 3, "queen_bed" => [4, 1] }, "bathroom_count" => ["2", "1"] } })
   end
 
   it "tests 3 hash layers holding arrays of int, but source is incomplete." do
-    hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { "king_bed" => [3] }, "bathroom_count" => ["1"] } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2, 3], "queen_bed" => [4] }, "bathroom_count" => ["2", "1"] } })
   end
 
   it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do
-    hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_src = { "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } }
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [2, 3], "queen_bed" => [4] }, "bathroom_count" => ["2", "1"] } })
   end
 
   it "tests 3 hash layers holding arrays of int, but source is empty" do
     hash_src = {}
-    hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}}
+    hash_dst = { "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { "king_bed" => [2], "queen_bed" => [4] }, "bathroom_count" => ["2"] } })
   end
 
   it "tests 3 hash layers holding arrays of int, but dest is empty" do
-    hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}}
+    hash_src = { "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => { 2 => 3, "king_bed" => [3] }, "bathroom_count" => ["1"] } })
   end
 
   it "tests hash holding arrays of arrays" do
-    hash_src = {["1", "2", "3"] => ["1", "2"]}
-    hash_dst = {["4", "5"] => ["3"]}
+    hash_src = { ["1", "2", "3"] => ["1", "2"] }
+    hash_dst = { ["4", "5"] => ["3"] }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({["1","2","3"] => ["1", "2"], ["4", "5"] => ["3"]})
+    expect(hash_dst).to eq({ ["1", "2", "3"] => ["1", "2"], ["4", "5"] => ["3"] })
   end
 
   it "tests merging of hash with blank hash, and make sure that source array split does not function when turned off" do
-    hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}}
+    hash_src = { "property" => { "bedroom_count" => ["1", "2,3"] } }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({'property' => {'bedroom_count' => ["1","2,3"]}})
+    expect(hash_dst).to eq({ "property" => { "bedroom_count" => ["1", "2,3"] } })
   end
 
   it "tests merging into a blank hash" do
-    hash_src = {"action"=>"browse", "controller"=>"results"}
+    hash_src = { "action" => "browse", "controller" => "results" }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
     expect(hash_dst).to eq(hash_src)
   end
 
   it "tests are unmerged hashes passed unmodified w/out :unpack_arrays?" do
-    hash_src = {"amenity"=>{"id"=>["26,27"]}}
+    hash_src = { "amenity" => { "id" => ["26,27"] } }
     hash_dst = {}
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"amenity"=>{"id"=>["26,27"]}})
+    expect(hash_dst).to eq({ "amenity" => { "id" => ["26,27"] } })
   end
 
   it "tests hash of array of hashes" do
-    hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]}
-    hash_dst = {"item" => [{"3" => "5"}]}
+    hash_src = { "item" => [{ "1" => "3" }, { "2" => "4" }] }
+    hash_dst = { "item" => [{ "3" => "5" }] }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]})
+    expect(hash_dst).to eq({ "item" => [{ "3" => "5" }, { "1" => "3" }, { "2" => "4" }] })
   end
 
   # Additions since import
   it "should overwrite true with false when merging boolean values" do
-    hash_src = {"valid" => false}
-    hash_dst = {"valid" => true}
+    hash_src = { "valid" => false }
+    hash_dst = { "valid" => true }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"valid" => false})
+    expect(hash_dst).to eq({ "valid" => false })
   end
 
   it "should overwrite false with true when merging boolean values" do
-    hash_src = {"valid" => true}
-    hash_dst = {"valid" => false}
+    hash_src = { "valid" => true }
+    hash_dst = { "valid" => false }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"valid" => true})
+    expect(hash_dst).to eq({ "valid" => true })
   end
 
   it "should overwrite a string with an empty string when merging string values" do
-    hash_src = {"item" => " "}
-    hash_dst = {"item" => "orange"}
+    hash_src = { "item" => " " }
+    hash_dst = { "item" => "orange" }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"item" => " "})
+    expect(hash_dst).to eq({ "item" => " " })
   end
 
   it "should overwrite an empty string with a string when merging string values" do
-    hash_src = {"item" => "orange"}
-    hash_dst = {"item" => " "}
+    hash_src = { "item" => "orange" }
+    hash_dst = { "item" => " " }
     @dm.deep_merge!(hash_src, hash_dst)
-    expect(hash_dst).to eq({"item" => "orange"})
+    expect(hash_dst).to eq({ "item" => "orange" })
   end
 end # deep_merge!
 
@@ -247,41 +247,41 @@ describe Chef::Mixin::DeepMerge do
   describe "merge" do
     it "should merge a hash into an empty hash" do
       hash_dst = {}
-      hash_src = {'id' => '2'}
+      hash_src = { "id" => "2" }
       expect(@dm.merge(hash_dst, hash_src)).to eq(hash_src)
     end
 
     it "should merge a nested hash into an empty hash" do
       hash_dst = {}
-      hash_src = {'region' => {'id' => ['227', '2']}}
+      hash_src = { "region" => { "id" => ["227", "2"] } }
       expect(@dm.merge(hash_dst, hash_src)).to eq(hash_src)
     end
 
     it "should overwrite as string value when merging hashes" do
-      hash_dst = {"name" => "value1"}
-      hash_src = {"name" => "value"}
-      expect(@dm.merge(hash_dst, hash_src)).to eq({"name" => "value"})
+      hash_dst = { "name" => "value1" }
+      hash_src = { "name" => "value" }
+      expect(@dm.merge(hash_dst, hash_src)).to eq({ "name" => "value" })
     end
 
     it "should merge arrays within hashes" do
-      hash_dst = {"property" => ["2","4"]}
-      hash_src = {"property" => ["1","3"]}
-      expect(@dm.merge(hash_dst, hash_src)).to eq({"property" => ["2","4","1","3"]})
+      hash_dst = { "property" => ["2", "4"] }
+      hash_src = { "property" => ["1", "3"] }
+      expect(@dm.merge(hash_dst, hash_src)).to eq({ "property" => ["2", "4", "1", "3"] })
     end
 
     it "should merge deeply nested hashes" do
-      hash_dst = {"property" => {"values" => {"are" => "falling", "can" => "change"}}}
-      hash_src = {"property" => {"values" => {"are" => "stable", "may" => "rise"}}}
-      expect(@dm.merge(hash_dst, hash_src)).to eq({"property" => {"values" => {"are" => "stable", "can" => "change", "may" => "rise"}}})
+      hash_dst = { "property" => { "values" => { "are" => "falling", "can" => "change" } } }
+      hash_src = { "property" => { "values" => { "are" => "stable", "may" => "rise" } } }
+      expect(@dm.merge(hash_dst, hash_src)).to eq({ "property" => { "values" => { "are" => "stable", "can" => "change", "may" => "rise" } } })
     end
 
     it "should not modify the source or destination during the merge" do
-      hash_dst = {"property" => ["1","2","3"]}
-      hash_src = {"property" => ["4","5","6"]}
+      hash_dst = { "property" => ["1", "2", "3"] }
+      hash_src = { "property" => ["4", "5", "6"] }
       ret = @dm.merge(hash_dst, hash_src)
-      expect(hash_dst).to eq({"property" => ["1","2","3"]})
-      expect(hash_src).to eq({"property" => ["4","5","6"]})
-      expect(ret).to eq({"property" => ["1","2","3","4","5","6"]})
+      expect(hash_dst).to eq({ "property" => ["1", "2", "3"] })
+      expect(hash_src).to eq({ "property" => ["4", "5", "6"] })
+      expect(ret).to eq({ "property" => ["1", "2", "3", "4", "5", "6"] })
     end
 
     it "should not error merging un-dupable objects" do
@@ -292,8 +292,8 @@ describe Chef::Mixin::DeepMerge do
 
   describe "hash-only merging" do
     it "merges Hashes like normal deep merge" do
-      merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => "1-deep-b-merge-ee"}, "top_level_b" => "top-level-b-merge-ee"}
-      merge_with_hash = {"top_level_a" => {"1_deep_b" => "1-deep-b-merged-onto", "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+      merge_ee_hash = { "top_level_a" => { "1_deep_a" => "1-a-merge-ee", "1_deep_b" => "1-deep-b-merge-ee" }, "top_level_b" => "top-level-b-merge-ee" }
+      merge_with_hash = { "top_level_a" => { "1_deep_b" => "1-deep-b-merged-onto", "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
 
       merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
 
@@ -304,38 +304,38 @@ describe Chef::Mixin::DeepMerge do
     end
 
     it "replaces arrays rather than merging them" do
-      merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => %w[A A A]}, "top_level_b" => "top-level-b-merge-ee"}
-      merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+      merge_ee_hash = { "top_level_a" => { "1_deep_a" => "1-a-merge-ee", "1_deep_b" => %w{A A A} }, "top_level_b" => "top-level-b-merge-ee" }
+      merge_with_hash = { "top_level_a" => { "1_deep_b" => %w{B B B}, "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
 
       merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
 
       expect(merged_result["top_level_b"]).to eq("top-level-b-merged-onto")
       expect(merged_result["top_level_a"]["1_deep_a"]).to eq("1-a-merge-ee")
-      expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w[B B B])
+      expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w{B B B})
     end
 
     it "replaces non-hash items with hashes when there's a conflict" do
-      merge_ee_hash = {"top_level_a" => "top-level-a-mergee", "top_level_b" => "top-level-b-merge-ee"}
-      merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" }
+      merge_ee_hash = { "top_level_a" => "top-level-a-mergee", "top_level_b" => "top-level-b-merge-ee" }
+      merge_with_hash = { "top_level_a" => { "1_deep_b" => %w{B B B}, "1_deep_c" => "1-deep-c-merged-onto" }, "top_level_b" => "top-level-b-merged-onto" }
 
       merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
 
       expect(merged_result["top_level_a"]).to be_a(Hash)
       expect(merged_result["top_level_a"]["1_deep_a"]).to be_nil
-      expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w[B B B])
+      expect(merged_result["top_level_a"]["1_deep_b"]).to eq(%w{B B B})
     end
 
     it "does not mutate deeply-nested original hashes by default" do
-      merge_ee_hash =   {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}}
-      merge_with_hash = {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}}
+      merge_ee_hash =   { "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" } } } }
+      merge_with_hash = { "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" } } } }
       @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
-      expect(merge_ee_hash).to eq({"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}})
-      expect(merge_with_hash).to eq({"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}})
+      expect(merge_ee_hash).to eq({ "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" } } } })
+      expect(merge_with_hash).to eq({ "top_level_a" => { "1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" } } } })
     end
 
     it "does not error merging un-dupable items" do
-      merge_ee_hash = {"top_level_a" => 1, "top_level_b" => false}
-      merge_with_hash = {"top_level_a" => 2, "top_level_b" => true }
+      merge_ee_hash = { "top_level_a" => 1, "top_level_b" => false }
+      merge_with_hash = { "top_level_a" => 2, "top_level_b" => true }
       @dm.hash_only_merge(merge_ee_hash, merge_with_hash)
     end
   end
diff --git a/spec/unit/mixin/deprecation_spec.rb b/spec/unit/mixin/deprecation_spec.rb
index 6d9f39a..8f22b09 100644
--- a/spec/unit/mixin/deprecation_spec.rb
+++ b/spec/unit/mixin/deprecation_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/deprecation'
+require "spec_helper"
+require "chef/mixin/deprecation"
 
 describe Chef::Mixin do
   describe "deprecating constants (Class/Module)" do
@@ -46,7 +46,7 @@ describe Chef::Mixin::Deprecation::DeprecatedInstanceVariable do
   before do
     Chef::Log.logger = Logger.new(StringIO.new)
 
-    @deprecated_ivar = Chef::Mixin::Deprecation::DeprecatedInstanceVariable.new('value', 'an_ivar')
+    @deprecated_ivar = Chef::Mixin::Deprecation::DeprecatedInstanceVariable.new("value", "an_ivar")
   end
 
   it "forward method calls to the target object" do
diff --git a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
index aeef175..248de0b 100644
--- a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
+++ b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Mark Mzyk (<mmzyk at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Mark Mzyk (<mmzyk at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'etc'
-require 'ostruct'
+require "spec_helper"
+require "etc"
+require "ostruct"
 
 describe Chef::Mixin::EnforceOwnershipAndPermissions do
 
@@ -49,12 +49,12 @@ describe Chef::Mixin::EnforceOwnershipAndPermissions do
       allow_any_instance_of(Chef::FileAccessControl).to receive(:uid_from_resource).and_return(0)
       allow_any_instance_of(Chef::FileAccessControl).to receive(:requires_changes?).and_return(false)
       allow_any_instance_of(Chef::FileAccessControl).to receive(:define_resource_requirements)
+      allow_any_instance_of(Chef::FileAccessControl).to receive(:describe_changes)
+
+      passwd_struct = OpenStruct.new(:name => "root", :passwd => "x",
+                                     :uid => 0, :gid => 0, :dir => "/root",
+                                     :shell => "/bin/bash")
 
-      passwd_struct = if windows?
-                        Struct::Passwd.new("root", "x", 0, 0, "/root", "/bin/bash")
-                      else
-                        Struct::Passwd.new("root", "x", 0, 0, "root", "/root", "/bin/bash")
-                      end
       group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0)
       allow(Etc).to receive(:getpwuid).and_return(passwd_struct)
       allow(Etc).to receive(:getgrgid).and_return(group_struct)
@@ -73,12 +73,12 @@ describe Chef::Mixin::EnforceOwnershipAndPermissions do
     before do
       allow_any_instance_of(Chef::FileAccessControl).to receive(:requires_changes?).and_return(true)
       allow_any_instance_of(Chef::FileAccessControl).to receive(:uid_from_resource).and_return(0)
+      allow_any_instance_of(Chef::FileAccessControl).to receive(:describe_changes)
+
+      passwd_struct = OpenStruct.new(:name => "root", :passwd => "x",
+                                     :uid => 0, :gid => 0, :dir => "/root",
+                                     :shell => "/bin/bash")
 
-      passwd_struct = if windows?
-                        Struct::Passwd.new("root", "x", 0, 0, "/root", "/bin/bash")
-                      else
-                        Struct::Passwd.new("root", "x", 0, 0, "root", "/root", "/bin/bash")
-                      end
       group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0)
       allow(Etc).to receive(:getpwuid).and_return(passwd_struct)
       allow(Etc).to receive(:getgrgid).and_return(group_struct)
diff --git a/spec/unit/mixin/homebrew_user_spec.rb b/spec/unit/mixin/homebrew_user_spec.rb
index 57b8972..de72f6b 100644
--- a/spec/unit/mixin/homebrew_user_spec.rb
+++ b/spec/unit/mixin/homebrew_user_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
+# Author:: Joshua Timberman (<joshua at chef.io>)
 #
-# Copyright 2014, Chef Software, Inc <legal at getchef.com>
+# Copyright 2014-2016, Chef Software, Inc <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/mixin/homebrew_user'
+require "spec_helper"
+require "chef/mixin/homebrew_user"
 
 class ExampleHomebrewUser
   include Chef::Mixin::HomebrewUser
@@ -24,22 +24,22 @@ end
 
 describe Chef::Mixin::HomebrewUser do
   before(:each) do
-    node.default['homebrew']['owner'] = nil
+    node.default["homebrew"]["owner"] = nil
   end
 
   let(:homebrew_user) { ExampleHomebrewUser.new }
   let(:node) { Chef::Node.new }
 
-  describe 'when the homebrew user is provided' do
+  describe "when the homebrew user is provided" do
     let(:uid) { 1001 }
     let(:user) { "foo" }
 
-    it 'returns the homebrew user without looking at the file when uid is provided' do
+    it "returns the homebrew user without looking at the file when uid is provided" do
       expect(File).to receive(:exist?).exactly(0).times
       expect(homebrew_user.find_homebrew_uid(uid)).to eq(uid)
     end
 
-    it 'returns the homebrew user without looking at the file when name is provided' do
+    it "returns the homebrew user without looking at the file when name is provided" do
       expect(File).to receive(:exist?).exactly(0).times
       allow(Etc).to receive_message_chain(:getpwnam, :uid).and_return(uid)
       expect(homebrew_user.find_homebrew_uid(user)).to eq(uid)
@@ -50,7 +50,7 @@ describe Chef::Mixin::HomebrewUser do
   shared_examples "successfully find executable" do
     let(:user) { nil }
     let(:brew_owner) { 2001 }
-    let(:default_brew_path) { '/usr/local/bin/brew' }
+    let(:default_brew_path) { "/usr/local/bin/brew" }
     let(:stat_double) {
       d = double()
       expect(d).to receive(:uid).and_return(brew_owner)
@@ -63,13 +63,13 @@ describe Chef::Mixin::HomebrewUser do
         expect(Etc).to receive(:getpwuid).with(brew_owner).and_return(OpenStruct.new(:name => "name"))
       end
 
-      it 'returns the owner of the brew executable when it is at a default location' do
+      it "returns the owner of the brew executable when it is at a default location" do
         expect(File).to receive(:exist?).with(default_brew_path).and_return(true)
         expect(File).to receive(:stat).with(default_brew_path).and_return(stat_double)
         expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner)
       end
 
-      it 'returns the owner of the brew executable when it is not at a default location' do
+      it "returns the owner of the brew executable when it is not at a default location" do
         expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
         allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("/foo")
         expect(File).to receive(:stat).with("/foo").and_return(stat_double)
@@ -79,9 +79,9 @@ describe Chef::Mixin::HomebrewUser do
     end
   end
 
-  describe 'when the homebrew user is not provided' do
+  describe "when the homebrew user is not provided" do
 
-    it 'raises an error if no executable is found' do
+    it "raises an error if no executable is found" do
       expect(File).to receive(:exist?).with(default_brew_path).and_return(false)
       allow(homebrew_user).to receive_message_chain(:shell_out, :stdout, :strip).and_return("")
       expect { homebrew_user.find_homebrew_uid(user) }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewOwner)
diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb
index 85e1c1a..259b890 100644
--- a/spec/unit/mixin/params_validate_spec.rb
+++ b/spec/unit/mixin/params_validate_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,23 +16,25 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class TinyClass
   include Chef::Mixin::ParamsValidate
 
-  def music(is_good=true)
+  attr_reader :name
+
+  def music(is_good = true)
     is_good
   end
 end
 
 describe Chef::Mixin::ParamsValidate do
   before(:each) do
-     @vo = TinyClass.new()
+    @vo = TinyClass.new()
   end
 
   it "should allow a hash and a hash as arguments to validate" do
-    expect { @vo.validate({:one => "two"}, {}) }.not_to raise_error
+    expect { @vo.validate({ :one => "two" }, {}) }.not_to raise_error
   end
 
   it "should raise an argument error if validate is called incorrectly" do
@@ -40,39 +42,39 @@ describe Chef::Mixin::ParamsValidate do
   end
 
   it "should require validation map keys to be symbols or strings" do
-    expect { @vo.validate({:one => "two"}, { :one => true }) }.not_to raise_error
-    expect { @vo.validate({:one => "two"}, { "one" => true }) }.not_to raise_error
-    expect { @vo.validate({:one => "two"}, { Hash.new => true }) }.to raise_error(ArgumentError)
+    expect { @vo.validate({ :one => "two" }, { :one => true }) }.not_to raise_error
+    expect { @vo.validate({ :one => "two" }, { "one" => true }) }.not_to raise_error
+    expect { @vo.validate({ :one => "two" }, { Hash.new => true }) }.to raise_error(ArgumentError)
   end
 
   it "should allow options to be required with true" do
-    expect { @vo.validate({:one => "two"}, { :one => true }) }.not_to raise_error
+    expect { @vo.validate({ :one => "two" }, { :one => true }) }.not_to raise_error
   end
 
   it "should allow options to be optional with false" do
-    expect { @vo.validate({}, {:one => false})}.not_to raise_error
+    expect { @vo.validate({}, { :one => false }) }.not_to raise_error
   end
 
   it "should allow you to check what kind_of? thing an argument is with kind_of" do
     expect {
       @vo.validate(
-        {:one => "string"},
+        { :one => "string" },
         {
           :one => {
             :kind_of => String
           }
-        }
+        },
       )
     }.not_to raise_error
 
     expect {
       @vo.validate(
-        {:one => "string"},
+        { :one => "string" },
         {
           :one => {
             :kind_of => Array
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -80,34 +82,34 @@ describe Chef::Mixin::ParamsValidate do
   it "should allow you to specify an argument is required with required" do
     expect {
       @vo.validate(
-        {:one => "string"},
+        { :one => "string" },
         {
           :one => {
             :required => true
           }
-        }
+        },
       )
     }.not_to raise_error
 
     expect {
       @vo.validate(
-        {:two => "string"},
+        { :two => "string" },
         {
           :one => {
             :required => true
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
 
     expect {
       @vo.validate(
-        {:two => "string"},
+        { :two => "string" },
         {
           :one => {
             :required => false
           }
-        }
+        },
       )
     }.not_to raise_error
   end
@@ -115,23 +117,23 @@ describe Chef::Mixin::ParamsValidate do
   it "should allow you to specify whether an object has a method with respond_to" do
     expect {
       @vo.validate(
-        {:one => @vo},
+        { :one => @vo },
         {
           :one => {
             :respond_to => "validate"
           }
-        }
+        },
       )
     }.not_to raise_error
 
     expect {
       @vo.validate(
-        {:one => @vo},
+        { :one => @vo },
         {
           :one => {
             :respond_to => "monkey"
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -139,23 +141,23 @@ describe Chef::Mixin::ParamsValidate do
   it "should allow you to specify whether an object has all the given methods with respond_to and an array" do
     expect {
       @vo.validate(
-        {:one => @vo},
+        { :one => @vo },
         {
           :one => {
             :respond_to => ["validate", "music"]
           }
-        }
+        },
       )
     }.not_to raise_error
 
     expect {
       @vo.validate(
-        {:one => @vo},
+        { :one => @vo },
         {
           :one => {
             :respond_to => ["monkey", "validate"]
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -166,7 +168,7 @@ describe Chef::Mixin::ParamsValidate do
       :one => {
         :default => "is the loneliest number"
       }
-    })
+    },)
     expect(arguments[:one]).to eq("is the loneliest number")
   end
 
@@ -178,7 +180,7 @@ describe Chef::Mixin::ParamsValidate do
           :one => {
             :regex => /^is good$/
           }
-        }
+        },
       )
     }.not_to raise_error
 
@@ -189,7 +191,7 @@ describe Chef::Mixin::ParamsValidate do
           :one => {
             :regex => /^is bad$/
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -203,10 +205,10 @@ describe Chef::Mixin::ParamsValidate do
             :callbacks => {
               "should be equal to is good" => lambda { |a|
                 a == "is good"
-              },
+              }
             }
           }
-        }
+        },
       )
     }.not_to raise_error
 
@@ -218,10 +220,10 @@ describe Chef::Mixin::ParamsValidate do
             :callbacks => {
               "should be equal to 'is good'" => lambda { |a|
                 a == "is good"
-              },
+              }
             }
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -241,14 +243,14 @@ describe Chef::Mixin::ParamsValidate do
                 a == "is good"
               }
             },
-            :required => true
+            :required => true,
           },
           :two => {
             :kind_of => String,
-            :required => false
+            :required => false,
           },
-          :three => { :default => "neato mosquito" }
-        }
+          :three => { :default => "neato mosquito" },
+        },
       )
     }.not_to raise_error
     expect(args[:three]).to eq("neato mosquito")
@@ -265,14 +267,14 @@ describe Chef::Mixin::ParamsValidate do
                 a == "is good"
               }
             },
-            :required => true
+            :required => true,
           },
           :two => {
             :kind_of => Hash,
-            :required => false
+            :required => false,
           },
-          :three => { :default => "neato mosquito" }
-        }
+          :three => { :default => "neato mosquito" },
+        },
       )
     }.to raise_error(ArgumentError)
   end
@@ -284,58 +286,58 @@ describe Chef::Mixin::ParamsValidate do
           :one => {
             :busted => "check"
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
 
   it "should accept keys that are strings in the options" do
     expect {
-      @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ }})
+      @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ } })
     }.not_to raise_error
   end
 
   it "should allow an array to kind_of" do
     expect {
       @vo.validate(
-        {:one => "string"},
+        { :one => "string" },
         {
           :one => {
             :kind_of => [ String, Array ]
           }
-        }
+        },
       )
     }.not_to raise_error
     expect {
       @vo.validate(
-        {:one => ["string"]},
+        { :one => ["string"] },
         {
           :one => {
             :kind_of => [ String, Array ]
           }
-        }
+        },
       )
     }.not_to raise_error
     expect {
       @vo.validate(
-        {:one => Hash.new},
+        { :one => Hash.new },
         {
           :one => {
             :kind_of => [ String, Array ]
           }
-        }
+        },
       )
     }.to raise_error(ArgumentError)
   end
 
   it "asserts that a value returns false from a predicate method" do
     expect do
-      @vo.validate({:not_blank => "should pass"},
-                   {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}})
+      @vo.validate({ :not_blank => "should pass" },
+                   { :not_blank => { :cannot_be => [ :nil, :empty ] } })
     end.not_to raise_error
     expect do
-      @vo.validate({:not_blank => ""},
-                   {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}})
+      @vo.validate({ :not_blank => "" },
+                   { :not_blank => { :cannot_be => [ :nil, :empty ] } })
     end.to raise_error(Chef::Exceptions::ValidationFailed)
   end
 
@@ -365,40 +367,40 @@ describe Chef::Mixin::ParamsValidate do
 
   it "should set and return @name, then return @name for foo when argument is nil" do
     value = "meow"
-    expect(@vo.set_or_return(:name, value, { }).object_id).to eq(value.object_id)
+    expect(@vo.set_or_return(:name, value, {}).object_id).to eq(value.object_id)
     expect(@vo.set_or_return(:foo, nil, { :name_attribute => true }).object_id).to eq(value.object_id)
   end
 
   it "should allow DelayedEvaluator instance to be set for value regardless of restriction" do
-    value = Chef::DelayedEvaluator.new{ 'test' }
-    @vo.set_or_return(:test, value, {:kind_of => Numeric})
+    value = Chef::DelayedEvaluator.new { "test" }
+    @vo.set_or_return(:test, value, { :kind_of => Numeric })
   end
 
   it "should raise an error when delayed evaluated attribute is not valid" do
-    value = Chef::DelayedEvaluator.new{ 'test' }
-    @vo.set_or_return(:test, value, {:kind_of => Numeric})
+    value = Chef::DelayedEvaluator.new { "test" }
+    @vo.set_or_return(:test, value, { :kind_of => Numeric })
     expect do
-      @vo.set_or_return(:test, nil, {:kind_of => Numeric})
+      @vo.set_or_return(:test, nil, { :kind_of => Numeric })
     end.to raise_error(Chef::Exceptions::ValidationFailed)
   end
 
   it "should create DelayedEvaluator instance when #lazy is used" do
-    @vo.set_or_return(:delayed, @vo.lazy{ 'test' }, {})
+    @vo.set_or_return(:delayed, @vo.lazy { "test" }, {})
     expect(@vo.instance_variable_get(:@delayed)).to be_a(Chef::DelayedEvaluator)
   end
 
   it "should execute block on each call when DelayedEvaluator" do
-    value = 'fubar'
-    @vo.set_or_return(:test, @vo.lazy{ value }, {})
-    expect(@vo.set_or_return(:test, nil, {})).to eq('fubar')
-    value = 'foobar'
-    expect(@vo.set_or_return(:test, nil, {})).to eq('foobar')
-    value = 'fauxbar'
-    expect(@vo.set_or_return(:test, nil, {})).to eq('fauxbar')
+    value = "fubar"
+    @vo.set_or_return(:test, @vo.lazy { value }, {})
+    expect(@vo.set_or_return(:test, nil, {})).to eq("fubar")
+    value = "foobar"
+    expect(@vo.set_or_return(:test, nil, {})).to eq("foobar")
+    value = "fauxbar"
+    expect(@vo.set_or_return(:test, nil, {})).to eq("fauxbar")
   end
 
   it "should not evaluate non DelayedEvaluator instances" do
-    value = lambda{ 'test' }
+    value = lambda { "test" }
     @vo.set_or_return(:test, value, {})
     expect(@vo.set_or_return(:test, nil, {}).object_id).to eq(value.object_id)
     expect(@vo.set_or_return(:test, nil, {})).to be_a(Proc)
diff --git a/spec/unit/mixin/path_sanity_spec.rb b/spec/unit/mixin/path_sanity_spec.rb
index ec8e182..e410f03 100644
--- a/spec/unit/mixin/path_sanity_spec.rb
+++ b/spec/unit/mixin/path_sanity_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class PathSanityTestHarness
   include Chef::Mixin::PathSanity
@@ -31,43 +31,43 @@ describe Chef::Mixin::PathSanity do
   describe "when enforcing path sanity" do
     before do
       Chef::Config[:enforce_path_sanity] = true
-      @ruby_bindir = '/some/ruby/bin'
-      @gem_bindir = '/some/gem/bin'
+      @ruby_bindir = "/some/ruby/bin"
+      @gem_bindir = "/some/gem/bin"
       allow(Gem).to receive(:bindir).and_return(@gem_bindir)
-      allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(@ruby_bindir)
-      allow(Chef::Platform).to receive(:windows?).and_return(false)
+      allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(@ruby_bindir)
+      allow(ChefConfig).to receive(:windows?).and_return(false)
     end
 
     it "adds all useful PATHs even if environment is an empty hash" do
-      env={}
+      env = {}
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
     end
 
     it "adds all useful PATHs that are not yet in PATH to PATH" do
-      env = {"PATH" => ""}
+      env = { "PATH" => "" }
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
     end
 
     it "does not re-add paths that already exist in PATH" do
-      env = {"PATH" => "/usr/bin:/sbin:/bin"}
+      env = { "PATH" => "/usr/bin:/sbin:/bin" }
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("/usr/bin:/sbin:/bin:#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin")
     end
 
     it "adds the current executing Ruby's bindir and Gem bindir to the PATH" do
-      env = {"PATH" => ""}
+      env = { "PATH" => "" }
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
     end
 
     it "does not create entries for Ruby/Gem bindirs if they exist in SANE_PATH or PATH" do
-      ruby_bindir = '/usr/bin'
-      gem_bindir = '/yo/gabba/gabba'
+      ruby_bindir = "/usr/bin"
+      gem_bindir = "/yo/gabba/gabba"
       allow(Gem).to receive(:bindir).and_return(gem_bindir)
-      allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(ruby_bindir)
-      env = {"PATH" => gem_bindir}
+      allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(ruby_bindir)
+      env = { "PATH" => gem_bindir }
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("/yo/gabba/gabba:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
     end
@@ -76,9 +76,9 @@ describe Chef::Mixin::PathSanity do
       ruby_bindir = 'C:\ruby\bin'
       gem_bindir = 'C:\gems\bin'
       allow(Gem).to receive(:bindir).and_return(gem_bindir)
-      allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return(ruby_bindir)
-      allow(Chef::Platform).to receive(:windows?).and_return(true)
-      env = {"PATH" => 'C:\Windows\system32;C:\mr\softie'}
+      allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(ruby_bindir)
+      allow(ChefConfig).to receive(:windows?).and_return(true)
+      env = { "PATH" => 'C:\Windows\system32;C:\mr\softie' }
       @sanity.enforce_path_sanity(env)
       expect(env["PATH"]).to eq("C:\\Windows\\system32;C:\\mr\\softie;#{ruby_bindir};#{gem_bindir}")
     end
diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb
new file mode 100644
index 0000000..b586be7
--- /dev/null
+++ b/spec/unit/mixin/powershell_out_spec.rb
@@ -0,0 +1,70 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/powershell_out"
+
+describe Chef::Mixin::PowershellOut do
+  let(:shell_out_class) { Class.new { include Chef::Mixin::PowershellOut } }
+  subject(:object) { shell_out_class.new }
+  let(:architecture) { "something" }
+  let(:flags) {
+    "-NoLogo -NonInteractive -NoProfile -ExecutionPolicy Unrestricted -InputFormat None"
+  }
+
+  describe "#powershell_out" do
+    it "runs a command and returns the shell_out object" do
+      ret = double("Mixlib::ShellOut")
+      expect(object).to receive(:shell_out).with(
+        "powershell.exe #{flags} -Command \"Get-Process\"",
+        {},
+      ).and_return(ret)
+      expect(object.powershell_out("Get-Process")).to eql(ret)
+    end
+
+    it "passes options" do
+      ret = double("Mixlib::ShellOut")
+      expect(object).to receive(:shell_out).with(
+        "powershell.exe #{flags} -Command \"Get-Process\"",
+        timeout: 600,
+      ).and_return(ret)
+      expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret)
+    end
+  end
+
+  describe "#powershell_out!" do
+    it "runs a command and returns the shell_out object" do
+      mixlib_shellout = double("Mixlib::ShellOut")
+      expect(object).to receive(:shell_out).with(
+        "powershell.exe #{flags} -Command \"Get-Process\"",
+        {},
+      ).and_return(mixlib_shellout)
+      expect(mixlib_shellout).to receive(:error!)
+      expect(object.powershell_out!("Get-Process")).to eql(mixlib_shellout)
+    end
+
+    it "passes options" do
+      mixlib_shellout = double("Mixlib::ShellOut")
+      expect(object).to receive(:shell_out).with(
+        "powershell.exe #{flags} -Command \"Get-Process\"",
+        timeout: 600,
+      ).and_return(mixlib_shellout)
+      expect(mixlib_shellout).to receive(:error!)
+      expect(object.powershell_out!("Get-Process", timeout: 600)).to eql(mixlib_shellout)
+    end
+  end
+end
diff --git a/spec/unit/mixin/powershell_type_coercions_spec.rb b/spec/unit/mixin/powershell_type_coercions_spec.rb
index 988c392..7f2ecb9 100644
--- a/spec/unit/mixin/powershell_type_coercions_spec.rb
+++ b/spec/unit/mixin/powershell_type_coercions_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/powershell_type_coercions'
-require 'base64'
+require "spec_helper"
+require "chef/mixin/powershell_type_coercions"
+require "base64"
 
 class Chef::PSTypeTester
   include Chef::Mixin::PowershellTypeCoercions
@@ -28,45 +28,56 @@ describe Chef::Mixin::PowershellTypeCoercions do
   let (:test_class) { Chef::PSTypeTester.new }
 
   describe '#translate_type' do
-    it 'should single quote a string' do
-      expect(test_class.translate_type('foo')).to eq("'foo'")
+    it "single quotes a string" do
+      expect(test_class.translate_type("foo")).to eq("'foo'")
     end
 
-    ["'", '"', '#', '`'].each do |c|
-      it "should base64 encode a string that contains #{c}" do
+    ["'", '"', '#', "`"].each do |c|
+      it "base64 encodes a string that contains #{c}" do
         expect(test_class.translate_type("#{c}")).to match(Base64.strict_encode64(c))
       end
     end
 
-    it 'should not quote an integer' do
-      expect(test_class.translate_type(123)).to eq('123')
+    it "does not quote an integer" do
+      expect(test_class.translate_type(123)).to eq("123")
     end
 
-    it 'should not quote a floating point number' do
-      expect(test_class.translate_type(123.4)).to eq('123.4')
+    it "does not quote a floating point number" do
+      expect(test_class.translate_type(123.4)).to eq("123.4")
     end
 
-    it 'should return $false when an instance of FalseClass is provided' do
-      expect(test_class.translate_type(false)).to eq('$false')
+    it "translates $false when an instance of FalseClass is provided" do
+      expect(test_class.translate_type(false)).to eq("$false")
     end
 
-    it 'should return $true when an instance of TrueClass is provided' do
-      expect(test_class.translate_type(true)).to eq('$true')
+    it "translates $true when an instance of TrueClass is provided" do
+      expect(test_class.translate_type(true)).to eq("$true")
     end
 
-    it 'should translate all members of a hash and wrap them in @{} separated by ;' do
-      expect(test_class.translate_type({"a" => 1, "b" => 1.2, "c" => false, "d" => true
+    it "translates all members of a hash and wrap them in @{} separated by ;" do
+      expect(test_class.translate_type({ "a" => 1, "b" => 1.2, "c" => false, "d" => true
       })).to eq("@{a=1;b=1.2;c=$false;d=$true}")
     end
 
-    it 'should translat all members of an array and them by a ,' do
-      expect(test_class.translate_type([true, false])).to eq('@($true,$false)')
+    it "translates all members of an array and them by a ," do
+      expect(test_class.translate_type([true, false])).to eq("@($true,$false)")
     end
 
-    it 'should fall back :to_psobject if we have not defined at explicit rule' do
+    it "translates a Chef::Node::ImmutableMash like a hash" do
+      test_mash = Chef::Node::ImmutableMash.new({ "a" => 1, "b" => 1.2,
+                                                  "c" => false, "d" => true })
+      expect(test_class.translate_type(test_mash)).to eq("@{a=1;b=1.2;c=$false;d=$true}")
+    end
+
+    it "translates a Chef::Node::ImmutableArray like an array" do
+      test_array = Chef::Node::ImmutableArray.new([true, false])
+      expect(test_class.translate_type(test_array)).to eq("@($true,$false)")
+    end
+
+    it "falls back :to_psobject if we have not defined at explicit rule" do
       ps_obj = double("PSObject")
-      expect(ps_obj).to receive(:to_psobject).and_return('$true')
-      expect(test_class.translate_type(ps_obj)).to eq('($true)')
+      expect(ps_obj).to receive(:to_psobject).and_return("$true")
+      expect(test_class.translate_type(ps_obj)).to eq("($true)")
     end
   end
 end
diff --git a/spec/unit/mixin/properties_spec.rb b/spec/unit/mixin/properties_spec.rb
new file mode 100644
index 0000000..00e339a
--- /dev/null
+++ b/spec/unit/mixin/properties_spec.rb
@@ -0,0 +1,97 @@
+require "support/shared/integration/integration_helper"
+require "chef/mixin/properties"
+
+module ChefMixinPropertiesSpec
+  describe "Chef::Resource.property" do
+    include IntegrationSupport
+
+    context "with a base class A with properties a, ab, and ac" do
+      class A
+        include Chef::Mixin::Properties
+        property :a, "a", default: "a"
+        property :ab, ["a", "b"], default: "a"
+        property :ac, ["a", "c"], default: "a"
+      end
+
+      context "and a module B with properties b, ab and bc" do
+        module B
+          include Chef::Mixin::Properties
+          property :b, "b", default: "b"
+          property :ab, default: "b"
+          property :bc, ["b", "c"], default: "c"
+        end
+
+        context "and a derived class C < A with properties c, ac and bc" do
+          class C < A
+            include B
+            property :c, "c", default: "c"
+            property :ac, default: "c"
+            property :bc, default: "c"
+          end
+
+          it "A.properties has a, ab, and ac with types 'a', ['a', 'b'], and ['b', 'c']" do
+            expect(A.properties.keys).to eq [ :a, :ab, :ac ]
+            expect(A.properties[:a].validation_options[:is]).to eq "a"
+            expect(A.properties[:ab].validation_options[:is]).to eq [ "a", "b" ]
+            expect(A.properties[:ac].validation_options[:is]).to eq [ "a", "c" ]
+          end
+          it "B.properties has b, ab, and bc with types 'b', nil and ['b', 'c']" do
+            expect(B.properties.keys).to eq [ :b, :ab, :bc ]
+            expect(B.properties[:b].validation_options[:is]).to eq "b"
+            expect(B.properties[:ab].validation_options[:is]).to be_nil
+            expect(B.properties[:bc].validation_options[:is]).to eq [ "b", "c" ]
+          end
+          it "C.properties has a, b, c, ac and bc with merged types" do
+            expect(C.properties.keys).to eq [ :a, :ab, :ac, :b, :bc, :c ]
+            expect(C.properties[:a].validation_options[:is]).to eq "a"
+            expect(C.properties[:b].validation_options[:is]).to eq "b"
+            expect(C.properties[:c].validation_options[:is]).to eq "c"
+            expect(C.properties[:ac].validation_options[:is]).to eq [ "a", "c" ]
+            expect(C.properties[:bc].validation_options[:is]).to eq [ "b", "c" ]
+          end
+          it "C.properties has ab with a non-merged type (from B)" do
+            expect(C.properties[:ab].validation_options[:is]).to be_nil
+          end
+
+          context "and an instance of C" do
+            let(:c) { C.new }
+
+            it "all properties can be retrieved and merged properties default to ab->b, ac->c, bc->c" do
+              expect(c.a).to  eq("a")
+              expect(c.b).to  eq("b")
+              expect(c.c).to  eq("c")
+              expect(c.ab).to eq("b")
+              expect(c.ac).to eq("c")
+              expect(c.bc).to eq("c")
+            end
+          end
+        end
+      end
+    end
+  end
+
+  context "with an Inner module" do
+    module Inner
+      include Chef::Mixin::Properties
+      property :inner
+    end
+
+    context "and an Outer module including it" do
+      module Outer
+        include Inner
+        property :outer
+      end
+
+      context "and an Outerest class including that" do
+        class Outerest
+          include Outer
+          property :outerest
+        end
+
+        it "Outerest.properties.validation_options[:is] inner, outer, outerest" do
+          expect(Outerest.properties.keys).to eq [:inner, :outer, :outerest]
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/mixin/proxified_socket_spec.rb b/spec/unit/mixin/proxified_socket_spec.rb
new file mode 100644
index 0000000..1d752bb
--- /dev/null
+++ b/spec/unit/mixin/proxified_socket_spec.rb
@@ -0,0 +1,94 @@
+#
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/proxified_socket"
+require "proxifier/proxy"
+
+class TestProxifiedSocket
+  include Chef::Mixin::ProxifiedSocket
+end
+
+describe Chef::Mixin::ProxifiedSocket do
+
+  before do
+    @original_env = ENV.to_hash
+  end
+
+  after do
+    ENV.clear
+    ENV.update(@original_env)
+  end
+
+  let(:host) { "host" }
+  let(:port) { 7979 }
+  let(:test_instance) { TestProxifiedSocket.new }
+  let(:socket_double) { instance_double(TCPSocket) }
+  let(:proxifier_double) { instance_double(Proxifier::Proxy) }
+  let(:http_uri) { "http://somehost:1" }
+  let(:https_uri) { "https://somehost:1" }
+  let(:no_proxy_spec) { nil }
+
+  shared_examples "proxified socket" do
+    it "wraps the Socket in a Proxifier::Proxy" do
+      expect(Proxifier).to receive(:Proxy).with(proxy_uri, no_proxy: no_proxy_spec).and_return(proxifier_double)
+      expect(proxifier_double).to receive(:open).with(host, port).and_return(socket_double)
+      expect(test_instance.proxified_socket(host, port)).to eq(socket_double)
+    end
+  end
+
+  context "when no proxy is set" do
+    it "returns a plain TCPSocket" do
+      expect(TCPSocket).to receive(:new).with(host, port).and_return(socket_double)
+      expect(test_instance.proxified_socket(host, port)).to eq(socket_double)
+    end
+  end
+
+  context "when https_proxy is set" do
+    before do
+      # I'm purposefully setting both of these because we prefer the https
+      # variable
+      ENV["https_proxy"] = https_uri
+      ENV["http_proxy"] = http_uri
+    end
+
+    let(:proxy_uri) { https_uri }
+    include_examples "proxified socket"
+
+    context "when no_proxy is set" do
+      # This is testing that no_proxy is also provided to Proxified
+      # when it is set
+      before do
+        ENV["no_proxy"] = no_proxy_spec
+      end
+
+      let(:no_proxy_spec) { "somehost1,somehost2" }
+      include_examples "proxified socket"
+    end
+  end
+
+  context "when http_proxy is set" do
+    before do
+      ENV["http_proxy"] = http_uri
+    end
+
+    let(:proxy_uri) { http_uri }
+    include_examples "proxified socket"
+  end
+
+end
diff --git a/spec/unit/mixin/securable_spec.rb b/spec/unit/mixin/securable_spec.rb
index 714d6de..6f50ce8 100644
--- a/spec/unit/mixin/securable_spec.rb
+++ b/spec/unit/mixin/securable_spec.rb
@@ -1,7 +1,7 @@
 # encoding: UTF-8
 #
-# Author:: Mark Mzyk (<mmzyk at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Mark Mzyk (<mmzyk at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Mixin::Securable do
 
@@ -59,32 +59,32 @@ describe Chef::Mixin::Securable do
     end
 
     it "should accept group/owner names that are a single character or digit" do
-      expect { @securable.group 'v' }.not_to raise_error
-      expect { @securable.group '1' }.not_to raise_error
-      expect { @securable.owner 'v' }.not_to raise_error
-      expect { @securable.owner '1' }.not_to raise_error
+      expect { @securable.group "v" }.not_to raise_error
+      expect { @securable.group "1" }.not_to raise_error
+      expect { @securable.owner "v" }.not_to raise_error
+      expect { @securable.owner "1" }.not_to raise_error
     end
 
     it "should not accept group/owner names starting with '-', '+', or '~'" do
-      expect { @securable.group '-test' }.to raise_error(ArgumentError)
-      expect { @securable.group '+test' }.to raise_error(ArgumentError)
-      expect { @securable.group '~test' }.to raise_error(ArgumentError)
-      expect { @securable.group 'te-st' }.not_to raise_error
-      expect { @securable.group 'te+st' }.not_to raise_error
-      expect { @securable.group 'te~st' }.not_to raise_error
-      expect { @securable.owner '-test' }.to raise_error(ArgumentError)
-      expect { @securable.owner '+test' }.to raise_error(ArgumentError)
-      expect { @securable.owner '~test' }.to raise_error(ArgumentError)
-      expect { @securable.owner 'te-st' }.not_to raise_error
-      expect { @securable.owner 'te+st' }.not_to raise_error
-      expect { @securable.owner 'te~st' }.not_to raise_error
+      expect { @securable.group "-test" }.to raise_error(ArgumentError)
+      expect { @securable.group "+test" }.to raise_error(ArgumentError)
+      expect { @securable.group "~test" }.to raise_error(ArgumentError)
+      expect { @securable.group "te-st" }.not_to raise_error
+      expect { @securable.group "te+st" }.not_to raise_error
+      expect { @securable.group "te~st" }.not_to raise_error
+      expect { @securable.owner "-test" }.to raise_error(ArgumentError)
+      expect { @securable.owner "+test" }.to raise_error(ArgumentError)
+      expect { @securable.owner "~test" }.to raise_error(ArgumentError)
+      expect { @securable.owner "te-st" }.not_to raise_error
+      expect { @securable.owner "te+st" }.not_to raise_error
+      expect { @securable.owner "te~st" }.not_to raise_error
     end
 
     it "should not accept group/owner names containing ':', ',' or non-space whitespace" do
-      expect { @securable.group ':test' }.to raise_error(ArgumentError)
-      expect { @securable.group 'te:st' }.to raise_error(ArgumentError)
-      expect { @securable.group ',test' }.to raise_error(ArgumentError)
-      expect { @securable.group 'te,st' }.to raise_error(ArgumentError)
+      expect { @securable.group ":test" }.to raise_error(ArgumentError)
+      expect { @securable.group "te:st" }.to raise_error(ArgumentError)
+      expect { @securable.group ",test" }.to raise_error(ArgumentError)
+      expect { @securable.group "te,st" }.to raise_error(ArgumentError)
       expect { @securable.group "\ttest" }.to raise_error(ArgumentError)
       expect { @securable.group "te\tst" }.to raise_error(ArgumentError)
       expect { @securable.group "\rtest" }.to raise_error(ArgumentError)
@@ -93,10 +93,10 @@ describe Chef::Mixin::Securable do
       expect { @securable.group "te\fst" }.to raise_error(ArgumentError)
       expect { @securable.group "\0test" }.to raise_error(ArgumentError)
       expect { @securable.group "te\0st" }.to raise_error(ArgumentError)
-      expect { @securable.owner ':test' }.to raise_error(ArgumentError)
-      expect { @securable.owner 'te:st' }.to raise_error(ArgumentError)
-      expect { @securable.owner ',test' }.to raise_error(ArgumentError)
-      expect { @securable.owner 'te,st' }.to raise_error(ArgumentError)
+      expect { @securable.owner ":test" }.to raise_error(ArgumentError)
+      expect { @securable.owner "te:st" }.to raise_error(ArgumentError)
+      expect { @securable.owner ",test" }.to raise_error(ArgumentError)
+      expect { @securable.owner "te,st" }.to raise_error(ArgumentError)
       expect { @securable.owner "\ttest" }.to raise_error(ArgumentError)
       expect { @securable.owner "te\tst" }.to raise_error(ArgumentError)
       expect { @securable.owner "\rtest" }.to raise_error(ArgumentError)
@@ -124,10 +124,10 @@ describe Chef::Mixin::Securable do
     end
 
     it "should accept group/owner names in UTF-8" do
-      expect { @securable.group 'tëst' }.not_to raise_error
-      expect { @securable.group 'ë' }.not_to raise_error
-      expect { @securable.owner 'tëst' }.not_to raise_error
-      expect { @securable.owner 'ë' }.not_to raise_error
+      expect { @securable.group "tëst" }.not_to raise_error
+      expect { @securable.group "ë" }.not_to raise_error
+      expect { @securable.owner "tëst" }.not_to raise_error
+      expect { @securable.owner "ë" }.not_to raise_error
     end
 
     it "should accept a unix file mode in string form as an octal number" do
@@ -227,9 +227,9 @@ describe Chef::Mixin::Securable do
       expect { @securable.mode 0111 }.not_to raise_error
       expect { @securable.mode 73 }.not_to raise_error
 
-      expect { @securable.mode -01 }.to raise_error(ArgumentError)
+      expect { @securable.mode(-01) }.to raise_error(ArgumentError)
       expect { @securable.mode 010000 }.to raise_error(ArgumentError)
-      expect { @securable.mode -1 }.to raise_error(ArgumentError)
+      expect { @securable.mode(-1) }.to raise_error(ArgumentError)
       expect { @securable.mode 4096 }.to raise_error(ArgumentError)
     end
 
@@ -253,7 +253,7 @@ describe Chef::Mixin::Securable do
 
     it "should accept a principal as a string or an array" do
       expect { @securable.rights :read, "The Dude" }.not_to raise_error
-      expect { @securable.rights :read, ["The Dude","Donny"] }.not_to raise_error
+      expect { @securable.rights :read, ["The Dude", "Donny"] }.not_to raise_error
       expect { @securable.rights :read, 3 }.to raise_error(ArgumentError)
     end
 
@@ -262,19 +262,19 @@ describe Chef::Mixin::Securable do
       expect { @securable.rights :read, "The Dude", :applies_to_children => true }.not_to raise_error
       expect { @securable.rights :read, "The Dude", :applies_to_children => :containers_only }.not_to raise_error
       expect { @securable.rights :read, "The Dude", :applies_to_children => :objects_only }.not_to raise_error
-      expect { @securable.rights :read, "The Dude", :applies_to_children => 'poop' }.to raise_error(ArgumentError)
+      expect { @securable.rights :read, "The Dude", :applies_to_children => "poop" }.to raise_error(ArgumentError)
     end
 
     it "should allow you to specify whether the permissions applies_to_self with true/false" do
       expect { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.not_to raise_error
       expect { @securable.rights :read, "The Dude", :applies_to_self => true }.not_to raise_error
-      expect { @securable.rights :read, "The Dude", :applies_to_self => 'poop' }.to raise_error(ArgumentError)
+      expect { @securable.rights :read, "The Dude", :applies_to_self => "poop" }.to raise_error(ArgumentError)
     end
 
     it "should allow you to specify whether the permissions applies one_level_deep with true/false" do
       expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.not_to raise_error
       expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.not_to raise_error
-      expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => 'poop' }.to raise_error(ArgumentError)
+      expect { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => "poop" }.to raise_error(ArgumentError)
     end
 
     it "should allow multiple rights and deny_rights declarations" do
diff --git a/spec/unit/mixin/shell_out_spec.rb b/spec/unit/mixin/shell_out_spec.rb
index beaf624..12336b1 100644
--- a/spec/unit/mixin/shell_out_spec.rb
+++ b/spec/unit/mixin/shell_out_spec.rb
@@ -1,10 +1,10 @@
 #
-# Author:: Ho-Sheng Hsiao (hosh at opscode.com)
+# Author:: Ho-Sheng Hsiao (hosh at chef.io)
 # Code derived from spec/unit/mixin/command_spec.rb
 #
 # Original header:
 # Author:: Hongli Lai (hongli at phusion.nl)
-# Copyright:: Copyright (c) 2009 Phusion
+# Copyright:: Copyright 2009-2016, Phusion
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Mixin::ShellOut do
   let(:shell_out_class) { Class.new { include Chef::Mixin::ShellOut } }
@@ -31,28 +31,28 @@ describe Chef::Mixin::ShellOut do
     let(:cmd) { "echo '#{rand(1000)}'" }
 
     let(:output) { StringIO.new }
-    let!(:capture_log_output) { Chef::Log.logger = Logger.new(output)  }
+    let!(:capture_log_output) { Chef::Log.logger = Logger.new(output) }
     let(:assume_deprecation_log_level) { allow(Chef::Log).to receive(:level).and_return(:warn) }
 
-    context 'without options' do
+    context "without options" do
       let(:command_args) { [ cmd ] }
 
-      it 'should not edit command args' do
+      it "should not edit command args" do
         is_expected.to eql(command_args)
       end
     end
 
-    context 'without deprecated options' do
+    context "without deprecated options" do
       let(:options) { { :environment => environment } }
-      let(:environment) { { 'LC_ALL' => 'C', 'LANG' => 'C', 'LANGUAGE' => 'C' } }
+      let(:environment) { { "LC_ALL" => "C", "LANG" => "C", "LANGUAGE" => "C" } }
 
-      it 'should not edit command args' do
+      it "should not edit command args" do
         is_expected.to eql(command_args)
       end
     end
 
     def self.should_emit_deprecation_warning_about(old_option, new_option)
-      it 'should emit a deprecation warning' do
+      it "should emit a deprecation warning" do
         assume_deprecation_log_level and capture_log_output
         subject
         expect(output.string).to match /DEPRECATION:/
@@ -61,22 +61,22 @@ describe Chef::Mixin::ShellOut do
       end
     end
 
-    context 'with :command_log_level option' do
+    context "with :command_log_level option" do
       let(:options) { { :command_log_level => command_log_level } }
       let(:command_log_level) { :warn }
 
-      it 'should convert :command_log_level to :log_level' do
+      it "should convert :command_log_level to :log_level" do
         is_expected.to eql [ cmd, { :log_level => command_log_level } ]
       end
 
       should_emit_deprecation_warning_about :command_log_level, :log_level
     end
 
-    context 'with :command_log_prepend option' do
+    context "with :command_log_prepend option" do
       let(:options) { { :command_log_prepend => command_log_prepend } }
-      let(:command_log_prepend) { 'PROVIDER:' }
+      let(:command_log_prepend) { "PROVIDER:" }
 
-      it 'should convert :command_log_prepend to :log_tag' do
+      it "should convert :command_log_prepend to :log_tag" do
         is_expected.to eql [ cmd, { :log_tag => command_log_prepend } ]
       end
 
@@ -84,7 +84,7 @@ describe Chef::Mixin::ShellOut do
     end
 
     context "with 'command_log_level' option" do
-      let(:options) { { 'command_log_level' => command_log_level } }
+      let(:options) { { "command_log_level" => command_log_level } }
       let(:command_log_level) { :warn }
 
       it "should convert 'command_log_level' to :log_level" do
@@ -95,8 +95,8 @@ describe Chef::Mixin::ShellOut do
     end
 
     context "with 'command_log_prepend' option" do
-      let(:options) { { 'command_log_prepend' => command_log_prepend } }
-      let(:command_log_prepend) { 'PROVIDER:' }
+      let(:options) { { "command_log_prepend" => command_log_prepend } }
+      let(:command_log_prepend) { "PROVIDER:" }
 
       it "should convert 'command_log_prepend' to :log_tag" do
         is_expected.to eql [ cmd, { :log_tag => command_log_prepend } ]
@@ -124,97 +124,97 @@ describe Chef::Mixin::ShellOut do
       describe "when the last argument is a Hash" do
         describe "and environment is an option" do
           it "should not change environment language settings when they are set to nil" do
-            options = { :environment => { 'LC_ALL' => nil, 'LANGUAGE' => nil, 'LANG' => nil } }
+            options = { :environment => { "LC_ALL" => nil, "LANGUAGE" => nil, "LANG" => nil } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should not change environment language settings when they are set to non-nil" do
-            options = { :environment => { 'LC_ALL' => 'en_US.UTF-8', 'LANGUAGE' => 'en_US.UTF-8', 'LANG' => 'en_US.UTF-8' } }
+            options = { :environment => { "LC_ALL" => "en_US.UTF-8", "LANGUAGE" => "en_US.UTF-8", "LANG" => "en_US.UTF-8" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should set environment language settings to the configured internal locale when they are not present" do
-            options = { :environment => { 'HOME' => '/Users/morty' } }
+            options = { :environment => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
               :environment => {
-                'HOME'     => '/Users/morty',
-                'LC_ALL'   => Chef::Config[:internal_locale],
-                'LANG'     => Chef::Config[:internal_locale],
-                'LANGUAGE' => Chef::Config[:internal_locale],
-              },
-            }).and_return(true)
+                "HOME"     => "/Users/morty",
+                "LC_ALL"   => Chef::Config[:internal_locale],
+                "LANG"     => Chef::Config[:internal_locale],
+                "LANGUAGE" => Chef::Config[:internal_locale],
+              }
+            },).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should not mutate the options hash when it adds language settings" do
-            options = { :environment => { 'HOME' => '/Users/morty' } }
+            options = { :environment => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
               :environment => {
-                'HOME'     => '/Users/morty',
-                'LC_ALL'   => Chef::Config[:internal_locale],
-                'LANG'     => Chef::Config[:internal_locale],
-                'LANGUAGE' => Chef::Config[:internal_locale],
-              },
-            }).and_return(true)
+                "HOME"     => "/Users/morty",
+                "LC_ALL"   => Chef::Config[:internal_locale],
+                "LANG"     => Chef::Config[:internal_locale],
+                "LANGUAGE" => Chef::Config[:internal_locale],
+              }
+            },).and_return(true)
             shell_out_obj.shell_out(cmd, options)
-            expect(options[:environment].has_key?('LC_ALL')).to be false
+            expect(options[:environment].has_key?("LC_ALL")).to be false
           end
         end
 
         describe "and env is an option" do
           it "should not change env when langauge options are set to nil" do
-            options = { :env => { 'LC_ALL' => nil, 'LANG' => nil, 'LANGUAGE' => nil } }
+            options = { :env => { "LC_ALL" => nil, "LANG" => nil, "LANGUAGE" => nil } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should not change env when language options are set to non-nil" do
-            options = { :env => { 'LC_ALL' => 'de_DE.UTF-8', 'LANG' => 'de_DE.UTF-8', 'LANGUAGE' => 'de_DE.UTF-8' }}
+            options = { :env => { "LC_ALL" => "de_DE.UTF-8", "LANG" => "de_DE.UTF-8", "LANGUAGE" => "de_DE.UTF-8" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should set environment language settings to the configured internal locale when they are not present" do
-            options = { :env => { 'HOME' => '/Users/morty' } }
+            options = { :env => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
               :env => {
-                'HOME'     => '/Users/morty',
-                'LC_ALL'   => Chef::Config[:internal_locale],
-                'LANG'     => Chef::Config[:internal_locale],
-                'LANGUAGE' => Chef::Config[:internal_locale],
+                "HOME"     => "/Users/morty",
+                "LC_ALL"   => Chef::Config[:internal_locale],
+                "LANG"     => Chef::Config[:internal_locale],
+                "LANGUAGE" => Chef::Config[:internal_locale],
               }
-            }).and_return(true)
+            },).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
 
           it "should not mutate the options hash when it adds language settings" do
-            options = { :env => { 'HOME' => '/Users/morty' } }
+            options = { :env => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
               :env => {
-                'HOME'     => '/Users/morty',
-                'LC_ALL'   => Chef::Config[:internal_locale],
-                'LANG'     => Chef::Config[:internal_locale],
-                'LANGUAGE' => Chef::Config[:internal_locale],
+                "HOME"     => "/Users/morty",
+                "LC_ALL"   => Chef::Config[:internal_locale],
+                "LANG"     => Chef::Config[:internal_locale],
+                "LANGUAGE" => Chef::Config[:internal_locale],
               }
-            }).and_return(true)
+            },).and_return(true)
             shell_out_obj.shell_out(cmd, options)
-            expect(options[:env].has_key?('LC_ALL')).to be false
+            expect(options[:env].has_key?("LC_ALL")).to be false
           end
         end
 
         describe "and no env/environment option is present" do
           it "should set environment language settings to the configured internal locale" do
-            options = { :user => 'morty' }
+            options = { :user => "morty" }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
-              :user => 'morty',
+              :user => "morty",
               :environment => {
-                'LC_ALL'   => Chef::Config[:internal_locale],
-                'LANG'     => Chef::Config[:internal_locale],
-                'LANGUAGE' => Chef::Config[:internal_locale],
+                "LC_ALL"   => Chef::Config[:internal_locale],
+                "LANG"     => Chef::Config[:internal_locale],
+                "LANGUAGE" => Chef::Config[:internal_locale],
               },
-            }).and_return(true)
+            },).and_return(true)
             shell_out_obj.shell_out(cmd, options)
           end
         end
@@ -224,11 +224,11 @@ describe Chef::Mixin::ShellOut do
         it "should set environment language settings to the configured internal locale" do
           expect(shell_out_obj).to receive(:shell_out_command).with(cmd, {
             :environment => {
-              'LC_ALL'   => Chef::Config[:internal_locale],
-              'LANG'     => Chef::Config[:internal_locale],
-              'LANGUAGE' => Chef::Config[:internal_locale],
-            },
-          }).and_return(true)
+              "LC_ALL"   => Chef::Config[:internal_locale],
+              "LANG"     => Chef::Config[:internal_locale],
+              "LANGUAGE" => Chef::Config[:internal_locale],
+            }
+          },).and_return(true)
           shell_out_obj.shell_out(cmd)
         end
       end
@@ -240,19 +240,19 @@ describe Chef::Mixin::ShellOut do
       describe "when the last argument is a Hash" do
         describe "and environment is an option" do
           it "should not change environment['LC_ALL'] when set to nil" do
-            options = { :environment => { 'LC_ALL' => nil } }
+            options = { :environment => { "LC_ALL" => nil } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
 
           it "should not change environment['LC_ALL'] when set to non-nil" do
-            options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } }
+            options = { :environment => { "LC_ALL" => "en_US.UTF-8" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
 
           it "should no longer set environment['LC_ALL'] to nil when 'LC_ALL' not present" do
-            options = { :environment => { 'HOME' => '/Users/morty' } }
+            options = { :environment => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
@@ -260,19 +260,19 @@ describe Chef::Mixin::ShellOut do
 
         describe "and env is an option" do
           it "should not change env when set to nil" do
-            options = { :env => { 'LC_ALL' => nil } }
+            options = { :env => { "LC_ALL" => nil } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
 
           it "should not change env when set to non-nil" do
-            options = { :env => { 'LC_ALL' => 'en_US.UTF-8'}}
+            options = { :env => { "LC_ALL" => "en_US.UTF-8" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
 
           it "should no longer set env['LC_ALL'] to nil when 'LC_ALL' not present" do
-            options = { :env => { 'HOME' => '/Users/morty' } }
+            options = { :env => { "HOME" => "/Users/morty" } }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
@@ -280,7 +280,7 @@ describe Chef::Mixin::ShellOut do
 
         describe "and no env/environment option is present" do
           it "should no longer add environment option and set environment['LC_ALL'] to nil" do
-            options = { :user => 'morty' }
+            options = { :user => "morty" }
             expect(shell_out_obj).to receive(:shell_out_command).with(cmd, options).and_return(true)
             shell_out_obj.shell_out_with_systems_locale(cmd, options)
           end
diff --git a/spec/unit/mixin/subclass_directive_spec.rb b/spec/unit/mixin/subclass_directive_spec.rb
new file mode 100644
index 0000000..ef3c566
--- /dev/null
+++ b/spec/unit/mixin/subclass_directive_spec.rb
@@ -0,0 +1,45 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+class SubclassDirectiveParent
+  extend Chef::Mixin::SubclassDirective
+
+  subclass_directive :behave_differently
+end
+
+class SubclassDirectiveChild < SubclassDirectiveParent
+  behave_differently
+end
+
+class ChildWithoutDirective < SubclassDirectiveParent
+end
+
+describe Chef::Mixin::Uris do
+  let (:child) { SubclassDirectiveChild.new }
+
+  let (:other_child) { ChildWithoutDirective.new }
+
+  it "the child instance has the directive set" do
+    expect(child.behave_differently?).to be true
+  end
+
+  it "a child that does not declare it does not have it set" do
+    expect(other_child.behave_differently?).to be false
+  end
+end
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index f02bd34..48150f7 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'cgi'
+require "cgi"
 describe Chef::Mixin::Template, "render_template" do
 
   let(:sep) { Chef::Platform.windows? ? "\r\n" : "\n" }
@@ -39,7 +39,7 @@ describe Chef::Mixin::Template, "render_template" do
 
   describe "when running on windows" do
     before do
-      allow(Chef::Platform).to receive(:windows?).and_return(true)
+      allow(ChefConfig).to receive(:windows?).and_return(true)
     end
 
     it "should render the templates with windows line endings" do
@@ -54,7 +54,7 @@ describe Chef::Mixin::Template, "render_template" do
 
   describe "when running on unix" do
     before do
-      allow(Chef::Platform).to receive(:windows?).and_return(false)
+      allow(ChefConfig).to receive(:windows?).and_return(false)
     end
 
     it "should render the templates with unix line endings" do
@@ -85,10 +85,10 @@ describe Chef::Mixin::Template, "render_template" do
       @events = Chef::EventDispatch::Dispatcher.new
       @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
 
-      @rendered_file_location = Dir.tmpdir + '/openldap_stuff.conf'
+      @rendered_file_location = Dir.tmpdir + "/openldap_stuff.conf"
 
       @resource = Chef::Resource::Template.new(@rendered_file_location)
-      @resource.cookbook_name = 'openldap'
+      @resource.cookbook_name = "openldap"
       @current_resource = @resource.dup
 
       @content_provider = Chef::Provider::Template::Content.new(@resource, @current_resource, @run_context)
@@ -117,7 +117,7 @@ describe Chef::Mixin::Template, "render_template" do
     end
 
     it "should render partials from a different cookbook" do
-      @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, 'apache2', @node)
+      @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, "apache2", @node)
 
       output = @template_context.render_template_from_string("before {<%= render('test.erb', :cookbook => 'openldap').strip %>} after")
       expect(output).to eq("before {We could be diving for pearls!} after")
@@ -144,19 +144,24 @@ describe Chef::Mixin::Template, "render_template" do
     end
 
     it "should pass the original variables to partials" do
-      @template_context[:secret] = 'candy'
+      @template_context[:secret] = "candy"
 
       output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after")
       output == "before {super secret is candy} after"
     end
 
+    it "should pass the template finder to the partials" do
+      output = @template_context.render_template_from_string("before {<%= render 'nested_openldap_partials.erb', :variables => {:hello => 'Hello World!' } %>} after")
+      output == "before {Hello World!} after"
+    end
+
     it "should pass variables to partials" do
       output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'whatever' } %>} after")
       expect(output).to eq("before {super secret is whatever} after")
     end
 
     it "should pass variables to partials even if they are named the same" do
-      @template_context[:secret] = 'one'
+      @template_context[:secret] = "one"
 
       output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'two' } %>} after <%= @secret %>")
       expect(output).to eq("before {super secret is two} after one")
@@ -167,7 +172,7 @@ describe Chef::Mixin::Template, "render_template" do
       expect(output).to eq("before {super secret is } after")
 
       output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after")
-    expect(output).to eq("before {super secret is } after")
+      expect(output).to eq("before {super secret is } after")
     end
 
     it "should render nested partials" do
@@ -194,14 +199,17 @@ describe Chef::Mixin::Template, "render_template" do
         mod = Module.new do
           def render
           end
+
           def node
           end
+
           def render_template
           end
+
           def render_template_from_string
           end
         end
-        ['node', 'render', 'render_template', 'render_template_from_string'].each do |method_name|
+        ["node", "render", "render_template", "render_template_from_string"].each do |method_name|
           expect(Chef::Log).to receive(:warn).with(/^Core template method `#{method_name}' overridden by extension module/)
         end
         @template_context._extend_modules([mod])
@@ -220,7 +228,7 @@ describe Chef::Mixin::Template, "render_template" do
     end
 
     it "should raise an error if an attempt is made to access node but it is nil" do
-      expect {@context.render_template_from_string("<%= node %>") {|r| r}}.to raise_error(Chef::Mixin::Template::TemplateError)
+      expect { @context.render_template_from_string("<%= node %>") { |r| r } }.to raise_error(Chef::Mixin::Template::TemplateError)
     end
 
     describe "the raised TemplateError" do
@@ -266,4 +274,3 @@ describe Chef::Mixin::Template, "render_template" do
     end
   end
 end
-
diff --git a/spec/unit/mixin/unformatter_spec.rb b/spec/unit/mixin/unformatter_spec.rb
new file mode 100644
index 0000000..b2b57c1
--- /dev/null
+++ b/spec/unit/mixin/unformatter_spec.rb
@@ -0,0 +1,61 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/unformatter"
+
+class Chef::UnformatterTest
+  include Chef::Mixin::Unformatter
+
+  def foo
+  end
+
+end
+
+describe Chef::Mixin::Unformatter do
+  let (:unformatter) { Chef::UnformatterTest.new }
+  let (:message) { "Test Message" }
+
+  describe "#write" do
+    context "with a timestamp" do
+      it "sends foo to itself when the message is of severity foo" do
+        expect(unformatter).to receive(:foo).with(message)
+        unformatter.write("[time] foo: #{message}")
+      end
+
+      it "sends foo to itself when the message is of severity FOO" do
+        expect(unformatter).to receive(:foo).with(message)
+        unformatter.write("[time] FOO: #{message}")
+      end
+    end
+
+    context "without a timestamp" do
+      it "sends foo to itself when the message is of severity foo" do
+        expect(unformatter).to receive(:foo).with(message)
+        unformatter.write("foo: #{message}")
+      end
+
+      it "sends foo to itself when the message is of severity FOO" do
+        expect(unformatter).to receive(:foo).with(message)
+        unformatter.write("FOO: #{message}")
+      end
+    end
+
+  end
+
+end
diff --git a/spec/unit/mixin/uris_spec.rb b/spec/unit/mixin/uris_spec.rb
new file mode 100644
index 0000000..9005edd
--- /dev/null
+++ b/spec/unit/mixin/uris_spec.rb
@@ -0,0 +1,57 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/mixin/uris"
+
+class Chef::UrisTest
+  include Chef::Mixin::Uris
+end
+
+describe Chef::Mixin::Uris do
+  let (:uris) { Chef::UrisTest.new }
+
+  describe "#uri_scheme?" do
+    it "matches 'scheme://foo.com'" do
+      expect(uris.uri_scheme?("scheme://foo.com")).to eq(true)
+    end
+
+    it "does not match 'c:/foo.com'" do
+      expect(uris.uri_scheme?("c:/foo.com")).to eq(false)
+    end
+
+    it "does not match '/usr/bin/foo.com'" do
+      expect(uris.uri_scheme?("/usr/bin/foo.com")).to eq(false)
+    end
+
+    it "does not match 'c:/foo.com://bar.com'" do
+      expect(uris.uri_scheme?("c:/foo.com://bar.com")).to eq(false)
+    end
+  end
+
+  describe "#as_uri" do
+    it "parses a file scheme uri with spaces" do
+      expect { uris.as_uri("file:///c:/foo bar.txt") }.not_to raise_exception
+    end
+
+    it "returns a URI object" do
+      expect( uris.as_uri("file:///c:/foo bar.txt") ).to be_a(URI)
+    end
+  end
+
+end
diff --git a/spec/unit/mixin/windows_architecture_helper_spec.rb b/spec/unit/mixin/windows_architecture_helper_spec.rb
index 3803d69..aaf9fa4 100644
--- a/spec/unit/mixin/windows_architecture_helper_spec.rb
+++ b/spec/unit/mixin/windows_architecture_helper_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,8 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
-require 'chef/mixin/windows_architecture_helper'
-
-
+require "spec_helper"
+require "chef/mixin/windows_architecture_helper"
 
 describe Chef::Mixin::WindowsArchitectureHelper do
   include Chef::Mixin::WindowsArchitectureHelper
@@ -34,25 +31,25 @@ describe Chef::Mixin::WindowsArchitectureHelper do
   end
 
   it "returns true when valid architectures are passed to valid_windows_architecture?" do
-    @valid_architectures.each do | architecture |
+    @valid_architectures.each do |architecture|
       expect(valid_windows_architecture?(architecture)).to eq(true)
     end
   end
 
   it "returns false when invalid architectures are passed to valid_windows_architecture?" do
-    @invalid_architectures.each do | architecture |
+    @invalid_architectures.each do |architecture|
       expect(valid_windows_architecture?(architecture)).to eq(false)
     end
   end
 
   it "does not raise an exception when a valid architecture is passed to assert_valid_windows_architecture!" do
-    @valid_architectures.each do | architecture |
+    @valid_architectures.each do |architecture|
       assert_valid_windows_architecture!(architecture)
     end
   end
 
   it "raises an error if an invalid architecture is passed to assert_valid_windows_architecture!" do
-    @invalid_architectures.each do | architecture |
+    @invalid_architectures.each do |architecture|
       begin
         expect(assert_valid_windows_architecture!(architecture)).to raise_error Chef::Exceptions::Win32ArchitectureIncorrect
       rescue Chef::Exceptions::Win32ArchitectureIncorrect
@@ -60,23 +57,28 @@ describe Chef::Mixin::WindowsArchitectureHelper do
     end
   end
 
-  it "returns true for each supported desired architecture for all nodes with each valid architecture passed to node_supports_windows_architecture" do
-    enumerate_architecture_node_combinations(true)
+  it "returns true only for supported desired architecture passed to node_supports_windows_architecture" do
+    with_node_architecture_combinations do |node, desired_arch|
+      expect(node_supports_windows_architecture?(node, desired_arch)).to be true if (node_windows_architecture(node) == :x86_64 || desired_arch == :i386 )
+      expect(node_supports_windows_architecture?(node, desired_arch)).to be false if (node_windows_architecture(node) == :i386 && desired_arch == :x86_64 )
+    end
   end
 
-  it "returns false for each unsupported desired architecture for all nodes with each valid architecture passed to node_supports_windows_architecture?" do
-    enumerate_architecture_node_combinations(true)
+  it "returns true only when forced_32bit_override_required? has 64-bit node architecture and 32-bit desired architecture" do
+    with_node_architecture_combinations do |node, desired_arch|
+      expect(forced_32bit_override_required?(node, desired_arch)).to be true if ((node_windows_architecture(node) == :x86_64) && (desired_arch == :i386) && !is_i386_process_on_x86_64_windows?)
+      expect(forced_32bit_override_required?(node, desired_arch)).to be false if ! ((node_windows_architecture(node) == :x86_64) && (desired_arch == :i386))
+    end
   end
 
-  def enumerate_architecture_node_combinations(only_valid_combinations)
-    @valid_architectures.each do | node_architecture |
+  def with_node_architecture_combinations
+    @valid_architectures.each do |node_architecture|
       new_node = Chef::Node.new
       new_node.default["kernel"] = Hash.new
       new_node.default["kernel"][:machine] = node_architecture.to_s
 
-      @valid_architectures.each do | supported_architecture |
-        expect(node_supports_windows_architecture?(new_node, supported_architecture)).to eq(true) if only_valid_combinations && (supported_architecture != :x86_64 && node_architecture != :i386 )
-        expect(node_supports_windows_architecture?(new_node, supported_architecture)).to eq(false) if ! only_valid_combinations && (supported_architecture == :x86_64 && node_architecture == :i386 )
+      @valid_architectures.each do |architecture|
+        yield new_node, architecture if block_given?
       end
     end
   end
diff --git a/spec/unit/mixin/xml_escape_spec.rb b/spec/unit/mixin/xml_escape_spec.rb
index c5156cf..2723fce 100644
--- a/spec/unit/mixin/xml_escape_spec.rb
+++ b/spec/unit/mixin/xml_escape_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class XMLEscapingTestHarness
   include Chef::Mixin::XMLEscape
diff --git a/spec/unit/monkey_patches/uri_spec.rb b/spec/unit/monkey_patches/uri_spec.rb
index 9aca1fc..0679705 100644
--- a/spec/unit/monkey_patches/uri_spec.rb
+++ b/spec/unit/monkey_patches/uri_spec.rb
@@ -1,6 +1,6 @@
 #--
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 describe URI do
 
   describe "when a URI contains an IPv6 literal" do
diff --git a/spec/unit/monologger_spec.rb b/spec/unit/monologger_spec.rb
index 8689ea0..e7f2dfb 100644
--- a/spec/unit/monologger_spec.rb
+++ b/spec/unit/monologger_spec.rb
@@ -1,5 +1,5 @@
 #
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,9 +15,9 @@
 # limitations under the License.
 #
 
-require 'chef/monologger'
-require 'tempfile'
-require 'spec_helper'
+require "chef/monologger"
+require "tempfile"
+require "spec_helper"
 
 describe MonoLogger do
   it "should disable buffering when passed an IO stream" do
diff --git a/spec/unit/node/attribute_spec.rb b/spec/unit/node/attribute_spec.rb
index 250b8c6..c69748a 100644
--- a/spec/unit/node/attribute_spec.rb
+++ b/spec/unit/node/attribute_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,178 +17,134 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/node/attribute'
+require "spec_helper"
+require "chef/node/attribute"
 
 describe Chef::Node::Attribute do
   before(:each) do
     @attribute_hash =
-      {"dmi"=>{},
-        "command"=>{"ps"=>"ps -ef"},
-        "platform_version"=>"10.5.7",
-        "platform"=>"mac_os_x",
-        "ipaddress"=>"192.168.0.117",
-        "network"=>
-    {"default_interface"=>"en1",
-      "interfaces"=>
-    {"vmnet1"=>
-      {"flags"=>
-        ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-          "number"=>"1",
-          "addresses"=>
-        {"00:50:56:c0:00:01"=>{"family"=>"lladdr"},
-          "192.168.110.1"=>
-        {"broadcast"=>"192.168.110.255",
-          "netmask"=>"255.255.255.0",
-          "family"=>"inet"}},
-          "mtu"=>"1500",
-          "type"=>"vmnet",
-          "arp"=>{"192.168.110.255"=>"ff:ff:ff:ff:ff:ff"},
-          "encapsulation"=>"Ethernet"},
-          "stf0"=>
-        {"flags"=>[],
-          "number"=>"0",
-          "addresses"=>{},
-          "mtu"=>"1280",
-          "type"=>"stf",
-          "encapsulation"=>"6to4"},
-          "lo0"=>
-        {"flags"=>["UP", "LOOPBACK", "RUNNING", "MULTICAST"],
-          "number"=>"0",
-          "addresses"=>
-        {"::1"=>{"scope"=>"Node", "prefixlen"=>"128", "family"=>"inet6"},
-          "127.0.0.1"=>{"netmask"=>"255.0.0.0", "family"=>"inet"},
-          "fe80::1"=>{"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
-          "mtu"=>"16384",
-          "type"=>"lo",
-          "encapsulation"=>"Loopback"},
-          "gif0"=>
-        {"flags"=>["POINTOPOINT", "MULTICAST"],
-          "number"=>"0",
-          "addresses"=>{},
-          "mtu"=>"1280",
-          "type"=>"gif",
-          "encapsulation"=>"IPIP"},
-          "vmnet8"=>
-        {"flags"=>
-          ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-            "number"=>"8",
-            "addresses"=>
-          {"192.168.4.1"=>
-            {"broadcast"=>"192.168.4.255",
-              "netmask"=>"255.255.255.0",
-              "family"=>"inet"},
-              "00:50:56:c0:00:08"=>{"family"=>"lladdr"}},
-              "mtu"=>"1500",
-              "type"=>"vmnet",
-              "arp"=>{"192.168.4.255"=>"ff:ff:ff:ff:ff:ff"},
-              "encapsulation"=>"Ethernet"},
-              "en0"=>
-            {"status"=>"inactive",
-              "flags"=>
-            ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-              "number"=>"0",
-              "addresses"=>{"00:23:32:b0:32:f2"=>{"family"=>"lladdr"}},
-              "mtu"=>"1500",
-              "media"=>
-            {"supported"=>
-              {"autoselect"=>{"options"=>[]},
-                "none"=>{"options"=>[]},
-                "1000baseT"=>
-              {"options"=>["full-duplex", "flow-control", "hw-loopback"]},
-                "10baseT/UTP"=>
-              {"options"=>
-                ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]},
-                  "100baseTX"=>
-                {"options"=>
-                  ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]}},
-                    "selected"=>{"autoselect"=>{"options"=>[]}}},
-                    "type"=>"en",
-                    "encapsulation"=>"Ethernet"},
-                    "en1"=>
-                  {"status"=>"active",
-                    "flags"=>
-                  ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-                    "number"=>"1",
-                    "addresses"=>
-                  {"fe80::223:6cff:fe7f:676c"=>
-                    {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"},
-                      "00:23:6c:7f:67:6c"=>{"family"=>"lladdr"},
-                      "192.168.0.117"=>
-                    {"broadcast"=>"192.168.0.255",
-                      "netmask"=>"255.255.255.0",
-                      "family"=>"inet"}},
-                      "mtu"=>"1500",
-                      "media"=>
-                    {"supported"=>{"autoselect"=>{"options"=>[]}},
-                      "selected"=>{"autoselect"=>{"options"=>[]}}},
-                      "type"=>"en",
-                      "arp"=>
-                    {"192.168.0.72"=>"0:f:ea:39:fa:d5",
-                      "192.168.0.1"=>"0:1c:fb:fc:6f:20",
-                      "192.168.0.255"=>"ff:ff:ff:ff:ff:ff",
-                      "192.168.0.3"=>"0:1f:33:ea:26:9b",
-                      "192.168.0.77"=>"0:23:12:70:f8:cf",
-                      "192.168.0.152"=>"0:26:8:7d:2:4c"},
-                      "encapsulation"=>"Ethernet"},
-                      "en2"=>
-                    {"status"=>"active",
-                      "flags"=>
-                    ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-                      "number"=>"2",
-                      "addresses"=>
-                    {"169.254.206.152"=>
-                      {"broadcast"=>"169.254.255.255",
-                        "netmask"=>"255.255.0.0",
-                        "family"=>"inet"},
-                        "00:1c:42:00:00:01"=>{"family"=>"lladdr"},
-                        "fe80::21c:42ff:fe00:1"=>
-                      {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
-                        "mtu"=>"1500",
-                        "media"=>
-                      {"supported"=>{"autoselect"=>{"options"=>[]}},
-                        "selected"=>{"autoselect"=>{"options"=>[]}}},
-                        "type"=>"en",
-                        "encapsulation"=>"Ethernet"},
-                        "fw0"=>
-                      {"status"=>"inactive",
-                        "flags"=>["BROADCAST", "SIMPLEX", "MULTICAST"],
-                        "number"=>"0",
-                        "addresses"=>{"00:23:32:ff:fe:b0:32:f2"=>{"family"=>"lladdr"}},
-                        "mtu"=>"4078",
-                        "media"=>
-                      {"supported"=>{"autoselect"=>{"options"=>["full-duplex"]}},
-                        "selected"=>{"autoselect"=>{"options"=>["full-duplex"]}}},
-                        "type"=>"fw",
-                        "encapsulation"=>"1394"},
-                        "en3"=>
-                      {"status"=>"active",
-                        "flags"=>
-                      ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
-                        "number"=>"3",
-                        "addresses"=>
-                      {"169.254.206.152"=>
-                        {"broadcast"=>"169.254.255.255",
-                          "netmask"=>"255.255.0.0",
-                          "family"=>"inet"},
-                          "00:1c:42:00:00:00"=>{"family"=>"lladdr"},
-                          "fe80::21c:42ff:fe00:0"=>
-                        {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}},
-                          "mtu"=>"1500",
-                          "media"=>
-                        {"supported"=>{"autoselect"=>{"options"=>[]}},
-                          "selected"=>{"autoselect"=>{"options"=>[]}}},
-                          "type"=>"en",
-                          "encapsulation"=>"Ethernet"}}},
-                          "fqdn"=>"latte.local",
-                          "ohai_time"=>1249065590.90391,
-                          "domain"=>"local",
-                          "os"=>"darwin",
-                          "platform_build"=>"9J61",
-                          "os_version"=>"9.7.0",
-                          "hostname"=>"latte",
-                          "macaddress"=>"00:23:6c:7f:67:6c",
-                          "music" => { "jimmy_eat_world" => "nice", "apophis" => false }
+      { "dmi" => {},
+        "command" => { "ps" => "ps -ef" },
+        "platform_version" => "10.5.7",
+        "platform" => "mac_os_x",
+        "ipaddress" => "192.168.0.117",
+        "network" =>     { "default_interface" => "en1",
+                           "interfaces" =>     { "vmnet1" =>       { "flags" =>         ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                     "number" => "1",
+                                                                     "addresses" =>         { "00:50:56:c0:00:01" => { "family" => "lladdr" },
+                                                                                              "192.168.110.1" =>         { "broadcast" => "192.168.110.255",
+                                                                                                                           "netmask" => "255.255.255.0",
+                                                                                                                           "family" => "inet" } },
+                                                                     "mtu" => "1500",
+                                                                     "type" => "vmnet",
+                                                                     "arp" => { "192.168.110.255" => "ff:ff:ff:ff:ff:ff" },
+                                                                     "encapsulation" => "Ethernet" },
+                                                 "stf0" =>         { "flags" => [],
+                                                                     "number" => "0",
+                                                                     "addresses" => {},
+                                                                     "mtu" => "1280",
+                                                                     "type" => "stf",
+                                                                     "encapsulation" => "6to4" },
+                                                 "lo0" =>         { "flags" => ["UP", "LOOPBACK", "RUNNING", "MULTICAST"],
+                                                                    "number" => "0",
+                                                                    "addresses" =>         { "::1" => { "scope" => "Node", "prefixlen" => "128", "family" => "inet6" },
+                                                                                             "127.0.0.1" => { "netmask" => "255.0.0.0", "family" => "inet" },
+                                                                                             "fe80::1" => { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+                                                                    "mtu" => "16384",
+                                                                    "type" => "lo",
+                                                                    "encapsulation" => "Loopback" },
+                                                 "gif0" =>         { "flags" => ["POINTOPOINT", "MULTICAST"],
+                                                                     "number" => "0",
+                                                                     "addresses" => {},
+                                                                     "mtu" => "1280",
+                                                                     "type" => "gif",
+                                                                     "encapsulation" => "IPIP" },
+                                                 "vmnet8" =>         { "flags" =>           ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                       "number" => "8",
+                                                                       "addresses" =>           { "192.168.4.1" =>             { "broadcast" => "192.168.4.255",
+                                                                                                                                 "netmask" => "255.255.255.0",
+                                                                                                                                 "family" => "inet" },
+                                                                                                  "00:50:56:c0:00:08" => { "family" => "lladdr" } },
+                                                                       "mtu" => "1500",
+                                                                       "type" => "vmnet",
+                                                                       "arp" => { "192.168.4.255" => "ff:ff:ff:ff:ff:ff" },
+                                                                       "encapsulation" => "Ethernet" },
+                                                 "en0" =>             { "status" => "inactive",
+                                                                        "flags" =>             ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                        "number" => "0",
+                                                                        "addresses" => { "00:23:32:b0:32:f2" => { "family" => "lladdr" } },
+                                                                        "mtu" => "1500",
+                                                                        "media" =>             { "supported" =>               { "autoselect" => { "options" => [] },
+                                                                                                                                "none" => { "options" => [] },
+                                                                                                                                "1000baseT" =>               { "options" => ["full-duplex", "flow-control", "hw-loopback"] },
+                                                                                                                                "10baseT/UTP" =>               { "options" =>                 ["half-duplex", "full-duplex", "flow-control", "hw-loopback"] },
+                                                                                                                                "100baseTX" =>                 { "options" =>                   ["half-duplex", "full-duplex", "flow-control", "hw-loopback"] } },
+                                                                                                 "selected" => { "autoselect" => { "options" => [] } } },
+                                                                        "type" => "en",
+                                                                        "encapsulation" => "Ethernet" },
+                                                 "en1" =>                   { "status" => "active",
+                                                                              "flags" =>                   ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                              "number" => "1",
+                                                                              "addresses" =>                   { "fe80::223:6cff:fe7f:676c" =>                     { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" },
+                                                                                                                 "00:23:6c:7f:67:6c" => { "family" => "lladdr" },
+                                                                                                                 "192.168.0.117" =>                     { "broadcast" => "192.168.0.255",
+                                                                                                                                                          "netmask" => "255.255.255.0",
+                                                                                                                                                          "family" => "inet" } },
+                                                                              "mtu" => "1500",
+                                                                              "media" =>                     { "supported" => { "autoselect" => { "options" => [] } },
+                                                                                                               "selected" => { "autoselect" => { "options" => [] } } },
+                                                                              "type" => "en",
+                                                                              "arp" =>                     { "192.168.0.72" => "0:f:ea:39:fa:d5",
+                                                                                                             "192.168.0.1" => "0:1c:fb:fc:6f:20",
+                                                                                                             "192.168.0.255" => "ff:ff:ff:ff:ff:ff",
+                                                                                                             "192.168.0.3" => "0:1f:33:ea:26:9b",
+                                                                                                             "192.168.0.77" => "0:23:12:70:f8:cf",
+                                                                                                             "192.168.0.152" => "0:26:8:7d:2:4c" },
+                                                                              "encapsulation" => "Ethernet" },
+                                                 "en2" =>                     { "status" => "active",
+                                                                                "flags" =>                     ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                                "number" => "2",
+                                                                                "addresses" =>                     { "169.254.206.152" =>                       { "broadcast" => "169.254.255.255",
+                                                                                                                                                                  "netmask" => "255.255.0.0",
+                                                                                                                                                                  "family" => "inet" },
+                                                                                                                     "00:1c:42:00:00:01" => { "family" => "lladdr" },
+                                                                                                                     "fe80::21c:42ff:fe00:1" =>                       { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+                                                                                "mtu" => "1500",
+                                                                                "media" =>                       { "supported" => { "autoselect" => { "options" => [] } },
+                                                                                                                   "selected" => { "autoselect" => { "options" => [] } } },
+                                                                                "type" => "en",
+                                                                                "encapsulation" => "Ethernet" },
+                                                 "fw0" =>                       { "status" => "inactive",
+                                                                                  "flags" => ["BROADCAST", "SIMPLEX", "MULTICAST"],
+                                                                                  "number" => "0",
+                                                                                  "addresses" => { "00:23:32:ff:fe:b0:32:f2" => { "family" => "lladdr" } },
+                                                                                  "mtu" => "4078",
+                                                                                  "media" =>                       { "supported" => { "autoselect" => { "options" => ["full-duplex"] } },
+                                                                                                                     "selected" => { "autoselect" => { "options" => ["full-duplex"] } } },
+                                                                                  "type" => "fw",
+                                                                                  "encapsulation" => "1394" },
+                                                 "en3" =>                       { "status" => "active",
+                                                                                  "flags" =>                       ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"],
+                                                                                  "number" => "3",
+                                                                                  "addresses" =>                       { "169.254.206.152" =>                         { "broadcast" => "169.254.255.255",
+                                                                                                                                                                        "netmask" => "255.255.0.0",
+                                                                                                                                                                        "family" => "inet" },
+                                                                                                                         "00:1c:42:00:00:00" => { "family" => "lladdr" },
+                                                                                                                         "fe80::21c:42ff:fe00:0" =>                         { "scope" => "Link", "prefixlen" => "64", "family" => "inet6" } },
+                                                                                  "mtu" => "1500",
+                                                                                  "media" =>                         { "supported" => { "autoselect" => { "options" => [] } },
+                                                                                                                       "selected" => { "autoselect" => { "options" => [] } } },
+                                                                                  "type" => "en",
+                                                                                  "encapsulation" => "Ethernet" } } },
+        "fqdn" => "latte.local",
+        "ohai_time" => 1249065590.90391,
+        "domain" => "local",
+        "os" => "darwin",
+        "platform_build" => "9J61",
+        "os_version" => "9.7.0",
+        "hostname" => "latte",
+        "macaddress" => "00:23:6c:7f:67:6c",
+        "music" => { "jimmy_eat_world" => "nice", "apophis" => false },
     }
     @default_hash = {
       "domain" => "opscode.com",
@@ -198,8 +154,8 @@ describe Chef::Node::Attribute do
         "mastodon" => "rocks",
         "mars_volta" => "is loud and nutty",
         "deeper" => { "gates_of_ishtar" => nil },
-        "this" => {"apparatus" => {"must" => "be unearthed"}}
-      }
+        "this" => { "apparatus" => { "must" => "be unearthed" } },
+      },
     }
     @override_hash = {
       "macaddress" => "00:00:00:00:00:00",
@@ -207,9 +163,9 @@ describe Chef::Node::Attribute do
       "fire" => "still burn",
       "music" => {
         "mars_volta" => "cicatriz"
-      }
+      },
     }
-    @automatic_hash = {"week" => "friday"}
+    @automatic_hash = { "week" => "friday" }
     @attributes = Chef::Node::Attribute.new(@attribute_hash, @default_hash, @override_hash, @automatic_hash)
   end
 
@@ -272,7 +228,7 @@ describe Chef::Node::Attribute do
         ["role_override", "role_override"],
         ["env_override", "env_override"],
         ["force_override", "force_override"],
-        ["automatic", "automatic"]
+        ["automatic", "automatic"],
       ]
       expect(@attributes.debug_value(:foo, :bar)).to eq(expected)
     end
@@ -354,13 +310,13 @@ describe Chef::Node::Attribute do
 
     it "merges nested hashes between precedence levels" do
       @attributes = Chef::Node::Attribute.new({}, {}, {}, {})
-      @attributes.env_default = {"a" => {"b" => {"default" => "default"}}}
-      @attributes.normal = {"a" => {"b" => {"normal" => "normal"}}}
-      @attributes.override = {"a" => {"override" => "role"}}
-      @attributes.automatic = {"a" => {"automatic" => "auto"}}
-      expect(@attributes["a"]).to eq({"b"=>{"default"=>"default", "normal"=>"normal"},
-                                  "override"=>"role",
-                                  "automatic"=>"auto"})
+      @attributes.env_default = { "a" => { "b" => { "default" => "default" } } }
+      @attributes.normal = { "a" => { "b" => { "normal" => "normal" } } }
+      @attributes.override = { "a" => { "override" => "role" } }
+      @attributes.automatic = { "a" => { "automatic" => "auto" } }
+      expect(@attributes["a"]).to eq({ "b" => { "default" => "default", "normal" => "normal" },
+                                       "override" => "role",
+                                       "automatic" => "auto" })
     end
   end
 
@@ -431,7 +387,7 @@ describe Chef::Node::Attribute do
 
   describe "[]=" do
     it "should error out when the type of attribute to set has not been specified" do
-      @attributes.normal["the_ghost"] = {  }
+      @attributes.normal["the_ghost"] = {}
       expect { @attributes["the_ghost"]["exterminate"] = false }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
     end
 
@@ -488,37 +444,37 @@ describe Chef::Node::Attribute do
     end
 
     it "should create a deep copy of the node attribute" do
-      @attributes.default['foo']['bar']['baz'] = 'fizz'
-      hash = @attributes['foo'].to_hash
-      expect(hash).to eql({"bar"=>{"baz"=>"fizz"}})
-      hash['bar']['baz'] = 'buzz'
-      expect(hash).to eql({"bar"=>{"baz"=>"buzz"}})
-      expect(@attributes.default['foo']).to eql({"bar"=>{"baz"=>"fizz"}})
+      @attributes.default["foo"]["bar"]["baz"] = "fizz"
+      hash = @attributes["foo"].to_hash
+      expect(hash).to eql({ "bar" => { "baz" => "fizz" } })
+      hash["bar"]["baz"] = "buzz"
+      expect(hash).to eql({ "bar" => { "baz" => "buzz" } })
+      expect(@attributes.default["foo"]).to eql({ "bar" => { "baz" => "fizz" } })
     end
 
     it "should create a deep copy of arrays in the node attribute" do
-      @attributes.default['foo']['bar'] = ['fizz']
-      hash = @attributes['foo'].to_hash
-      expect(hash).to eql({"bar"=>[ 'fizz' ]})
-      hash['bar'].push('buzz')
-      expect(hash).to eql({"bar"=>[ 'fizz', 'buzz' ]})
-      expect(@attributes.default['foo']).to eql({"bar"=>[ 'fizz' ]})
+      @attributes.default["foo"]["bar"] = ["fizz"]
+      hash = @attributes["foo"].to_hash
+      expect(hash).to eql({ "bar" => [ "fizz" ] })
+      hash["bar"].push("buzz")
+      expect(hash).to eql({ "bar" => [ "fizz", "buzz" ] })
+      expect(@attributes.default["foo"]).to eql({ "bar" => [ "fizz" ] })
     end
 
     it "mutating strings should not mutate the attributes" do
       pending "this is a bug that should be fixed"
-      @attributes.default['foo']['bar']['baz'] = 'fizz'
-      hash = @attributes['foo'].to_hash
-      expect(hash).to eql({"bar"=>{"baz"=>"fizz"}})
-      hash['bar']['baz'] << 'buzz'
-      expect(hash).to eql({"bar"=>{"baz"=>"fizzbuzz"}})
-      expect(@attributes.default['foo']).to eql({"bar"=>{"baz"=>"fizz"}})
+      @attributes.default["foo"]["bar"]["baz"] = "fizz"
+      hash = @attributes["foo"].to_hash
+      expect(hash).to eql({ "bar" => { "baz" => "fizz" } })
+      hash["bar"]["baz"] << "buzz"
+      expect(hash).to eql({ "bar" => { "baz" => "fizzbuzz" } })
+      expect(@attributes.default["foo"]).to eql({ "bar" => { "baz" => "fizz" } })
     end
   end
 
   describe "dup" do
     it "array can be duped even if some elements can't" do
-      @attributes.default[:foo] = %w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ]
+      @attributes.default[:foo] = %w{foo bar baz} + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ]
       @attributes.default[:foo].dup
     end
   end
@@ -592,17 +548,17 @@ describe Chef::Node::Attribute do
         {
           "one" =>  { "two" => "three" },
           "hut" =>  { "two" => "three" },
-          "place" => { }
+          "place" => {},
         },
         {
           "one" =>  { "four" => "five" },
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" =>  { "six" => "seven" },
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -644,13 +600,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -682,13 +638,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -718,13 +674,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -754,13 +710,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -798,13 +754,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
       @empty = Chef::Node::Attribute.new({}, {}, {}, {})
     end
@@ -832,13 +788,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -852,8 +808,8 @@ describe Chef::Node::Attribute do
           "one" => "six",
           "hut" => "three",
           "snakes" => "on a plane",
-          "snack" => "cookies"
-        }.each do |k,v|
+          "snack" => "cookies",
+        }.each do |k, v|
           expect(@attributes.fetch(k)).to eq(v)
         end
       end
@@ -889,13 +845,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -934,13 +890,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -975,13 +931,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -1011,13 +967,13 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
     end
 
@@ -1031,7 +987,7 @@ describe Chef::Node::Attribute do
       end
     else
       it "should raise a LocalJumpError if no block is given" do
-        expect{ @attributes.select }.to raise_error(LocalJumpError)
+        expect { @attributes.select }.to raise_error(LocalJumpError)
       end
     end
 
@@ -1046,7 +1002,7 @@ describe Chef::Node::Attribute do
           ["hut", "three"],
           ["one", "six"],
           ["snack", "cookies"],
-          ["snakes", "on a plane"]
+          ["snakes", "on a plane"],
         ]
       )
     end
@@ -1061,16 +1017,16 @@ describe Chef::Node::Attribute do
         },
         {
           "one" =>  "four",
-          "snakes" => "on a plane"
+          "snakes" => "on a plane",
         },
         {
           "one" => "six",
-          "snack" => "cookies"
+          "snack" => "cookies",
         },
-        {}
+        {},
       )
 
-      @empty = Chef::Node::Attribute.new({},{},{},{})
+      @empty = Chef::Node::Attribute.new({}, {}, {}, {})
     end
 
     it "should respond to size" do
@@ -1117,11 +1073,11 @@ describe Chef::Node::Attribute do
     it "should output merged attributes" do
       default_hash = {
           "a" => 1,
-          "b" => 2
+          "b" => 2,
       }
       override_hash = {
           "b" => 3,
-          "c" => 4
+          "c" => 4,
       }
       attributes = Chef::Node::Attribute.new(nil, default_hash, override_hash, nil)
       expect(attributes.to_s).to eq('{"a"=>1, "b"=>3, "c"=>4}')
@@ -1138,7 +1094,6 @@ describe Chef::Node::Attribute do
     end
   end
 
-
   describe "when not mutated" do
 
     it "does not reset the cache when dup'd [CHEF-3680]" do
diff --git a/spec/unit/node/immutable_collections_spec.rb b/spec/unit/node/immutable_collections_spec.rb
index d0ec81c..170e6d9 100644
--- a/spec/unit/node/immutable_collections_spec.rb
+++ b/spec/unit/node/immutable_collections_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 require "chef/node/immutable_collections"
 
 describe Chef::Node::ImmutableMash do
   before do
-    @data_in = {:top => {:second_level => "some value"},
-                "top_level_2" => %w[array of values],
-                :top_level_3 => [{:hash_array => 1, :hash_array_b => 2}],
-                :top_level_4 => {:level2 => {:key => "value"}}
+    @data_in = { :top => { :second_level => "some value" },
+                 "top_level_2" => %w{array of values},
+                 :top_level_3 => [{ :hash_array => 1, :hash_array_b => 2 }],
+                 :top_level_4 => { :level2 => { :key => "value" } },
     }
     @immutable_mash = Chef::Node::ImmutableMash.new(@data_in)
   end
@@ -34,7 +34,7 @@ describe Chef::Node::ImmutableMash do
   end
 
   it "element references like a regular Mash" do
-    expect(@immutable_mash[:top_level_2]).to eq(%w[array of values])
+    expect(@immutable_mash[:top_level_2]).to eq(%w{array of values})
   end
 
   it "converts Hash-like inputs into ImmutableMash's" do
@@ -64,19 +64,19 @@ describe Chef::Node::ImmutableMash do
     end
 
     it "converts an immutable nested mash to a new mutable hash" do
-      expect(@copy['top_level_4']['level2']).to be_instance_of(Hash)
+      expect(@copy["top_level_4"]["level2"]).to be_instance_of(Hash)
     end
 
     it "converts an immutable nested array to a new mutable array" do
-      expect(@copy['top_level_2']).to be_instance_of(Array)
+      expect(@copy["top_level_2"]).to be_instance_of(Array)
     end
 
     it "should create a mash with the same content" do
       expect(@copy).to eq(@immutable_mash)
     end
 
-    it 'should allow mutation' do
-      expect { @copy['m'] = 'm' }.not_to raise_error
+    it "should allow mutation" do
+      expect { @copy["m"] = "m" }.not_to raise_error
     end
 
   end
@@ -94,7 +94,7 @@ describe Chef::Node::ImmutableMash do
     :reject!,
     :replace,
     :select!,
-    :shift
+    :shift,
   ].each do |mutator|
     it "doesn't allow mutation via `#{mutator}'" do
       expect { @immutable_mash.send(mutator) }.to raise_error
@@ -112,9 +112,9 @@ end
 describe Chef::Node::ImmutableArray do
 
   before do
-    @immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz] + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ])
-    immutable_mash = Chef::Node::ImmutableMash.new({:m => 'm'})
-    @immutable_nested_array = Chef::Node::ImmutableArray.new(["level1", at immutable_array, immutable_mash])
+    @immutable_array = Chef::Node::ImmutableArray.new(%w{foo bar baz} + Array(1..3) + [nil, true, false, [ "el", 0, nil ] ])
+    immutable_mash = Chef::Node::ImmutableMash.new({ :m => "m" })
+    @immutable_nested_array = Chef::Node::ImmutableArray.new(["level1", @immutable_array, immutable_mash])
   end
 
   ##
@@ -151,10 +151,10 @@ describe Chef::Node::ImmutableArray do
     :sort!,
     :sort_by!,
     :uniq!,
-    :unshift
+    :unshift,
   ].each do |mutator|
     it "does not allow mutation via `#{mutator}" do
-      expect { @immutable_array.send(mutator)}.to raise_error
+      expect { @immutable_array.send(mutator) }.to raise_error
     end
   end
 
@@ -189,10 +189,9 @@ describe Chef::Node::ImmutableArray do
       expect(@copy).to eq(@immutable_nested_array)
     end
 
-    it 'should allow mutation' do
-      expect { @copy << 'm' }.not_to raise_error
+    it "should allow mutation" do
+      expect { @copy << "m" }.not_to raise_error
     end
   end
 
 end
-
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index fe73729..0eb251a 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Lamont Granquist (<lamont at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/node_map'
+require "spec_helper"
+require "chef/node_map"
 
 describe Chef::NodeMap do
 
@@ -27,7 +27,7 @@ describe Chef::NodeMap do
 
   describe "with a bad filter name" do
     it "should raise an error" do
-      expect{ node_map.set(node, :thing, on_platform_family: 'rhel') }.to raise_error
+      expect { node_map.set(node, :thing, on_platform_family: "rhel") }.to raise_error
     end
   end
 
@@ -131,16 +131,32 @@ describe Chef::NodeMap do
       allow(node).to receive(:[]).with(:platform_version).and_return("6.0")
       expect(node_map.get(node, :thing)).to eql(nil)
     end
+
+    context "when there is a less specific definition" do
+      before do
+        node_map.set(:thing, :bar, platform_family: "rhel")
+      end
+
+      it "returns the value when the node matches" do
+        allow(node).to receive(:[]).with(:platform_family).and_return("rhel")
+        allow(node).to receive(:[]).with(:platform_version).and_return("7.0")
+        expect(node_map.get(node, :thing)).to eql(:foo)
+      end
+    end
   end
 
   describe "resource back-compat testing" do
+    before :each do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+    end
+
     it "should handle :on_platforms => :all" do
       node_map.set(:chef_gem, :foo, :on_platforms => :all)
       allow(node).to receive(:[]).with(:platform).and_return("windows")
       expect(node_map.get(node, :chef_gem)).to eql(:foo)
     end
     it "should handle :on_platforms => [ 'windows' ]" do
-      node_map.set(:dsc_script, :foo, :on_platforms => [ 'windows' ])
+      node_map.set(:dsc_script, :foo, :on_platforms => [ "windows" ])
       allow(node).to receive(:[]).with(:platform).and_return("windows")
       expect(node_map.get(node, :dsc_script)).to eql(:foo)
     end
@@ -152,4 +168,3 @@ describe Chef::NodeMap do
   end
 
 end
-
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 5939403..d3c58c6 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Node do
 
@@ -27,24 +27,32 @@ describe Chef::Node do
   it_behaves_like "a platform introspector"
 
   it "creates a node and assigns it a name" do
-    node = Chef::Node.build('solo-node')
-    expect(node.name).to eq('solo-node')
+    node = Chef::Node.build("solo-node")
+    expect(node.name).to eq("solo-node")
   end
 
   it "should validate the name of the node" do
-    expect{Chef::Node.build('solo node')}.to raise_error(Chef::Exceptions::ValidationFailed)
+    expect { Chef::Node.build("solo node") }.to raise_error(Chef::Exceptions::ValidationFailed)
   end
 
   it "should be sortable" do
-    n1 = Chef::Node.build('alpha')
-    n2 = Chef::Node.build('beta')
-    n3 = Chef::Node.build('omega')
+    n1 = Chef::Node.build("alpha")
+    n2 = Chef::Node.build("beta")
+    n3 = Chef::Node.build("omega")
     expect([n3, n1, n2].sort).to eq([n1, n2, n3])
   end
 
+  it "should share identity only with others of the same name" do
+    n1 = Chef::Node.build("foo")
+    n2 = Chef::Node.build("foo")
+    n3 = Chef::Node.build("bar")
+    expect(n1).to eq(n2)
+    expect(n1).not_to eq(n3)
+  end
+
   describe "when the node does not exist on the server" do
     before do
-      response = OpenStruct.new(:code => '404')
+      response = OpenStruct.new(:code => "404")
       exception = Net::HTTPServerException.new("404 not found", response)
       allow(Chef::Node).to receive(:load).and_raise(exception)
       node.name("created-node")
@@ -54,19 +62,19 @@ describe Chef::Node do
       allow(Chef::Node).to receive(:new).and_return(node)
       expect(node).to receive(:create).and_return(node)
       node = Chef::Node.find_or_create("created-node")
-      expect(node.name).to eq('created-node')
+      expect(node.name).to eq("created-node")
       expect(node).to equal(node)
     end
   end
 
   describe "when the node exists on the server" do
     before do
-      node.name('existing-node')
+      node.name("existing-node")
       allow(Chef::Node).to receive(:load).and_return(node)
     end
 
     it "loads the node via the REST API for find_or_create" do
-      expect(Chef::Node.find_or_create('existing-node')).to equal(node)
+      expect(Chef::Node.find_or_create("existing-node")).to equal(node)
     end
   end
 
@@ -80,7 +88,7 @@ describe Chef::Node do
   describe "initialize" do
     it "should default to the '_default' chef_environment" do
       n = Chef::Node.new
-      expect(n.chef_environment).to eq('_default')
+      expect(n.chef_environment).to eq("_default")
     end
   end
 
@@ -99,11 +107,11 @@ describe Chef::Node do
     end
 
     it "cannot be blank" do
-      expect { node.name("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+      expect { node.name("") }.to raise_error(Chef::Exceptions::ValidationFailed)
     end
 
     it "should not accept name doesn't match /^[\-[:alnum:]_:.]+$/" do
-      expect { node.name("space in it")}.to raise_error(Chef::Exceptions::ValidationFailed)
+      expect { node.name("space in it") }.to raise_error(Chef::Exceptions::ValidationFailed)
     end
   end
 
@@ -123,7 +131,79 @@ describe Chef::Node do
     end
 
     it "cannot be blank" do
-      expect { node.chef_environment("")}.to raise_error(Chef::Exceptions::ValidationFailed)
+      expect { node.chef_environment("") }.to raise_error(Chef::Exceptions::ValidationFailed)
+    end
+  end
+
+  describe "policy_name" do
+
+    it "defaults to nil" do
+      expect(node.policy_name).to be_nil
+    end
+
+    it "sets policy_name with a regular setter" do
+      node.policy_name = "example-policy"
+      expect(node.policy_name).to eq("example-policy")
+    end
+
+    it "allows policy_name with every valid character" do
+      expect { node.policy_name = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:." }.to_not raise_error
+    end
+
+    it "sets policy_name when given an argument" do
+      node.policy_name("example-policy")
+      expect(node.policy_name).to eq("example-policy")
+    end
+
+    it "sets policy_name to nil when given nil" do
+      node.policy_name = "example-policy"
+      node.policy_name = nil
+      expect(node.policy_name).to be_nil
+    end
+
+    it "disallows non-strings" do
+      expect { node.policy_name(Hash.new) }.to raise_error(Chef::Exceptions::ValidationFailed)
+      expect { node.policy_name(42) }.to raise_error(Chef::Exceptions::ValidationFailed)
+    end
+
+    it "cannot be blank" do
+      expect { node.policy_name("") }.to raise_error(Chef::Exceptions::ValidationFailed)
+    end
+  end
+
+  describe "policy_group" do
+
+    it "defaults to nil" do
+      expect(node.policy_group).to be_nil
+    end
+
+    it "sets policy_group with a regular setter" do
+      node.policy_group = "staging"
+      expect(node.policy_group).to eq("staging")
+    end
+
+    it "allows policy_group with every valid character" do
+      expect { node.policy_group = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqurstuvwxyz0123456789-_:." }.to_not raise_error
+    end
+
+    it "sets an environment with chef_environment(something)" do
+      node.policy_group("staging")
+      expect(node.policy_group).to eq("staging")
+    end
+
+    it "sets policy_group to nil when given nil" do
+      node.policy_group = "staging"
+      node.policy_group = nil
+      expect(node.policy_group).to be_nil
+    end
+
+    it "disallows non-strings" do
+      expect { node.policy_group(Hash.new) }.to raise_error(Chef::Exceptions::ValidationFailed)
+      expect { node.policy_group(42) }.to raise_error(Chef::Exceptions::ValidationFailed)
+    end
+
+    it "cannot be blank" do
+      expect { node.policy_group("") }.to raise_error(Chef::Exceptions::ValidationFailed)
     end
   end
 
@@ -143,7 +223,7 @@ describe Chef::Node do
     end
 
     it "does not allow you to set an attribute via node[]=" do
-      expect  { node["secret"] = "shush" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+      expect { node["secret"] = "shush" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
     end
 
     it "should allow you to query whether an attribute exists with attribute?" do
@@ -159,7 +239,7 @@ describe Chef::Node do
     end
 
     it "does not allow you to set an attribute via method_missing" do
-      expect { node.sunshine = "is bright"}.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
+      expect { node.sunshine = "is bright" }.to raise_error(Chef::Exceptions::ImmutableAttributeModification)
     end
 
     it "should allow you get get an attribute via method_missing" do
@@ -184,6 +264,12 @@ describe Chef::Node do
         expect(node[:snoopy][:is_a_puppy]).to eq(true)
       end
 
+      it "should allow you to set an attribute with set_unless if is a nil value" do
+        node.attributes.normal = { snoopy: { is_a_puppy: nil } }
+        node.set_unless[:snoopy][:is_a_puppy] = false
+        expect(node[:snoopy][:is_a_puppy]).to eq(false)
+      end
+
       it "should allow you to set a value after a set_unless" do
         # this tests for set_unless_present state bleeding between statements CHEF-3806
         node.set_unless[:snoopy][:is_a_puppy] = false
@@ -205,9 +291,9 @@ describe Chef::Node do
       end
 
       it "should let you use tag as a convience method for the tags attribute" do
-        node.normal['tags'] = ['one', 'two']
-        node.tag('three', 'four')
-        expect(node['tags']).to eq(['one', 'two', 'three', 'four'])
+        node.normal["tags"] = ["one", "two"]
+        node.tag("three", "four")
+        expect(node["tags"]).to eq(["one", "two", "three", "four"])
       end
     end
 
@@ -303,7 +389,7 @@ describe Chef::Node do
 
         it "deletes nested things correctly" do
           node.default["mysql"]["client"]["client_setting"] = "foo"
-          expect( node.rm("mysql", "server") ).to eql( {"port" => 3456} )
+          expect( node.rm("mysql", "server") ).to eql( { "port" => 3456 } )
           expect( node["mysql"] ).to eql( { "client" => { "client_setting" => "foo" } } )
         end
 
@@ -312,7 +398,7 @@ describe Chef::Node do
         end
 
         it "can delete the entire tree" do
-          expect( node.rm("mysql") ).to eql({"server"=>{"port"=>3456}})
+          expect( node.rm("mysql") ).to eql({ "server" => { "port" => 3456 } })
         end
       end
 
@@ -352,13 +438,13 @@ describe Chef::Node do
       context "with real arrays" do
         before do
           node.role_default["mysql"]["server"] = [ {
-            "port" => 1234,
+            "port" => 1234
           } ]
           node.normal["mysql"]["server"] = [ {
-            "port" => 2345,
+            "port" => 2345
           } ]
           node.override["mysql"]["server"] = [ {
-            "port" => 3456,
+            "port" => 3456
           } ]
         end
 
@@ -524,12 +610,12 @@ describe Chef::Node do
         node.force_default["mysql"]["server"]["port"] = 2345
 
         node.force_default!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
 
         expect( node["mysql"]["server"] ).to eql({
-          "data_dir" => "/my_raid_volume/lib/mysql",
-        })
+          "data_dir" => "/my_raid_volume/lib/mysql"
+        },)
       end
 
       it "removes all values from the precedence level when setting" do
@@ -538,14 +624,14 @@ describe Chef::Node do
         node.force_default["mysql"]["server"]["port"] = 3456
 
         node.force_default!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
 
         expect( node["mysql"]["server"]["port"] ).to be_nil
         expect( node["mysql"]["server"]["data_dir"] ).to eql("/my_raid_volume/lib/mysql")
         expect( node["mysql"]["server"] ).to eql({
-          "data_dir" => "/my_raid_volume/lib/mysql",
-        })
+          "data_dir" => "/my_raid_volume/lib/mysql"
+        },)
       end
 
       it "higher precedence levels are not removed" do
@@ -555,7 +641,7 @@ describe Chef::Node do
         node.override["mysql"]["server"]["service_name"] = "fancypants-sql"
 
         node.force_default!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
 
         expect( node["mysql"]["server"]["port"] ).to be_nil
@@ -563,12 +649,12 @@ describe Chef::Node do
         expect( node["mysql"]["server"] ).to eql({
           "service_name" => "fancypants-sql",
           "data_dir" => "/my_raid_volume/lib/mysql",
-        })
+        },)
       end
 
       it "will autovivify" do
         node.force_default!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
         expect( node["mysql"]["server"]["data_dir"] ).to eql("/my_raid_volume/lib/mysql")
       end
@@ -580,7 +666,7 @@ describe Chef::Node do
         node.default["mysql"]["server"]["service_name"] = "fancypants-sql"
 
         node.force_override!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
 
         expect( node["mysql"]["server"]["port"] ).to be_nil
@@ -588,14 +674,14 @@ describe Chef::Node do
         expect( node["mysql"]["server"] ).to eql({
           "service_name" => "fancypants-sql",
           "data_dir" => "/my_raid_volume/lib/mysql",
-        })
+        },)
       end
 
       it "when overwriting a non-hash/array" do
         node.override["mysql"] = false
         node.force_override["mysql"] = true
         node.force_override!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
         expect( node["mysql"]["server"]["data_dir"] ).to eql("/my_raid_volume/lib/mysql")
       end
@@ -603,11 +689,11 @@ describe Chef::Node do
       it "when overwriting an array with a hash" do
         node.force_override["mysql"][0] = true
         node.force_override!["mysql"]["server"] = {
-          "data_dir" => "/my_raid_volume/lib/mysql",
+          "data_dir" => "/my_raid_volume/lib/mysql"
         }
         expect( node["mysql"]["server"] ).to eql({
-          "data_dir" => "/my_raid_volume/lib/mysql",
-        })
+          "data_dir" => "/my_raid_volume/lib/mysql"
+        },)
       end
     end
 
@@ -620,25 +706,25 @@ describe Chef::Node do
     #
     describe "deep merge attribute cache edge conditions" do
       it "does not error with complicated attribute substitution" do
-        node.default['chef_attribute_hell']['attr1'] = "attribute1"
-        node.default['chef_attribute_hell']['attr2'] = "#{node.chef_attribute_hell.attr1}/attr2"
-        expect { node.default['chef_attribute_hell']['attr3'] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error
+        node.default["chef_attribute_hell"]["attr1"] = "attribute1"
+        node.default["chef_attribute_hell"]["attr2"] = "#{node.chef_attribute_hell.attr1}/attr2"
+        expect { node.default["chef_attribute_hell"]["attr3"] = "#{node.chef_attribute_hell.attr2}/attr3" }.not_to raise_error
       end
 
       it "caches both strings and symbols correctly" do
-        node.force_default[:solr][:version] = '4.10.2'
+        node.force_default[:solr][:version] = "4.10.2"
         node.force_default[:solr][:data_dir] = "/opt/solr-#{node['solr'][:version]}/example/solr"
         node.force_default[:solr][:xms] = "512M"
         expect(node[:solr][:xms]).to eql("512M")
-        expect(node['solr'][:xms]).to eql("512M")
+        expect(node["solr"][:xms]).to eql("512M")
       end
 
       it "method interpolation syntax also works" do
-        node.default['passenger']['version']     = '4.0.57'
-        node.default['passenger']['root_path']   = "passenger-#{node['passenger']['version']}"
-        node.default['passenger']['root_path_2'] = "passenger-#{node.passenger['version']}"
-        expect(node['passenger']['root_path_2']).to eql("passenger-4.0.57")
-        expect(node[:passenger]['root_path_2']).to eql("passenger-4.0.57")
+        node.default["passenger"]["version"]     = "4.0.57"
+        node.default["passenger"]["root_path"]   = "passenger-#{node['passenger']['version']}"
+        node.default["passenger"]["root_path_2"] = "passenger-#{node.passenger['version']}"
+        expect(node["passenger"]["root_path_2"]).to eql("passenger-4.0.57")
+        expect(node[:passenger]["root_path_2"]).to eql("passenger-4.0.57")
       end
     end
 
@@ -650,7 +736,7 @@ describe Chef::Node do
       node.default.sunshine = "is bright"
       node.default.canada = "is a nice place"
       seen_attributes = Hash.new
-      node.each_attribute do |a,v|
+      node.each_attribute do |a, v|
         seen_attributes[a] = v
       end
       expect(seen_attributes).to have_key("sunshine")
@@ -663,15 +749,22 @@ describe Chef::Node do
   describe "consuming json" do
 
     before do
-      @ohai_data = {:platform => 'foo', :platform_version => 'bar'}
+      @ohai_data = { :platform => "foo", :platform_version => "bar" }
     end
 
     it "consumes the run list portion of a collection of attributes and returns the remainder" do
-      attrs = {"run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar"}
-      expect(node.consume_run_list(attrs)).to eq({"foo" => "bar"})
+      attrs = { "run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar" }
+      expect(node.consume_run_list(attrs)).to eq({ "foo" => "bar" })
       expect(node.run_list).to eq([ "role[base]", "recipe[chef::server]" ])
     end
 
+    it "sets the node chef_environment" do
+      attrs = { "chef_environment" => "foo_environment", "bar" => "baz" }
+      expect(node.consume_chef_environment(attrs)).to eq({ "bar" => "baz" })
+      expect(node.chef_environment).to eq("foo_environment")
+      expect(node["chef_environment"]).to be nil
+    end
+
     it "should overwrites the run list with the run list it consumes" do
       node.consume_run_list "recipes" => [ "one", "two" ]
       node.consume_run_list "recipes" => [ "three" ]
@@ -681,7 +774,7 @@ describe Chef::Node do
     it "should not add duplicate recipes from the json attributes" do
       node.run_list << "one"
       node.consume_run_list "recipes" => [ "one", "two", "three" ]
-      expect(node.run_list).to  eq([ "one", "two", "three" ])
+      expect(node.run_list).to eq([ "one", "two", "three" ])
     end
 
     it "doesn't change the run list if no run_list is specified in the json" do
@@ -695,7 +788,7 @@ describe Chef::Node do
     end
 
     it "should add json attributes to the node" do
-      node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"})
+      node.consume_external_attrs(@ohai_data, { "one" => "two", "three" => "four" })
       expect(node.one).to eql("two")
       expect(node.three).to eql("four")
     end
@@ -706,50 +799,68 @@ describe Chef::Node do
     end
 
     it "should not set the tags attribute to an empty array if it is already defined" do
-      node.normal[:tags] = [ "radiohead" ]
+      node.tag("radiohead")
       node.consume_external_attrs(@ohai_data, {})
       expect(node.tags).to eql([ "radiohead" ])
     end
 
+    it "should set the tags attribute to an empty array if it is nil" do
+      node.attributes.normal = { "tags" => nil }
+      node.consume_external_attrs(@ohai_data, {})
+      expect(node.tags).to eql([])
+    end
+
+    it "should return an array if it is fed a string" do
+      node.normal[:tags] = "string"
+      node.consume_external_attrs(@ohai_data, {})
+      expect(node.tags).to eql(["string"])
+    end
+
+    it "should return an array if it is fed a hash" do
+      node.normal[:tags] = {}
+      node.consume_external_attrs(@ohai_data, {})
+      expect(node.tags).to eql([])
+    end
+
     it "deep merges attributes instead of overwriting them" do
-      node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
-      expect(node.one.to_hash).to eq({"two" => {"three" => "four"}})
-      node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"})
-      node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}})
-      expect(node.one.to_hash).to eq({"two" => {"three" => "four", "foo" => "bar"}, "abc" => "123"})
+      node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
+      expect(node.one.to_hash).to eq({ "two" => { "three" => "four" } })
+      node.consume_external_attrs(@ohai_data, "one" => { "abc" => "123" })
+      node.consume_external_attrs(@ohai_data, "one" => { "two" => { "foo" => "bar" } })
+      expect(node.one.to_hash).to eq({ "two" => { "three" => "four", "foo" => "bar" }, "abc" => "123" })
     end
 
     it "gives attributes from JSON priority when deep merging" do
-      node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}})
-      expect(node.one.to_hash).to eq({"two" => {"three" => "four"}})
-      node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}})
-      expect(node.one.to_hash).to eq({"two" => {"three" => "forty-two"}})
+      node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "four" } })
+      expect(node.one.to_hash).to eq({ "two" => { "three" => "four" } })
+      node.consume_external_attrs(@ohai_data, "one" => { "two" => { "three" => "forty-two" } })
+      expect(node.one.to_hash).to eq({ "two" => { "three" => "forty-two" } })
     end
 
   end
 
   describe "preparing for a chef client run" do
     before do
-      @ohai_data = {:platform => 'foobuntu', :platform_version => '23.42'}
+      @ohai_data = { :platform => "foobuntu", :platform_version => "23.42" }
     end
 
     it "sets its platform according to platform detection" do
       node.consume_external_attrs(@ohai_data, {})
-      expect(node.automatic_attrs[:platform]).to eq('foobuntu')
-      expect(node.automatic_attrs[:platform_version]).to eq('23.42')
+      expect(node.automatic_attrs[:platform]).to eq("foobuntu")
+      expect(node.automatic_attrs[:platform_version]).to eq("23.42")
     end
 
     it "consumes the run list from provided json attributes" do
-      node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']})
-      expect(node.run_list).to eq(['recipe[unicorn]'])
+      node.consume_external_attrs(@ohai_data, { "run_list" => ["recipe[unicorn]"] })
+      expect(node.run_list).to eq(["recipe[unicorn]"])
     end
 
     it "saves non-runlist json attrs for later" do
-      expansion = Chef::RunList::RunListExpansion.new('_default', [])
+      expansion = Chef::RunList::RunListExpansion.new("_default", [])
       allow(node.run_list).to receive(:expand).and_return(expansion)
-      node.consume_external_attrs(@ohai_data, {"foo" => "bar"})
+      node.consume_external_attrs(@ohai_data, { "foo" => "bar" })
       node.expand!
-      expect(node.normal_attrs).to eq({"foo" => "bar", "tags" => []})
+      expect(node.normal_attrs).to eq({ "foo" => "bar", "tags" => [] })
     end
 
   end
@@ -757,7 +868,7 @@ describe Chef::Node do
   describe "when expanding its run list and merging attributes" do
     before do
       @environment = Chef::Environment.new.tap do |e|
-        e.name('rspec_env')
+        e.name("rspec_env")
         e.default_attributes("env default key" => "env default value")
         e.override_attributes("env override key" => "env override value")
       end
@@ -768,15 +879,15 @@ describe Chef::Node do
     end
 
     it "sets the 'recipes' automatic attribute to the recipes in the expanded run_list" do
-      @expansion.recipes << 'recipe[chef::client]' << 'recipe[nginx::default]'
+      @expansion.recipes << "recipe[chef::client]" << "recipe[nginx::default]"
       node.expand!
-      expect(node.automatic_attrs[:recipes]).to eq(['recipe[chef::client]', 'recipe[nginx::default]'])
+      expect(node.automatic_attrs[:recipes]).to eq(["recipe[chef::client]", "recipe[nginx::default]"])
     end
 
     it "sets the 'roles' automatic attribute to the expanded role list" do
-      @expansion.instance_variable_set(:@applied_roles, {'arf' => nil, 'countersnark' => nil})
+      @expansion.instance_variable_set(:@applied_roles, { "arf" => nil, "countersnark" => nil })
       node.expand!
-      expect(node.automatic_attrs[:roles].sort).to eq(['arf', 'countersnark'])
+      expect(node.automatic_attrs[:roles].sort).to eq(["arf", "countersnark"])
     end
 
     it "applies default attributes from the environment as environment defaults" do
@@ -874,12 +985,12 @@ describe Chef::Node do
     before do
       node.chef_environment = "rspec"
       @expansion = Chef::RunList::RunListExpansion.new("rspec", [])
-      @expansion.default_attrs.replace({:default => "from role", :d_role => "role only"})
-      @expansion.override_attrs.replace({:override => "from role", :o_role => "role only"})
+      @expansion.default_attrs.replace({ :default => "from role", :d_role => "role only" })
+      @expansion.override_attrs.replace({ :override => "from role", :o_role => "role only" })
 
       @environment = Chef::Environment.new
-      @environment.default_attributes = {:default => "from env", :d_env => "env only" }
-      @environment.override_attributes = {:override => "from env", :o_env => "env only"}
+      @environment.default_attributes = { :default => "from env", :d_env => "env only" }
+      @environment.override_attributes = { :override => "from env", :o_env => "env only" }
       allow(Chef::Environment).to receive(:load).and_return(@environment)
       node.apply_expansion_attributes(@expansion)
     end
@@ -1041,7 +1152,7 @@ describe Chef::Node do
       expect(h["chef_environment"]).to eq("dev")
     end
 
-    it 'should return an empty array for empty run_list' do
+    it "should return an empty array for empty run_list" do
       expect(node.to_hash["run_list"]).to eq([])
     end
   end
@@ -1059,11 +1170,11 @@ describe Chef::Node do
       expect(json).to match(/run_list/)
     end
 
-    it 'should serialize valid json with a run list', :json => true do
+    it "should serialize valid json with a run list", :json => true do
       #This test came about because activesupport mucks with Chef json serialization
       #Test should pass with and without Activesupport
-      node.run_list << {"type" => "role", "name" => 'Cthulu'}
-      node.run_list << {"type" => "role", "name" => 'Hastur'}
+      node.run_list << { "type" => "role", "name" => "Cthulu" }
+      node.run_list << { "type" => "role", "name" => "Hastur" }
       json = Chef::JSONCompat.to_json(node)
       expect(json).to match(/\"run_list\":\[\"role\[Cthulu\]\",\"role\[Hastur\]\"\]/)
     end
@@ -1096,17 +1207,54 @@ describe Chef::Node do
     it "should deserialize itself from json", :json => true do
       node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
       json = Chef::JSONCompat.to_json(node)
-      serialized_node = Chef::JSONCompat.from_json(json)
+      serialized_node = Chef::Node.from_hash(Chef::JSONCompat.parse(json))
       expect(serialized_node).to be_a_kind_of(Chef::Node)
       expect(serialized_node.name).to eql(node.name)
       expect(serialized_node.chef_environment).to eql(node.chef_environment)
-      node.each_attribute do |k,v|
+      node.each_attribute do |k, v|
         expect(serialized_node[k]).to eql(v)
       end
       expect(serialized_node.run_list).to eq(node.run_list)
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    context "when policyfile attributes are not present" do
+
+      it "does not have a policy_name key in the json" do
+        expect(node.for_json.keys).to_not include("policy_name")
+      end
+
+      it "does not have a policy_group key in the json" do
+        expect(node.for_json.keys).to_not include("policy_name")
+      end
+    end
+
+    context "when policyfile attributes are present" do
+
+      before do
+        node.policy_name = "my-application"
+        node.policy_group = "staging"
+      end
+
+      it "includes policy_name key in the json" do
+        expect(node.for_json).to have_key("policy_name")
+        expect(node.for_json["policy_name"]).to eq("my-application")
+      end
+
+      it "includes a policy_group key in the json" do
+        expect(node.for_json).to have_key("policy_group")
+        expect(node.for_json["policy_group"]).to eq("staging")
+      end
+
+      it "parses policyfile attributes from JSON" do
+        round_tripped_node = Chef::Node.from_hash(node.for_json)
+
+        expect(round_tripped_node.policy_name).to eq("my-application")
+        expect(round_tripped_node.policy_group).to eq("staging")
+      end
+
+    end
+
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) {
         node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
         node
@@ -1123,8 +1271,8 @@ describe Chef::Node do
 
   describe "api model" do
     before(:each) do
-      @rest = double("Chef::REST")
-      allow(Chef::REST).to receive(:new).and_return(@rest)
+      @rest = double("Chef::ServerAPI")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
       @query = double("Chef::Search::Query")
       allow(Chef::Search::Query).to receive(:new).and_return(@query)
     end
@@ -1133,6 +1281,7 @@ describe Chef::Node do
       describe "inflated" do
         it "should return a hash of node names and objects" do
           n1 = double("Chef::Node", :name => "one")
+          allow(n1).to receive(:kind_of?).with(Chef::Node) { true }
           expect(@query).to receive(:search).with(:node).and_yield(n1)
           r = Chef::Node.list(true)
           expect(r["one"]).to eq(n1)
@@ -1140,7 +1289,7 @@ describe Chef::Node do
       end
 
       it "should return a hash of node names and urls" do
-        expect(@rest).to receive(:get_rest).and_return({ "one" => "http://foo" })
+        expect(@rest).to receive(:get).and_return({ "one" => "http://foo" })
         r = Chef::Node.list
         expect(r["one"]).to eq("http://foo")
       end
@@ -1148,14 +1297,19 @@ describe Chef::Node do
 
     describe "load" do
       it "should load a node by name" do
-        expect(@rest).to receive(:get_rest).with("nodes/monkey").and_return("foo")
-        expect(Chef::Node.load("monkey")).to eq("foo")
+        node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA))
+        json = Chef::JSONCompat.to_json(node)
+        parsed = Chef::JSONCompat.parse(json)
+        expect(@rest).to receive(:get).with("nodes/test.example.com").and_return(parsed)
+        serialized_node = Chef::Node.load("test.example.com")
+        expect(serialized_node).to be_a_kind_of(Chef::Node)
+        expect(serialized_node.name).to eql(node.name)
       end
     end
 
     describe "destroy" do
       it "should destroy a node" do
-        expect(@rest).to receive(:delete_rest).with("nodes/monkey").and_return("foo")
+        expect(@rest).to receive(:delete).with("nodes/monkey").and_return("foo")
         node.name("monkey")
         node.destroy
       end
@@ -1165,15 +1319,15 @@ describe Chef::Node do
       it "should update a node if it already exists" do
         node.name("monkey")
         allow(node).to receive(:data_for_save).and_return({})
-        expect(@rest).to receive(:put_rest).with("nodes/monkey", {}).and_return("foo")
+        expect(@rest).to receive(:put).with("nodes/monkey", {}).and_return("foo")
         node.save
       end
 
       it "should not try and create if it can update" do
         node.name("monkey")
         allow(node).to receive(:data_for_save).and_return({})
-        expect(@rest).to receive(:put_rest).with("nodes/monkey", {}).and_return("foo")
-        expect(@rest).not_to receive(:post_rest)
+        expect(@rest).to receive(:put).with("nodes/monkey", {}).and_return("foo")
+        expect(@rest).not_to receive(:post)
         node.save
       end
 
@@ -1181,8 +1335,8 @@ describe Chef::Node do
         node.name("monkey")
         allow(node).to receive(:data_for_save).and_return({})
         exception = double("404 error", :code => "404")
-        expect(@rest).to receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception))
-        expect(@rest).to receive(:post_rest).with("nodes", {})
+        expect(@rest).to receive(:put).and_raise(Net::HTTPServerException.new("foo", exception))
+        expect(@rest).to receive(:post).with("nodes", {})
         node.save
       end
 
@@ -1195,8 +1349,8 @@ describe Chef::Node do
         end
         it "should not save" do
           node.name("monkey")
-          expect(@rest).not_to receive(:put_rest)
-          expect(@rest).not_to receive(:post_rest)
+          expect(@rest).not_to receive(:put)
+          expect(@rest).not_to receive(:post)
           node.save
         end
       end
@@ -1205,21 +1359,21 @@ describe Chef::Node do
         it "should only save whitelisted attributes (and subattributes)" do
           Chef::Config[:automatic_attribute_whitelist] = [
             ["filesystem", "/dev/disk0s2"],
-            "network/interfaces/eth0"
+            "network/interfaces/eth0",
           ]
 
           data = {
             "automatic" => {
               "filesystem" => {
                 "/dev/disk0s2"   => { "size" => "10mb" },
-                "map - autohome" => { "size" => "10mb" }
+                "map - autohome" => { "size" => "10mb" },
               },
               "network" => {
                 "interfaces" => {
                   "eth0" => {},
-                  "eth1" => {}
+                  "eth1" => {},
                 }
-              }
+              },
             },
             "default" => {}, "normal" => {}, "override" => {}
           }
@@ -1233,14 +1387,14 @@ describe Chef::Node do
                 "interfaces" => {
                   "eth0" => {}
                 }
-              }
+              },
             },
             "default" => {}, "normal" => {}, "override" => {}
           }
 
           node.name("picky-monkey")
           allow(node).to receive(:for_json).and_return(data)
-          expect(@rest).to receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo")
+          expect(@rest).to receive(:put).with("nodes/picky-monkey", selected_data).and_return("foo")
           node.save
         end
 
@@ -1253,11 +1407,11 @@ describe Chef::Node do
             "default" => {
               "foo" => {
                 "bar" => {
-                  "baz" => false,
+                  "baz" => false
                 },
                 "other" => {
-                  "stuff" => true,
-                }
+                  "stuff" => true
+                },
               }
             }
           }
@@ -1266,7 +1420,7 @@ describe Chef::Node do
             "default" => {
               "foo" => {
                 "bar" => {
-                  "baz" => false,
+                  "baz" => false
                 }
               }
             }
@@ -1274,7 +1428,7 @@ describe Chef::Node do
 
           node.name("falsey-monkey")
           allow(node).to receive(:for_json).and_return(data)
-          expect(@rest).to receive(:put_rest).with("nodes/falsey-monkey", selected_data).and_return("foo")
+          expect(@rest).to receive(:put).with("nodes/falsey-monkey", selected_data).and_return("foo")
           node.save
         end
 
@@ -1285,7 +1439,7 @@ describe Chef::Node do
             "automatic" => {
               "filesystem" => {
                 "/dev/disk0s2"   => { "size" => "10mb" },
-                "map - autohome" => { "size" => "10mb" }
+                "map - autohome" => { "size" => "10mb" },
               }
             },
             "default" => {}, "normal" => {}, "override" => {}
@@ -1297,10 +1451,114 @@ describe Chef::Node do
 
           node.name("picky-monkey")
           allow(node).to receive(:for_json).and_return(data)
-          expect(@rest).to receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo")
+          expect(@rest).to receive(:put).with("nodes/picky-monkey", selected_data).and_return("foo")
           node.save
         end
       end
+
+      context "when policyfile attributes are present" do
+
+        before do
+          node.name("example-node")
+          node.policy_name = "my-application"
+          node.policy_group = "staging"
+        end
+
+        context "and the server supports policyfile attributes in node JSON" do
+
+          it "creates the object normally" do
+            expect(@rest).to receive(:post).with("nodes", node.for_json)
+            node.create
+          end
+
+          it "saves the node object normally" do
+            expect(@rest).to receive(:put).with("nodes/example-node", node.for_json)
+            node.save
+          end
+        end
+
+        # Chef Server before 12.3
+        context "and the Chef Server does not support policyfile attributes in node JSON" do
+
+          let(:response_body) { %q[{"error":["Invalid key policy_name in request body"]}] }
+
+          let(:response) do
+            Net::HTTPResponse.send(:response_class, "400").new("1.0", "400", "Bad Request").tap do |r|
+              allow(r).to receive(:body).and_return(response_body)
+            end
+          end
+
+          let(:http_exception) do
+            begin
+              response.error!
+            rescue => e
+              e
+            end
+          end
+
+          let(:trimmed_node) do
+            node.for_json.tap do |j|
+              j.delete("policy_name")
+              j.delete("policy_group")
+            end
+
+          end
+
+          context "on Chef Client 13 and later" do
+
+            # Though we normally attempt to provide compatibility with chef
+            # server one major version back, policyfiles were beta when we
+            # added the policyfile attributes to the node JSON, therefore
+            # policyfile users need to be on 12.3 minimum when upgrading Chef
+            # Client to 13+
+            it "lets the 400 pass through", :chef_gte_13_only do
+              expect { node.save }.to raise_error(http_exception)
+            end
+
+          end
+
+          context "when the node exists" do
+
+            it "falls back to saving without policyfile attributes" do
+              expect(@rest).to receive(:put).with("nodes/example-node", node.for_json).and_raise(http_exception)
+              expect(@rest).to receive(:put).with("nodes/example-node", trimmed_node).and_return(@node)
+              expect { node.save }.to_not raise_error
+            end
+
+          end
+
+          context "when the node doesn't exist" do
+
+            let(:response_404) do
+              Net::HTTPResponse.send(:response_class, "404").new("1.0", "404", "Not Found")
+            end
+
+            let(:http_exception_404) do
+              begin
+                response_404.error!
+              rescue => e
+                e
+              end
+            end
+
+            it "falls back to saving without policyfile attributes" do
+              expect(@rest).to receive(:put).with("nodes/example-node", node.for_json).and_raise(http_exception)
+              expect(@rest).to receive(:put).with("nodes/example-node", trimmed_node).and_raise(http_exception_404)
+              expect(@rest).to receive(:post).with("nodes", trimmed_node).and_return(@node)
+              node.save
+            end
+
+            it "creates the node without policyfile attributes" do
+              expect(@rest).to receive(:post).with("nodes", node.for_json).and_raise(http_exception)
+              expect(@rest).to receive(:post).with("nodes", trimmed_node).and_return(@node)
+              node.create
+            end
+          end
+
+        end
+
+      end
+
     end
   end
 
diff --git a/spec/unit/org_spec.rb b/spec/unit/org_spec.rb
index cd6cc94..4955741 100644
--- a/spec/unit/org_spec.rb
+++ b/spec/unit/org_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (steve at opscode.com)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/org'
-require 'tempfile'
+require "chef/org"
+require "tempfile"
 
 describe Chef::Org do
   let(:org) { Chef::Org.new("an_org") }
@@ -110,8 +110,8 @@ describe Chef::Org do
   describe "when deserializing from JSON" do
     let(:org) do
       o = { "name" => "turtle",
-        "full_name" => "turtle_club",
-        "private_key" => "pandas" }
+            "full_name" => "turtle_club",
+            "private_key" => "pandas" }
       Chef::Org.from_json(o.to_json)
     end
 
@@ -135,8 +135,8 @@ describe Chef::Org do
   describe "API Interactions" do
     let(:rest) do
       Chef::Config[:chef_server_root] = "http://www.example.com"
-      r = double('rest')
-      allow(Chef::REST).to receive(:new).and_return(r)
+      r = double("rest")
+      allow(Chef::ServerAPI).to receive(:new).and_return(r)
       r
     end
 
@@ -147,31 +147,31 @@ describe Chef::Org do
     end
 
     describe "list" do
-      let(:response) { {"foobar" => "http://www.example.com/organizations/foobar"} }
-      let(:inflated_response) { {"foobar" => org } }
+      let(:response) { { "foobar" => "http://www.example.com/organizations/foobar" } }
+      let(:inflated_response) { { "foobar" => org } }
 
       it "lists all orgs" do
-        expect(rest).to receive(:get_rest).with("organizations").and_return(response)
+        expect(rest).to receive(:get).with("organizations").and_return(response)
         expect(Chef::Org.list).to eq(response)
       end
 
       it "inflate all orgs" do
         allow(Chef::Org).to receive(:load).with("foobar").and_return(org)
-        expect(rest).to receive(:get_rest).with("organizations").and_return(response)
+        expect(rest).to receive(:get).with("organizations").and_return(response)
         expect(Chef::Org.list(true)).to eq(inflated_response)
       end
     end
 
     describe "create" do
       it "creates a new org via the API" do
-        expect(rest).to receive(:post_rest).with("organizations", {:name => "foobar", :full_name => "foo bar bat"}).and_return({})
+        expect(rest).to receive(:post).with("organizations", { :name => "foobar", :full_name => "foo bar bat" }).and_return({})
         org.create
       end
     end
 
     describe "read" do
       it "loads a named org from the API" do
-        expect(rest).to receive(:get_rest).with("organizations/foobar").and_return({"name" => "foobar", "full_name" => "foo bar bat", "private_key" => "private"})
+        expect(rest).to receive(:get).with("organizations/foobar").and_return({ "name" => "foobar", "full_name" => "foo bar bat", "private_key" => "private" })
         org = Chef::Org.load("foobar")
         expect(org.name).to eq("foobar")
         expect(org.full_name).to eq("foo bar bat")
@@ -181,14 +181,14 @@ describe Chef::Org do
 
     describe "update" do
       it "updates an existing org on via the API" do
-        expect(rest).to receive(:put_rest).with("organizations/foobar", {:name => "foobar", :full_name => "foo bar bat"}).and_return({})
+        expect(rest).to receive(:put).with("organizations/foobar", { :name => "foobar", :full_name => "foo bar bat" }).and_return({})
         org.update
       end
     end
 
     describe "destroy" do
       it "deletes the specified org via the API" do
-        expect(rest).to receive(:delete_rest).with("organizations/foobar")
+        expect(rest).to receive(:delete).with("organizations/foobar")
         org.destroy
       end
     end
diff --git a/spec/unit/platform/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb
index 1dbd07a..49da6a9 100644
--- a/spec/unit/platform/query_helpers_spec.rb
+++ b/spec/unit/platform/query_helpers_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe "Chef::Platform#windows_server_2003?" do
   it "returns false early when not on windows" do
-    allow(Chef::Platform).to receive(:windows?).and_return(false)
-    expect(Chef::Platform).not_to receive(:require) 
+    allow(ChefConfig).to receive(:windows?).and_return(false)
+    expect(Chef::Platform).not_to receive(:require)
     expect(Chef::Platform.windows_server_2003?).to be_falsey
   end
 
@@ -31,13 +31,133 @@ describe "Chef::Platform#windows_server_2003?" do
   end
 end
 
-describe 'Chef::Platform#supports_dsc?' do 
-  it 'returns false if powershell is not present' do
+describe "Chef::Platform#windows_nano_server?" do
+  include_context "Win32"
+
+  let(:key) { "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Server\\ServerLevels" }
+  let(:key_query_value) { 0x0001 }
+  let(:access) { key_query_value | 0x0100 }
+  let(:hive) { double("Win32::Registry::HKEY_LOCAL_MACHINE") }
+  let(:registry) { double("Win32::Registry") }
+
+  before(:all) do
+    Win32::Registry = Class.new
+    Win32::Registry::Error = Class.new(RuntimeError)
+  end
+
+  before do
+    Win32::Registry::HKEY_LOCAL_MACHINE = hive
+    Win32::Registry::KEY_QUERY_VALUE = key_query_value
+  end
+
+  after do
+    Win32::Registry.send(:remove_const, "HKEY_LOCAL_MACHINE") if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
+    Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
+  end
+
+  it "returns false early when not on windows" do
+    allow(ChefConfig).to receive(:windows?).and_return(false)
+    expect(Chef::Platform).to_not receive(:require)
+    expect(Chef::Platform.windows_nano_server?).to be false
+  end
+
+  it "returns true when the registry value is 1" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_yield(registry)
+    expect(registry).to receive(:[]).with("NanoServer").and_return(1)
+    expect(Chef::Platform.windows_nano_server?).to be true
+  end
+
+  it "returns false when the registry value is not 1" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_yield(registry)
+    expect(registry).to receive(:[]).with("NanoServer").and_return(0)
+    expect(Chef::Platform.windows_nano_server?).to be false
+  end
+
+  it "returns false when the registry value does not exist" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_yield(registry)
+    expect(registry).to receive(:[]).with("NanoServer").
+      and_raise(Win32::Registry::Error, "The system cannot find the file specified.")
+    expect(Chef::Platform.windows_nano_server?).to be false
+  end
+
+  it "returns false when the registry key does not exist" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_raise(Win32::Registry::Error, "The system cannot find the file specified.")
+    expect(Chef::Platform.windows_nano_server?).to be false
+  end
+end
+
+describe "Chef::Platform#supports_msi?" do
+  include_context "Win32" # clear and restore Win32:: namespace
+
+  let(:key) { "System\\CurrentControlSet\\Services\\msiserver" }
+  let(:key_query_value) { 0x0001 }
+  let(:access) { key_query_value }
+  let(:hive) { double("Win32::Registry::HKEY_LOCAL_MACHINE") }
+  let(:registry) { double("Win32::Registry") }
+
+  before(:all) do
+    Win32::Registry = Class.new
+    Win32::Registry::Error = Class.new(RuntimeError)
+  end
+
+  before do
+    Win32::Registry::HKEY_LOCAL_MACHINE = hive
+    Win32::Registry::KEY_QUERY_VALUE = key_query_value
+  end
+
+  after do
+    Win32::Registry.send(:remove_const, "HKEY_LOCAL_MACHINE") if defined?(Win32::Registry::HKEY_LOCAL_MACHINE)
+    Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
+  end
+
+  it "returns false early when not on windows" do
+    allow(ChefConfig).to receive(:windows?).and_return(false)
+    expect(Chef::Platform).to_not receive(:require)
+    expect(Chef::Platform.supports_msi?).to be false
+  end
+
+  it "returns true when the registry key exists" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_yield(registry)
+    expect(Chef::Platform.supports_msi?).to be true
+  end
+
+  it "returns false when the registry key does not exist" do
+    allow(ChefConfig).to receive(:windows?).and_return(true)
+    allow(Chef::Platform).to receive(:require).with("win32/registry")
+    expect(Win32::Registry::HKEY_LOCAL_MACHINE).to receive(:open).
+      with(key, access).
+      and_raise(Win32::Registry::Error, "The system cannot find the file specified.")
+    expect(Chef::Platform.supports_msi?).to be false
+  end
+end
+
+describe 'Chef::Platform#supports_dsc?' do
+  it "returns false if powershell is not present" do
     node = Chef::Node.new
     expect(Chef::Platform.supports_dsc?(node)).to be_falsey
   end
 
-  ['1.0', '2.0', '3.0'].each do |version|
+  ["1.0", "2.0", "3.0"].each do |version|
     it "returns false for Powershell #{version}" do
       node = Chef::Node.new
       node.automatic[:languages][:powershell][:version] = version
@@ -45,7 +165,7 @@ describe 'Chef::Platform#supports_dsc?' do
     end
   end
 
-  ['4.0', '5.0'].each do |version|
+  ["4.0", "5.0"].each do |version|
     it "returns true for Powershell #{version}" do
       node = Chef::Node.new
       node.automatic[:languages][:powershell][:version] = version
@@ -54,13 +174,13 @@ describe 'Chef::Platform#supports_dsc?' do
   end
 end
 
-describe 'Chef::Platform#supports_dsc_invoke_resource?' do 
-  it 'returns false if powershell is not present' do
+describe 'Chef::Platform#supports_dsc_invoke_resource?' do
+  it "returns false if powershell is not present" do
     node = Chef::Node.new
     expect(Chef::Platform.supports_dsc_invoke_resource?(node)).to be_falsey
   end
 
-  ['1.0', '2.0', '3.0', '4.0', '5.0.10017.9'].each do |version|
+  ["1.0", "2.0", "3.0", "4.0", "5.0.10017.9"].each do |version|
     it "returns false for Powershell #{version}" do
       node = Chef::Node.new
       node.automatic[:languages][:powershell][:version] = version
@@ -75,3 +195,26 @@ describe 'Chef::Platform#supports_dsc_invoke_resource?' do
   end
 end
 
+describe 'Chef::Platform#dsc_refresh_mode_disabled?' do
+  let(:node) { instance_double("Chef::Node") }
+  let(:cmdlet) { instance_double("Chef::Util::Powershell::Cmdlet") }
+  let(:cmdlet_result) { instance_double("Chef::Util::Powershell::CmdletResult") }
+
+  it "returns true when RefreshMode is Disabled" do
+    expect(Chef::Util::Powershell::Cmdlet).to receive(:new).
+      with(node, "Get-DscLocalConfigurationManager", :object).
+      and_return(cmdlet)
+    expect(cmdlet).to receive(:run!).and_return(cmdlet_result)
+    expect(cmdlet_result).to receive(:return_value).and_return({ "RefreshMode" => "Disabled" })
+    expect(Chef::Platform.dsc_refresh_mode_disabled?(node)).to be true
+  end
+
+  it "returns false when RefreshMode is not Disabled" do
+    expect(Chef::Util::Powershell::Cmdlet).to receive(:new).
+      with(node, "Get-DscLocalConfigurationManager", :object).
+      and_return(cmdlet)
+    expect(cmdlet).to receive(:run!).and_return(cmdlet_result)
+    expect(cmdlet_result).to receive(:return_value).and_return({ "RefreshMode" => "LaLaLa" })
+    expect(Chef::Platform.dsc_refresh_mode_disabled?(node)).to be false
+  end
+end
diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb
index e0115bc..e37e00b 100644
--- a/spec/unit/platform_spec.rb
+++ b/spec/unit/platform_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,30 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-
-describe "Chef::Platform supports" do
-  [
-    :freebsd,
-    :ubuntu,
-    :debian,
-    :centos,
-    :fedora,
-    :suse,
-    :opensuse,
-    :redhat,
-    :oracle,
-    :gentoo,
-    :arch,
-    :solaris,
-    :gcel,
-    :ibm_powerkvm
-  ].each do |platform|
-    it "#{platform}" do
-      expect(Chef::Platform.platforms).to have_key(platform)
-    end
-  end
-end
+require "spec_helper"
 
 describe Chef::Platform do
 
@@ -61,20 +38,20 @@ describe Chef::Platform do
           },
           "9.2.2" => {
             :file => "darwinian",
-            :else => "thing"
+            :else => "thing",
           },
           :default => {
             :file => "old school",
-            :snicker => "snack"
-          }
+            :snicker => "snack",
+          },
         },
         :mars_volta => {
         },
         :default => {
           :file => Chef::Provider::File,
           :pax => "brittania",
-          :cat => "nice"
-        }
+          :cat => "nice",
+        },
       }
       @events = Chef::EventDispatch::Dispatcher.new
     end
@@ -126,7 +103,7 @@ describe Chef::Platform do
     end
 
     it "should raise an exception if a provider cannot be found for a resource type" do
-      expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(ArgumentError)
+      expect { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.to raise_error(Chef::Exceptions::ProviderNotFound)
     end
 
     it "should look up a provider for a resource with a Chef::Resource object" do
@@ -194,11 +171,11 @@ describe Chef::Platform do
 
     it "raises an error when trying to find the provider for a resource with no run context" do
       file = Chef::Resource::File.new("whateva")
-      expect {Chef::Platform.provider_for_resource(file)}.to raise_error(ArgumentError)
+      expect { Chef::Platform.provider_for_resource(file) }.to raise_error(ArgumentError)
     end
 
     it "does not support finding a provider by resource and node -- a run context is required" do
-      expect {Chef::Platform.provider_for_node('node', 'resource')}.to raise_error(NotImplementedError)
+      expect { Chef::Platform.provider_for_node("node", "resource") }.to raise_error(NotImplementedError)
     end
 
     it "should update the provider map with map" do
@@ -206,18 +183,18 @@ describe Chef::Platform do
            :platform => :darwin,
            :version => "9.2.2",
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:darwin]["9.2.2"][:file]).to eql("masterful")
       Chef::Platform.set(
            :platform => :darwin,
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:darwin][:default][:file]).to eql("masterful")
       Chef::Platform.set(
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:default][:file]).to eql("masterful")
 
@@ -225,13 +202,13 @@ describe Chef::Platform do
            :platform => :hero,
            :version => "9.2.2",
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:hero]["9.2.2"][:file]).to eql("masterful")
 
       Chef::Platform.set(
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:default][:file]).to eql("masterful")
 
@@ -239,7 +216,7 @@ describe Chef::Platform do
 
       Chef::Platform.set(
            :resource => :file,
-           :provider => "masterful"
+           :provider => "masterful",
       )
       expect(Chef::Platform.platforms[:default][:file]).to eql("masterful")
 
@@ -253,7 +230,7 @@ describe Chef::Platform do
       Chef::Platform.set(
         :resource => :file,
         :platform => :default,
-        :provider => "new school"
+        :provider => "new school",
       )
       expect(Chef::Platform.platforms[:default][:file]).to eql("new school")
       expect(Chef::Platform.platforms[:default][:cat]).to eql("nice")
@@ -261,41 +238,4 @@ describe Chef::Platform do
 
   end
 
-  context "while testing the configured platform data" do
-
-    it "should use the solaris package provider on Solaris <11" do
-      pmap = Chef::Platform.find("Solaris2", "5.9")
-      expect(pmap[:package]).to eql(Chef::Provider::Package::Solaris)
-    end
-
-    it "should use the IPS package provider on Solaris 11" do
-      pmap = Chef::Platform.find("Solaris2", "5.11")
-      expect(pmap[:package]).to eql(Chef::Provider::Package::Ips)
-    end
-
-    it "should use the Redhat service provider on SLES11" do
-      1.upto(3) do |sp|
-        pmap = Chef::Platform.find("SUSE", "11.#{sp}")
-        expect(pmap[:service]).to eql(Chef::Provider::Service::Redhat)
-      end
-    end
-
-    it "should use the Systemd service provider on SLES12" do
-      pmap = Chef::Platform.find("SUSE", "12.0")
-      expect(pmap[:service]).to eql(Chef::Provider::Service::Systemd)
-    end
-
-    it "should use the SUSE group provider on SLES11" do
-      1.upto(3) do |sp|
-        pmap = Chef::Platform.find("SUSE", "11.#{sp}")
-        expect(pmap[:group]).to eql(Chef::Provider::Group::Suse)
-      end
-    end
-
-    it "should use the Gpasswd group provider on SLES12" do
-      pmap = Chef::Platform.find("SUSE", "12.0")
-      expect(pmap[:group]).to eql(Chef::Provider::Group::Gpasswd)
-    end
-  end
-
 end
diff --git a/spec/unit/policy_builder/dynamic_spec.rb b/spec/unit/policy_builder/dynamic_spec.rb
new file mode 100644
index 0000000..f91b0ba
--- /dev/null
+++ b/spec/unit/policy_builder/dynamic_spec.rb
@@ -0,0 +1,273 @@
+#
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/policy_builder"
+
+describe Chef::PolicyBuilder::Dynamic do
+
+  let(:node_name) { "joe_node" }
+  let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+  let(:json_attribs) { { "custom_attr" => "custom_attr_value" } }
+  let(:override_runlist) { nil }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+
+  let(:err_namespace) { Chef::PolicyBuilder::Policyfile }
+
+  let(:base_node) do
+    node = Chef::Node.new
+    node.name(node_name)
+    node
+  end
+
+  let(:node) { base_node }
+
+  subject(:policy_builder) { Chef::PolicyBuilder::Dynamic.new(node_name, ohai_data, json_attribs, override_runlist, events) }
+
+  describe "loading policy data" do
+
+    describe "delegating PolicyBuilder API to the correct implementation" do
+
+      let(:implementation) { instance_double("Chef::PolicyBuilder::Policyfile") }
+
+      before do
+        allow(policy_builder).to receive(:implementation).and_return(implementation)
+      end
+
+      # Dynamic should load_node, figure out the correct backend, then forward
+      # messages to it after. That behavior is tested below.
+      it "responds to #load_node" do
+        expect(policy_builder).to respond_to(:load_node)
+      end
+
+      it "forwards #original_runlist" do
+        expect(implementation).to receive(:original_runlist)
+        policy_builder.original_runlist
+      end
+
+      it "forwards #run_context" do
+        expect(implementation).to receive(:run_context)
+        policy_builder.run_context
+      end
+
+      it "forwards #run_list_expansion" do
+        expect(implementation).to receive(:run_list_expansion)
+        policy_builder.run_list_expansion
+      end
+
+      it "forwards #build_node to the implementation object" do
+        expect(implementation).to receive(:build_node)
+        policy_builder.build_node
+      end
+
+      it "forwards #setup_run_context to the implementation object" do
+        expect(implementation).to receive(:setup_run_context)
+        policy_builder.setup_run_context
+
+        arg = Object.new
+
+        expect(implementation).to receive(:setup_run_context).with(arg)
+        policy_builder.setup_run_context(arg)
+      end
+
+      it "forwards #expand_run_list to the implementation object" do
+        expect(implementation).to receive(:expand_run_list)
+        policy_builder.expand_run_list
+      end
+
+      it "forwards #sync_cookbooks to the implementation object" do
+        expect(implementation).to receive(:sync_cookbooks)
+        policy_builder.sync_cookbooks
+      end
+
+      it "forwards #temporary_policy? to the implementation object" do
+        expect(implementation).to receive(:temporary_policy?)
+        policy_builder.temporary_policy?
+      end
+
+    end
+
+    describe "selecting a backend implementation" do
+
+      let(:implementation) do
+        policy_builder.select_implementation(node)
+        policy_builder.implementation
+      end
+
+      context "when no policyfile attributes are present on the node" do
+
+        context "and json_attribs are not given" do
+
+          let(:json_attribs) { {} }
+
+          it "uses the ExpandNodeObject implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::ExpandNodeObject)
+          end
+
+        end
+
+        context "and no policyfile attributes are present in json_attribs" do
+
+          let(:json_attribs) { { "foo" => "bar" } }
+
+          it "uses the ExpandNodeObject implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::ExpandNodeObject)
+          end
+
+        end
+
+        context "and :use_policyfile is set in Chef::Config" do
+
+          before do
+            Chef::Config[:use_policyfile] = true
+          end
+
+          it "uses the Policyfile implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
+          end
+
+        end
+
+        context "and policy_name and policy_group are set on Chef::Config" do
+
+          before do
+            Chef::Config[:policy_name] = "example-policy"
+            Chef::Config[:policy_group] = "testing"
+          end
+
+          it "uses the Policyfile implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
+          end
+
+        end
+
+        context "and deployment_group and policy_document_native_api are set on Chef::Config" do
+
+          before do
+            Chef::Config[:deployment_group] = "example-policy-staging"
+            Chef::Config[:policy_document_native_api] = false
+          end
+
+          it "uses the Policyfile implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
+          end
+
+        end
+
+        context "and policyfile attributes are present in json_attribs" do
+
+          let(:json_attribs) { { "policy_name" => "example-policy", "policy_group" => "testing" } }
+
+          it "uses the Policyfile implementation" do
+            expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
+          end
+
+        end
+
+      end
+
+      context "when policyfile attributes are present on the node" do
+
+        let(:node) do
+          base_node.policy_name = "example-policy"
+          base_node.policy_group = "staging"
+          base_node
+        end
+
+        it "uses the Policyfile implementation" do
+          expect(implementation).to be_a(Chef::PolicyBuilder::Policyfile)
+        end
+
+      end
+
+    end
+
+    describe "loading a node" do
+
+      let(:implementation) { instance_double("Chef::PolicyBuilder::Policyfile") }
+
+      before do
+        allow(policy_builder).to receive(:implementation).and_return(implementation)
+      end
+
+      context "when not running chef solo" do
+
+        context "when successful" do
+
+          before do
+            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
+            expect(policy_builder).to receive(:select_implementation).with(node)
+            expect(implementation).to receive(:finish_load_node).with(node)
+          end
+
+          it "selects the backend implementation and continues node loading" do
+            policy_builder.load_node
+          end
+
+        end
+
+        context "when an error occurs finding the node" do
+
+          before do
+            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_raise("oops")
+          end
+
+          it "sends a node_load_failed event and re-raises" do
+            expect(events).to receive(:node_load_failed)
+            expect { policy_builder.load_node }.to raise_error("oops")
+          end
+
+        end
+
+        context "when an error occurs in the implementation's finish_load_node call" do
+
+          before do
+            expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
+            expect(policy_builder).to receive(:select_implementation).with(node)
+            expect(implementation).to receive(:finish_load_node).and_raise("oops")
+          end
+
+          it "sends a node_load_failed event and re-raises" do
+            expect(events).to receive(:node_load_failed)
+            expect { policy_builder.load_node }.to raise_error("oops")
+          end
+
+        end
+
+      end
+
+      context "when running chef solo" do
+
+        before do
+          Chef::Config[:solo] = true
+          expect(Chef::Node).to receive(:build).with(node_name).and_return(node)
+          expect(policy_builder).to receive(:select_implementation).with(node)
+          expect(implementation).to receive(:finish_load_node).with(node)
+        end
+
+        it "selects the backend implementation and continues node loading" do
+          policy_builder.load_node
+        end
+
+      end
+
+    end
+
+  end
+
+end
diff --git a/spec/unit/policy_builder/expand_node_object_spec.rb b/spec/unit/policy_builder/expand_node_object_spec.rb
index 8e9fdc3..8667532 100644
--- a/spec/unit/policy_builder/expand_node_object_spec.rb
+++ b/spec/unit/policy_builder/expand_node_object_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
 
 describe Chef::PolicyBuilder::ExpandNodeObject do
 
   let(:node_name) { "joe_node" }
-  let(:ohai_data) { {"platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com"} }
-  let(:json_attribs) { {"run_list" => []} }
+  let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+  let(:json_attribs) { { "run_list" => [] } }
   let(:override_runlist) { "recipe[foo::default]" }
   let(:events) { Chef::EventDispatch::Dispatcher.new }
   let(:policy_builder) { Chef::PolicyBuilder::ExpandNodeObject.new(node_name, ohai_data, json_attribs, override_runlist, events) }
@@ -34,10 +34,18 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
       expect(policy_builder).to respond_to(:node)
     end
 
-    it "implements a load_node method" do
+    it "implements a load_node method for backwards compatibility until Chef 13" do
       expect(policy_builder).to respond_to(:load_node)
     end
 
+    it "has removed the deprecated #load_node method", :chef_gte_13_only do
+      expect(policy_builder).to_not respond_to(:load_node)
+    end
+
+    it "implements a finish_load_node method" do
+      expect(policy_builder).to respond_to(:finish_load_node)
+    end
+
     it "implements  a build_node method" do
       expect(policy_builder).to respond_to(:build_node)
     end
@@ -63,39 +71,13 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
       expect(policy_builder).to respond_to(:temporary_policy?)
     end
 
-    describe "loading the node" do
-
-      context "on chef-solo" do
-
-        before do
-          Chef::Config[:solo] = true
-        end
-
-        it "creates a new in-memory node object with the given name" do
-          policy_builder.load_node
-          expect(policy_builder.node.name).to eq(node_name)
-        end
-
-      end
-
-      context "on chef-client" do
-
-        let(:node) { Chef::Node.new.tap { |n| n.name(node_name) } }
-
-        it "loads or creates a node on the server" do
-          expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
-          policy_builder.load_node
-          expect(policy_builder.node).to eq(node)
-        end
+    describe "finishing loading the node" do
 
-      end
-    end
-
-    describe "building the node" do
+      let(:node) { Chef::Node.new.tap { |n| n.name(node_name) } }
 
-      # XXX: Chef::Client just needs to be able to call this, it doesn't depend on the return value.
-      it "builds the node and returns the updated node object" do
-        skip
+      it "stores the node" do
+        policy_builder.finish_load_node(node)
+        expect(policy_builder.node).to eq(node)
       end
 
     end
@@ -124,7 +106,8 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
 
   end
 
-  context "once the node has been loaded" do
+  context "deprecated #load_node method" do
+
     let(:node) do
       node = Chef::Node.new
       node.name(node_name)
@@ -133,10 +116,29 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
     end
 
     before do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
       expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
       policy_builder.load_node
     end
 
+    it "loads the node" do
+      expect(policy_builder.node).to eq(node)
+    end
+
+  end
+
+  context "once the node has been loaded" do
+    let(:node) do
+      node = Chef::Node.new
+      node.name(node_name)
+      node.run_list(["recipe[a::default]", "recipe[b::server]"])
+      node
+    end
+
+    before do
+      policy_builder.finish_load_node(node)
+    end
+
     it "expands the run_list" do
       expect(policy_builder.expand_run_list).to be_a(Chef::RunList::RunListExpansion)
       expect(policy_builder.run_list_expansion).to be_a(Chef::RunList::RunListExpansion)
@@ -153,8 +155,8 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
     let(:override_runlist) { nil }
     let(:primary_runlist) { ["recipe[primary::default]"] }
 
-    let(:original_default_attrs) { {"default_key" => "default_value"} }
-    let(:original_override_attrs) { {"override_key" => "override_value"} }
+    let(:original_default_attrs) { { "default_key" => "default_value" } }
+    let(:original_override_attrs) { { "override_key" => "override_value" } }
 
     let(:node) do
       node = Chef::Node.new
@@ -167,8 +169,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
 
     before do
       Chef::Config[:environment] = configured_environment
-      expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
-      policy_builder.load_node
+      policy_builder.finish_load_node(node)
       policy_builder.build_node
     end
 
@@ -226,7 +227,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
 
     context "when JSON attributes are given on the command line" do
 
-      let(:json_attribs) { {"run_list" => ["recipe[json_attribs::default]"], "json_attribs_key" => "json_attribs_value"  } }
+      let(:json_attribs) { { "run_list" => ["recipe[json_attribs::default]"], "json_attribs_key" => "json_attribs_value" } }
 
       it "sets the run list according to the given JSON" do
         expect(node.run_list).to eq(["recipe[json_attribs::default]"])
@@ -266,7 +267,7 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
       let(:configured_environment) { environment.name }
 
       let(:environment) do
-        environment = Chef::Environment.new.tap {|e| e.name("prod") }
+        environment = Chef::Environment.new.tap { |e| e.name("prod") }
         expect(Chef::Environment).to receive(:load).with("prod").and_return(environment)
         environment
       end
@@ -289,30 +290,30 @@ describe Chef::PolicyBuilder::ExpandNodeObject do
       node
     end
 
-    let(:chef_http) { double("Chef::REST") }
+    let(:chef_http) { double("Chef::ServerAPI") }
 
     let(:cookbook_resolve_url) { "environments/#{node.chef_environment}/cookbook_versions" }
-    let(:cookbook_resolve_post_data) { {:run_list=>["first::default", "second::default"]} }
+    let(:cookbook_resolve_post_data) { { :run_list => ["first::default", "second::default"] } }
 
     # cookbook_hash is just a hash, but since we're passing it between mock
     # objects, we get a little better test strictness by using a double (which
     # will have object equality rather than semantic equality #== semantics).
-    let(:cookbook_hash) { double("cookbook hash", :each => nil) }
+    let(:cookbook_hash) { double("cookbook hash") }
+    let(:expanded_cookbook_hash) { double("expanded cookbook hash", :each => nil) }
 
     let(:cookbook_synchronizer) { double("CookbookSynchronizer") }
 
     before do
-      expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
-
       allow(policy_builder).to receive(:api_service).and_return(chef_http)
 
-      policy_builder.load_node
+      policy_builder.finish_load_node(node)
       policy_builder.build_node
 
       run_list_expansion = policy_builder.run_list_expansion
 
+      expect(cookbook_hash).to receive(:inject).and_return(expanded_cookbook_hash)
       expect(chef_http).to receive(:post).with(cookbook_resolve_url, cookbook_resolve_post_data).and_return(cookbook_hash)
-      expect(Chef::CookbookSynchronizer).to receive(:new).with(cookbook_hash, events).and_return(cookbook_synchronizer)
+      expect(Chef::CookbookSynchronizer).to receive(:new).with(expanded_cookbook_hash, events).and_return(cookbook_synchronizer)
       expect(cookbook_synchronizer).to receive(:sync_cookbooks)
 
       expect_any_instance_of(Chef::RunContext).to receive(:load).with(run_list_expansion)
diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb
index e4f7388..6b71b4d 100644
--- a/spec/unit/policy_builder/policyfile_spec.rb
+++ b/spec/unit/policy_builder/policyfile_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
 
 describe Chef::PolicyBuilder::Policyfile do
 
   let(:node_name) { "joe_node" }
-  let(:ohai_data) { {"platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com"} }
-  let(:json_attribs) { {"custom_attr" => "custom_attr_value"} }
+  let(:ohai_data) { { "platform" => "ubuntu", "platform_version" => "13.04", "fqdn" => "joenode.example.com" } }
+  let(:json_attribs) { { "custom_attr" => "custom_attr_value" } }
   let(:override_runlist) { nil }
   let(:events) { Chef::EventDispatch::Dispatcher.new }
   let(:policy_builder) { Chef::PolicyBuilder::Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events) }
@@ -40,11 +40,10 @@ describe Chef::PolicyBuilder::Policyfile do
     major = sha1_id[0...14]
     minor = sha1_id[14...28]
     patch = sha1_id[28..40]
-    decimal_integers =[major, minor, patch].map {|hex| hex.to_i(16) }
+    decimal_integers = [major, minor, patch].map { |hex| hex.to_i(16) }
     decimal_integers.join(".")
   end
 
-
   let(:example1_lock_data) do
     # based on https://github.com/danielsdeleo/chef-workflow2-prototype/blob/master/skeletons/basic_policy/Policyfile.lock.json
     {
@@ -53,11 +52,11 @@ describe Chef::PolicyBuilder::Policyfile do
       # NOTE: for compatibility mode we include the dotted id in the policyfile to enhance discoverability.
       "dotted_decimal_identifier" => id_to_dotted("168d2102fb11c9617cd8a981166c8adc30a6e915"),
       "source" => { "path" => "./cookbooks/demo" },
-      "scm_identifier"=> {
-        "vcs"=> "git",
-        "rev_id"=> "9d5b09026470c322c3cb5ca8a4157c4d2f16cef3",
-        "remote"=> nil
-      }
+      "scm_identifier" => {
+        "vcs" => "git",
+        "rev_id" => "9d5b09026470c322c3cb5ca8a4157c4d2f16cef3",
+        "remote" => nil,
+      },
     }
   end
 
@@ -67,36 +66,41 @@ describe Chef::PolicyBuilder::Policyfile do
       "version" => "4.2.0",
       # NOTE: for compatibility mode we include the dotted id in the policyfile to enhance discoverability.
       "dotted_decimal_identifier" => id_to_dotted("feab40e1fca77c7360ccca1481bb8ba5f919ce3a"),
-      "source" => { "api" => "https://community.getchef.com/api/v1/cookbooks/example2" }
+      "source" => { "api" => "https://community.getchef.com/api/v1/cookbooks/example2" },
     }
   end
 
-  let(:policyfile_default_attributes) { {"policyfile_default_attr" => "policyfile_default_value"} }
-  let(:policyfile_override_attributes) { {"policyfile_override_attr" => "policyfile_override_value"} }
+  let(:policyfile_default_attributes) { { "policyfile_default_attr" => "policyfile_default_value" } }
+  let(:policyfile_override_attributes) { { "policyfile_override_attr" => "policyfile_override_value" } }
 
   let(:policyfile_run_list) { ["recipe[example1::default]", "recipe[example2::server]"] }
 
-  let(:parsed_policyfile_json) do
+  let(:basic_valid_policy_data) do
     {
+      "name" => "example-policy",
+      "revision_id" => "123abc",
+
       "run_list" => policyfile_run_list,
 
       "cookbook_locks" => {
         "example1" => example1_lock_data,
-        "example2" => example2_lock_data
+        "example2" => example2_lock_data,
       },
 
       "default_attributes" => policyfile_default_attributes,
-      "override_attributes" => policyfile_override_attributes
+      "override_attributes" => policyfile_override_attributes,
     }
   end
 
+  let(:parsed_policyfile_json) { basic_valid_policy_data }
+
   let(:err_namespace) { Chef::PolicyBuilder::Policyfile }
 
   it "configures a Chef HTTP API client" do
-    http = double("Chef::REST")
+    http = double("Chef::ServerAPI")
     server_url = "https://api.opscode.com/organizations/example"
     Chef::Config[:chef_server_url] = server_url
-    expect(Chef::REST).to receive(:new).with(server_url).and_return(http)
+    expect(Chef::ServerAPI).to receive(:new).with(server_url).and_return(http)
     expect(policy_builder.http_api).to eq(http)
   end
 
@@ -127,7 +131,7 @@ describe Chef::PolicyBuilder::Policyfile do
     end
 
     context "when json_attribs contains a run_list" do
-      let(:json_attribs) { {"run_list" => []} }
+      let(:json_attribs) { { "run_list" => [] } }
 
       it "errors on create" do
         expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature)
@@ -146,15 +150,15 @@ describe Chef::PolicyBuilder::Policyfile do
 
   describe "loading policy data" do
 
-    let(:http_api) { double("Chef::REST") }
+    let(:http_api) { double("Chef::ServerAPI") }
 
     let(:configured_environment) { nil }
 
     let(:override_runlist) { nil }
     let(:primary_runlist) { nil }
 
-    let(:original_default_attrs) { {"default_key" => "default_value"} }
-    let(:original_override_attrs) { {"override_key" => "override_value"} }
+    let(:original_default_attrs) { { "default_key" => "default_value" } }
+    let(:original_override_attrs) { { "override_key" => "override_value" } }
 
     let(:node) do
       node = Chef::Node.new
@@ -166,30 +170,28 @@ describe Chef::PolicyBuilder::Policyfile do
     end
 
     before do
-      # TODO: agree on this name and logic.
+      Chef::Config[:policy_document_native_api] = false
       Chef::Config[:deployment_group] = "example-policy-stage"
       allow(policy_builder).to receive(:http_api).and_return(http_api)
     end
 
     describe "when using compatibility mode (policy_document_native_api == false)" do
 
+      before do
+        Chef::Config[:deployment_group] = "example-policy-stage"
+      end
+
       context "when the deployment group cannot be loaded" do
         let(:error404) { Net::HTTPServerException.new("404 message", :body) }
 
         before do
-          expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
           expect(http_api).to receive(:get).
             with("data/policyfiles/example-policy-stage").
             and_raise(error404)
         end
 
         it "raises an error" do
-          expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError)
-        end
-
-        it "sends error message to the event system" do
-          expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_namespace::ConfigurationError), Chef::Config)
-          expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError)
+          expect { policy_builder.finish_load_node(node) }.to raise_error(err_namespace::ConfigurationError)
         end
 
       end
@@ -197,20 +199,12 @@ describe Chef::PolicyBuilder::Policyfile do
       context "when the deployment_group is not configured" do
         before do
           Chef::Config[:deployment_group] = nil
-          expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
         end
 
         it "errors while loading the node" do
-          expect { policy_builder.load_node }.to raise_error(err_namespace::ConfigurationError)
+          expect { policy_builder.finish_load_node(node) }.to raise_error(err_namespace::ConfigurationError)
         end
 
-
-        it "passes error information to the event system" do
-          # TODO: also make sure something acceptable happens with the error formatters
-          err_class = err_namespace::ConfigurationError
-          expect(events).to receive(:node_load_failed).with(node_name, an_instance_of(err_class), Chef::Config)
-          expect { policy_builder.load_node }.to raise_error(err_class)
-        end
       end
 
       context "when deployment_group is correctly configured" do
@@ -273,7 +267,6 @@ describe Chef::PolicyBuilder::Policyfile do
 
     end
 
-
     describe "building policy from the policyfile" do
 
       before do
@@ -291,7 +284,7 @@ describe Chef::PolicyBuilder::Policyfile do
       it "extracts the cookbooks and versions for display from the policyfile" do
         expected = [
           "example1::default at 2.3.5 (168d210)",
-          "example2::server at 4.2.0 (feab40e)"
+          "example2::server at 4.2.0 (feab40e)",
         ]
 
         expect(policy_builder.run_list_with_versions_for_display).to eq(expected)
@@ -303,14 +296,12 @@ describe Chef::PolicyBuilder::Policyfile do
       end
 
       it "implements #expand_run_list in a manner compatible with ExpandNodeObject" do
-        expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
-        policy_builder.load_node
+        policy_builder.finish_load_node(node)
         expect(policy_builder.expand_run_list).to respond_to(:recipes)
         expect(policy_builder.expand_run_list.recipes).to eq(["example1::default", "example2::server"])
         expect(policy_builder.expand_run_list.roles).to eq([])
       end
 
-
       describe "validating the Policyfile.lock" do
 
         it "errors if the policyfile json contains any non-recipe items" do
@@ -341,56 +332,269 @@ describe Chef::PolicyBuilder::Policyfile do
 
       describe "building the node object" do
 
+        let(:extra_chef_config) { {} }
+
         before do
-          expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
+          # must be set before #build_node is called to have the proper effect
+          extra_chef_config.each do |key, value|
+            Chef::Config[key] = value
+          end
 
-          policy_builder.load_node
+          policy_builder.finish_load_node(node)
           policy_builder.build_node
         end
 
+        # it sets policy_name and policy_group in the following priority order:
+        # -j JSON > config file > node object
+
+        describe "selecting policy_name and policy_group from the various sources" do
+
+          context "when only set in node JSON" do
+
+            let(:json_attribs) do
+              {
+                "policy_name" => "policy_name_from_node_json",
+                "policy_group" => "policy_group_from_node_json",
+              }
+            end
+
+            it "sets policy_name and policy_group on Chef::Config" do
+              expect(Chef::Config[:policy_name]).to eq("policy_name_from_node_json")
+              expect(Chef::Config[:policy_group]).to eq("policy_group_from_node_json")
+            end
+
+            it "sets policy_name and policy_group on the node object" do
+              expect(node.policy_name).to eq("policy_name_from_node_json")
+              expect(node.policy_group).to eq("policy_group_from_node_json")
+            end
+
+          end
+
+          context "when only set in Chef::Config" do
+
+            let(:extra_chef_config) do
+              {
+                policy_name: "policy_name_from_config",
+                policy_group: "policy_group_from_config",
+              }
+            end
+
+            it "sets policy_name and policy_group on the node object" do
+              expect(node.policy_name).to eq("policy_name_from_config")
+              expect(node.policy_group).to eq("policy_group_from_config")
+            end
+
+          end
+
+          context "when only set on the node" do
+
+            let(:node) do
+              node = Chef::Node.new
+              node.name(node_name)
+              node.policy_name = "policy_name_from_node"
+              node.policy_group = "policy_group_from_node"
+              node
+            end
+
+            it "sets policy_name and policy_group on Chef::Config" do
+              expect(Chef::Config[:policy_name]).to eq("policy_name_from_node")
+              expect(Chef::Config[:policy_group]).to eq("policy_group_from_node")
+            end
+
+          end
+
+          context "when set in Chef::Config and the fetched node" do
+
+            let(:node) do
+              node = Chef::Node.new
+              node.name(node_name)
+              node.policy_name = "policy_name_from_node"
+              node.policy_group = "policy_group_from_node"
+              node
+            end
+
+            let(:extra_chef_config) do
+              {
+                policy_name: "policy_name_from_config",
+                policy_group: "policy_group_from_config",
+              }
+            end
+
+            it "prefers the policy_name and policy_group from Chef::Config" do
+              expect(node.policy_name).to eq("policy_name_from_config")
+              expect(node.policy_group).to eq("policy_group_from_config")
+            end
+
+          end
+
+          context "when set in node json and the fetched node" do
+
+            let(:json_attribs) do
+              {
+                "policy_name" => "policy_name_from_node_json",
+                "policy_group" => "policy_group_from_node_json",
+              }
+            end
+
+            let(:node) do
+              node = Chef::Node.new
+              node.name(node_name)
+              node.policy_name = "policy_name_from_node"
+              node.policy_group = "policy_group_from_node"
+              node
+            end
+
+            it "prefers the policy_name and policy_group from the node json" do
+              expect(policy_builder.policy_name).to eq("policy_name_from_node_json")
+              expect(policy_builder.policy_group).to eq("policy_group_from_node_json")
+
+              expect(Chef::Config[:policy_name]).to eq("policy_name_from_node_json")
+              expect(Chef::Config[:policy_group]).to eq("policy_group_from_node_json")
+              expect(node.policy_name).to eq("policy_name_from_node_json")
+              expect(node.policy_group).to eq("policy_group_from_node_json")
+            end
+
+          end
+
+          context "when set in all sources" do
+
+            let(:json_attribs) do
+              {
+                "policy_name" => "policy_name_from_node_json",
+                "policy_group" => "policy_group_from_node_json",
+              }
+            end
+
+            let(:node) do
+              node = Chef::Node.new
+              node.name(node_name)
+              node.policy_name = "policy_name_from_node"
+              node.policy_group = "policy_group_from_node"
+              node
+            end
+
+            let(:extra_chef_config) do
+              {
+                policy_name: "policy_name_from_config",
+                policy_group: "policy_group_from_config",
+              }
+            end
+
+            it "prefers the policy_name and group from node json" do
+              expect(policy_builder.policy_name).to eq("policy_name_from_node_json")
+              expect(policy_builder.policy_group).to eq("policy_group_from_node_json")
+
+              expect(Chef::Config[:policy_name]).to eq("policy_name_from_node_json")
+              expect(Chef::Config[:policy_group]).to eq("policy_group_from_node_json")
+              expect(node.policy_name).to eq("policy_name_from_node_json")
+              expect(node.policy_group).to eq("policy_group_from_node_json")
+            end
+
+          end
+
+        end
+
         it "resets default and override data" do
           expect(node["default_key"]).to be_nil
           expect(node["override_key"]).to be_nil
         end
 
-        it "applies ohai data" do
-          expect(ohai_data).to_not be_empty # ensure test is testing something
-          ohai_data.each do |key, value|
-            expect(node.automatic_attrs[key]).to eq(value)
+        describe "setting attribute values" do
+
+          before do
+            policy_builder.build_node
           end
-        end
 
-        it "applies attributes from json file" do
-          expect(node["custom_attr"]).to eq("custom_attr_value")
-        end
+          it "resets default and override data" do
+            expect(node["default_key"]).to be_nil
+            expect(node["override_key"]).to be_nil
+          end
 
-        it "applies attributes from the policyfile" do
-          expect(node["policyfile_default_attr"]).to eq("policyfile_default_value")
-          expect(node["policyfile_override_attr"]).to eq("policyfile_override_value")
-        end
+          it "applies ohai data" do
+            expect(ohai_data).to_not be_empty # ensure test is testing something
+            ohai_data.each do |key, value|
+              expect(node.automatic_attrs[key]).to eq(value)
+            end
+          end
 
-        it "sets the policyfile's run_list on the node object" do
-          expect(node.run_list).to eq(policyfile_run_list)
-        end
+          it "applies attributes from json file" do
+            expect(node["custom_attr"]).to eq("custom_attr_value")
+          end
 
-        it "creates node.automatic_attrs[:roles]" do
-          expect(node.automatic_attrs[:roles]).to eq([])
-        end
+          it "applies attributes from the policyfile" do
+            expect(node["policyfile_default_attr"]).to eq("policyfile_default_value")
+            expect(node["policyfile_override_attr"]).to eq("policyfile_override_value")
+          end
 
-        it "create node.automatic_attrs[:recipes]" do
-          expect(node.automatic_attrs[:recipes]).to eq(["example1::default", "example2::server"])
+          it "sets the policyfile's run_list on the node object" do
+            expect(node.run_list).to eq(policyfile_run_list)
+          end
+
+          it "creates node.automatic_attrs[:roles]" do
+            expect(node.automatic_attrs[:roles]).to eq([])
+          end
+
+          it "create node.automatic_attrs[:recipes]" do
+            expect(node.automatic_attrs[:recipes]).to eq(["example1::default", "example2::server"])
+          end
         end
 
-      end
+        context "when a named run_list is given" do
+
+          before do
+            Chef::Config[:named_run_list] = "deploy-app"
+          end
+
+          context "and the named run_list is not present in the policy" do
+
+            it "raises a ConfigurationError" do
+              err_class = Chef::PolicyBuilder::Policyfile::ConfigurationError
+              err_text = "Policy 'example-policy' revision '123abc' does not have named_run_list 'deploy-app'(available named_run_lists: [])"
+              expect { policy_builder.build_node }.to raise_error(err_class, err_text)
+            end
+
+          end
+
+          context "and the named run_list is present in the policy" do
+
+            let(:parsed_policyfile_json) do
+              basic_valid_policy_data.dup.tap do |p|
+                p["named_run_lists"] = {
+                  "deploy-app" => [ "recipe[example1::default]" ]
+                }
+              end
+            end
+
+            before do
+              policy_builder.build_node
+            end
+
+            it "sets the run list to the desired named run list" do
+              expect(policy_builder.run_list).to eq([ "recipe[example1::default]" ])
+              expected_expansion = Chef::PolicyBuilder::Policyfile::RunListExpansionIsh.new([ "example1::default" ], [])
+              expect(policy_builder.run_list_expansion).to eq(expected_expansion)
+              expect(policy_builder.run_list_with_versions_for_display).to eq(["example1::default at 2.3.5 (168d210)"])
+              expect(node.run_list).to eq([ Chef::RunList::RunListItem.new("recipe[example1::default]") ])
+              expect(node[:roles]).to eq( [] )
+              expect(node[:recipes]).to eq( ["example1::default"] )
+            end
 
+            it "disables the cookbook cache cleaner" do
+              expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be(true)
+            end
+
+          end
+
+        end
+      end
 
       describe "fetching the desired cookbook set" do
 
         let(:example1_cookbook_data) { double("CookbookVersion Hash for example1 cookbook") }
         let(:example2_cookbook_data) { double("CookbookVersion Hash for example2 cookbook") }
 
-        let(:example1_cookbook_object) { double("Chef::CookbookVersion for example1 cookbook") }
-        let(:example2_cookbook_object) { double("Chef::CookbookVersion for example2 cookbook") }
+        let(:example1_cookbook_object) { double("Chef::CookbookVersion for example1 cookbook", version: "0.1.2") }
+        let(:example2_cookbook_object) { double("Chef::CookbookVersion for example2 cookbook", version: "1.2.3") }
 
         let(:expected_cookbook_hash) do
           { "example1" => example1_cookbook_object, "example2" => example2_cookbook_object }
@@ -410,9 +614,7 @@ describe Chef::PolicyBuilder::Policyfile do
             let(:error404) { Net::HTTPServerException.new("404 message", :body) }
 
             before do
-              expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
-
-              policy_builder.load_node
+              policy_builder.finish_load_node(node)
               policy_builder.build_node
 
               expect(http_api).to receive(:get).with(cookbook1_url).
@@ -429,9 +631,9 @@ describe Chef::PolicyBuilder::Policyfile do
         shared_examples_for "fetching cookbooks when they exist" do
           context "and the cookbooks can be fetched" do
             before do
-              expect(Chef::Node).to receive(:find_or_create).with(node_name).and_return(node)
+              Chef.reset!
 
-              policy_builder.load_node
+              policy_builder.finish_load_node(node)
               policy_builder.build_node
 
               allow(Chef::CookbookSynchronizer).to receive(:new).
@@ -439,6 +641,10 @@ describe Chef::PolicyBuilder::Policyfile do
                 and_return(cookbook_synchronizer)
             end
 
+            after do
+              Chef.reset!
+            end
+
             it "builds a Hash of the form 'cookbook_name' => Chef::CookbookVersion" do
               expect(policy_builder.cookbooks_to_sync).to eq(expected_cookbook_hash)
             end
@@ -451,11 +657,20 @@ describe Chef::PolicyBuilder::Policyfile do
             it "builds a run context" do
               expect(cookbook_synchronizer).to receive(:sync_cookbooks)
               expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish)
+              expect_any_instance_of(Chef::CookbookCollection).to receive(:validate!)
               run_context = policy_builder.setup_run_context
               expect(run_context.node).to eq(node)
               expect(run_context.cookbook_collection.keys).to match_array(["example1", "example2"])
             end
 
+            it "makes the run context available via static method on Chef" do
+              expect(cookbook_synchronizer).to receive(:sync_cookbooks)
+              expect_any_instance_of(Chef::RunContext).to receive(:load).with(policy_builder.run_list_expansion_ish)
+              expect_any_instance_of(Chef::CookbookCollection).to receive(:validate!)
+              run_context = policy_builder.setup_run_context
+              expect(Chef.run_context).to eq(run_context)
+            end
+
           end
         end # shared_examples_for "fetching cookbooks"
 
@@ -496,7 +711,6 @@ describe Chef::PolicyBuilder::Policyfile do
             include_examples "fetching cookbooks when they don't exist"
           end
 
-
           context "when the cookbooks exist on the server" do
 
             before do
@@ -515,7 +729,6 @@ describe Chef::PolicyBuilder::Policyfile do
 
           end
 
-
         end
 
       end
diff --git a/spec/unit/policy_builder_spec.rb b/spec/unit/policy_builder_spec.rb
index 5069114..674978a 100644
--- a/spec/unit/policy_builder_spec.rb
+++ b/spec/unit/policy_builder_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright 2014 Chef Software, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/policy_builder'
+require "spec_helper"
+require "chef/policy_builder"
 
 describe Chef::PolicyBuilder do
 
diff --git a/spec/unit/property/state_spec.rb b/spec/unit/property/state_spec.rb
new file mode 100644
index 0000000..f553991
--- /dev/null
+++ b/spec/unit/property/state_spec.rb
@@ -0,0 +1,508 @@
+require "support/shared/integration/integration_helper"
+
+describe "Chef::Resource#identity and #state" do
+  include IntegrationSupport
+
+  class NewResourceNamer
+    @i = 0
+    def self.next
+      "chef_resource_property_spec_#{@i += 1}"
+    end
+  end
+
+  def self.new_resource_name
+    NewResourceNamer.next
+  end
+
+  let(:resource_class) do
+    new_resource_name = self.class.new_resource_name
+    Class.new(Chef::Resource) do
+      resource_name new_resource_name
+    end
+  end
+
+  let(:resource) do
+    resource_class.new("blah")
+  end
+
+  def self.english_join(values)
+    return "<nothing>" if values.size == 0
+    return values[0].inspect if values.size == 1
+    "#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
+  end
+
+  def self.with_property(*properties, &block)
+    tags_index = properties.find_index { |p| !p.is_a?(String) }
+    if tags_index
+      properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
+    else
+      tags = []
+    end
+    properties = properties.map { |property| "property #{property}" }
+    context "With properties #{english_join(properties)}", *tags do
+      before do
+        properties.each do |property_str|
+          resource_class.class_eval(property_str, __FILE__, __LINE__)
+        end
+      end
+      instance_eval(&block)
+    end
+  end
+
+  # identity
+  context "Chef::Resource#identity_properties" do
+    with_property ":x" do
+      it "name is the default identity" do
+        expect(resource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
+        expect(Chef::Resource.properties[:name].identity?).to be_falsey
+        expect(resource.name).to eq "blah"
+        expect(resource.identity).to eq "blah"
+      end
+
+      it "identity_properties :x changes the identity" do
+        expect(resource_class.identity_properties :x).to eq [ resource_class.properties[:x] ]
+        expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
+        expect(Chef::Resource.properties[:name].identity?).to be_falsey
+        expect(resource_class.properties[:x].identity?).to be_truthy
+
+        expect(resource.x "woo").to eq "woo"
+        expect(resource.x).to eq "woo"
+
+        expect(resource.name).to eq "blah"
+        expect(resource.identity).to eq "woo"
+      end
+
+      with_property ":y, identity: true" do
+        context "and identity_properties :x" do
+          before do
+            resource_class.class_eval do
+              identity_properties :x
+            end
+          end
+
+          it "only returns :x as identity" do
+            resource.x "foo"
+            resource.y "bar"
+            expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
+            expect(resource.identity).to eq "foo"
+          end
+          it "does not flip y.desired_state off" do
+            resource.x "foo"
+            resource.y "bar"
+            expect(resource_class.state_properties).to eq [
+              resource_class.properties[:x],
+              resource_class.properties[:y],
+            ]
+            expect(resource.state_for_resource_reporter).to eq(x: "foo", y: "bar")
+          end
+        end
+      end
+
+      context "With a subclass" do
+        let(:subresource_class) do
+          new_resource_name = self.class.new_resource_name
+          Class.new(resource_class) do
+            resource_name new_resource_name
+          end
+        end
+        let(:subresource) do
+          subresource_class.new("sub")
+        end
+
+        it "name is the default identity on the subclass" do
+          expect(subresource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
+          expect(Chef::Resource.properties[:name].identity?).to be_falsey
+          expect(subresource.name).to eq "sub"
+          expect(subresource.identity).to eq "sub"
+        end
+
+        context "With identity_properties :x on the superclass" do
+          before do
+            resource_class.class_eval do
+              identity_properties :x
+            end
+          end
+
+          it "The subclass inherits :x as identity" do
+            expect(subresource_class.identity_properties).to eq [ subresource_class.properties[:x] ]
+            expect(Chef::Resource.properties[:name].identity?).to be_falsey
+            expect(subresource_class.properties[:x].identity?).to be_truthy
+
+            subresource.x "foo"
+            expect(subresource.identity).to eq "foo"
+          end
+
+          context "With property :y, identity: true on the subclass" do
+            before do
+              subresource_class.class_eval do
+                property :y, identity: true
+              end
+            end
+            it "The subclass's identity includes both x and y" do
+              expect(subresource_class.identity_properties).to eq [
+                subresource_class.properties[:x],
+                subresource_class.properties[:y],
+              ]
+              subresource.x "foo"
+              subresource.y "bar"
+              expect(subresource.identity).to eq(x: "foo", y: "bar")
+            end
+          end
+
+          with_property ":y, String" do
+            context "With identity_properties :y on the subclass" do
+              before do
+                subresource_class.class_eval do
+                  identity_properties :y
+                end
+              end
+              it "y is part of state" do
+                subresource.x "foo"
+                subresource.y "bar"
+                expect(subresource.state_for_resource_reporter).to eq(x: "foo", y: "bar")
+                expect(subresource_class.state_properties).to eq [
+                  subresource_class.properties[:x],
+                  subresource_class.properties[:y],
+                ]
+              end
+              it "y is the identity" do
+                expect(subresource_class.identity_properties).to eq [ subresource_class.properties[:y] ]
+                subresource.x "foo"
+                subresource.y "bar"
+                expect(subresource.identity).to eq "bar"
+              end
+              it "y still has validation" do
+                expect { subresource.y 12 }.to raise_error Chef::Exceptions::ValidationFailed
+              end
+            end
+          end
+        end
+      end
+    end
+
+    with_property ":string_only, String, identity: true", ":string_only2, String" do
+      it "identity_properties does not change validation" do
+        resource_class.identity_properties :string_only
+        expect { resource.string_only 12 }.to raise_error Chef::Exceptions::ValidationFailed
+        expect { resource.string_only2 12 }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+    end
+
+    with_property ":x, desired_state: false" do
+      it "identity_properties does not change desired_state" do
+        resource_class.identity_properties :x
+        resource.x "hi"
+        expect(resource.identity).to eq "hi"
+        expect(resource_class.properties[:x].desired_state?).to be_falsey
+        expect(resource_class.state_properties).to eq []
+        expect(resource.state_for_resource_reporter).to eq({})
+      end
+    end
+
+    context "With custom property custom_property defined only as methods, using different variables for storage" do
+      before do
+        resource_class.class_eval do
+          def custom_property
+            @blarghle ? @blarghle * 3 : nil
+          end
+
+          def custom_property=(x)
+            @blarghle = x * 2
+          end
+        end
+      end
+
+      context "And identity_properties :custom_property" do
+        before do
+          resource_class.class_eval do
+            identity_properties :custom_property
+          end
+        end
+
+        it "identity_properties comes back as :custom_property" do
+          expect(resource_class.properties[:custom_property].identity?).to be_truthy
+          expect(resource_class.identity_properties).to eq [ resource_class.properties[:custom_property] ]
+        end
+        it "custom_property becomes part of desired_state" do
+          resource.custom_property = 1
+          expect(resource.state_for_resource_reporter).to eq(custom_property: 6)
+          expect(resource_class.properties[:custom_property].desired_state?).to be_truthy
+          expect(resource_class.state_properties).to eq [
+            resource_class.properties[:custom_property]
+          ]
+        end
+        it "identity_properties does not change custom_property's getter or setter" do
+          resource.custom_property = 1
+          expect(resource.custom_property).to eq 6
+        end
+        it "custom_property is returned as the identity" do
+          expect(resource.identity).to be_nil
+          resource.custom_property = 1
+          expect(resource.identity).to eq 6
+        end
+      end
+    end
+  end
+
+  context "Property#identity" do
+    with_property ":x, identity: true" do
+      it "name is only part of the identity if an identity attribute is defined" do
+        expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
+        resource.x "woo"
+        expect(resource.identity).to eq "woo"
+      end
+    end
+
+    with_property ":x, identity: true, default: 'xxx'",
+                  ":y, identity: true, default: 'yyy'",
+                  ":z, identity: true, default: 'zzz'" do
+      it "identity_property raises an error if multiple identity values are defined" do
+        expect { resource_class.identity_property }.to raise_error Chef::Exceptions::MultipleIdentityError
+      end
+      it "identity_attr raises an error if multiple identity values are defined" do
+        expect { resource_class.identity_attr }.to raise_error Chef::Exceptions::MultipleIdentityError
+      end
+      it "identity returns all identity values in a hash if multiple are defined" do
+        resource.x "foo"
+        resource.y "bar"
+        resource.z "baz"
+        expect(resource.identity).to eq(x: "foo", y: "bar", z: "baz")
+      end
+      it "identity returns all values whether any value is set or not" do
+        expect(resource.identity).to eq(x: "xxx", y: "yyy", z: "zzz")
+      end
+      it "identity_properties wipes out any other identity attributes if multiple are defined" do
+        resource_class.identity_properties :y
+        resource.x "foo"
+        resource.y "bar"
+        resource.z "baz"
+        expect(resource.identity).to eq "bar"
+      end
+    end
+
+    with_property ":x, identity: true, name_property: true" do
+      it "identity when x is not defined returns the value of x" do
+        expect(resource.identity).to eq "blah"
+      end
+      it "state when x is not defined returns the value of x" do
+        expect(resource.state_for_resource_reporter).to eq(x: "blah")
+      end
+    end
+  end
+
+  # state_properties
+  context "Chef::Resource#state_properties" do
+    it "state_properties is empty by default" do
+      expect(Chef::Resource.state_properties).to eq []
+      expect(resource.state_for_resource_reporter).to eq({})
+    end
+
+    with_property ":x", ":y", ":z" do
+      it "x, y and z are state attributes" do
+        resource.x 1
+        resource.y 2
+        resource.z 3
+        expect(resource_class.state_properties).to eq [
+          resource_class.properties[:x],
+          resource_class.properties[:y],
+          resource_class.properties[:z],
+        ]
+        expect(resource.state_for_resource_reporter).to eq(x: 1, y: 2, z: 3)
+      end
+      it "values that are not set are not included in state" do
+        resource.x 1
+        expect(resource.state_for_resource_reporter).to eq(x: 1)
+      end
+      it "when no values are set, nothing is included in state" do
+      end
+    end
+
+    with_property ":x", ":y, desired_state: false", ":z, desired_state: true" do
+      it "x and z are state attributes, and y is not" do
+        resource.x 1
+        resource.y 2
+        resource.z 3
+        expect(resource_class.state_properties).to eq [
+          resource_class.properties[:x],
+          resource_class.properties[:z],
+        ]
+        expect(resource.state_for_resource_reporter).to eq(x: 1, z: 3)
+      end
+    end
+
+    with_property ":x, name_property: true" do
+      # it "Unset values with name_property are included in state" do
+      #   expect(resource.state_for_resource_reporter).to eq({ x: 'blah' })
+      # end
+      it "Set values with name_property are included in state" do
+        resource.x 1
+        expect(resource.state_for_resource_reporter).to eq(x: 1)
+      end
+    end
+
+    with_property ":x, default: 1" do
+      it "Unset values with defaults are not included in state" do
+        expect(resource.state_for_resource_reporter).to eq({})
+      end
+      it "Set values with defaults are included in state" do
+        resource.x 1
+        expect(resource.state_for_resource_reporter).to eq(x: 1)
+      end
+    end
+
+    context "With a class with a normal getter and setter" do
+      before do
+        resource_class.class_eval do
+          def x
+            @blah * 3
+          end
+
+          def x=(value)
+            @blah = value * 2
+          end
+        end
+      end
+      it "state_properties(:x) causes the value to be included in properties" do
+        resource_class.state_properties(:x)
+        resource.x = 1
+
+        expect(resource.x).to eq 6
+        expect(resource.state_for_resource_reporter).to eq(x: 6)
+      end
+    end
+
+    context "When state_properties happens before properties are declared" do
+      before do
+        resource_class.class_eval do
+          state_properties :x
+          property :x
+        end
+      end
+      it "the property works and is in state_properties" do
+        expect(resource_class.state_properties).to include(resource_class.properties[:x])
+        resource.x = 1
+        expect(resource.x).to eq 1
+        expect(resource.state_for_resource_reporter).to eq(x: 1)
+      end
+    end
+
+    with_property ":x, Integer, identity: true" do
+      it "state_properties(:x) leaves the property in desired_state" do
+        resource_class.state_properties(:x)
+        resource.x 10
+
+        expect(resource_class.properties[:x].desired_state?).to be_truthy
+        expect(resource_class.state_properties).to eq [
+          resource_class.properties[:x]
+        ]
+        expect(resource.state_for_resource_reporter).to eq(x: 10)
+      end
+      it "state_properties(:x) does not turn off validation" do
+        resource_class.state_properties(:x)
+        expect { resource.x "ouch" }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+      it "state_properties(:x) does not turn off identity" do
+        resource_class.state_properties(:x)
+        resource.x 10
+
+        expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
+        expect(resource_class.properties[:x].identity?).to be_truthy
+        expect(resource.identity).to eq 10
+      end
+    end
+
+    with_property ":x, Integer, identity: true, desired_state: false" do
+      before do
+        resource_class.class_eval do
+          def y
+            20
+          end
+        end
+      end
+
+      it "state_properties(:x) leaves x identical" do
+        old_value = resource_class.properties[:y]
+        resource_class.state_properties(:x)
+        resource.x 10
+
+        expect(resource_class.properties[:y].object_id).to eq old_value.object_id
+
+        expect(resource_class.properties[:x].desired_state?).to be_truthy
+        expect(resource_class.properties[:x].identity?).to be_truthy
+        expect(resource_class.identity_properties).to eq [
+          resource_class.properties[:x]
+        ]
+        expect(resource.identity).to eq(10)
+        expect(resource_class.state_properties).to eq [
+          resource_class.properties[:x]
+        ]
+        expect(resource.state_for_resource_reporter).to eq(x: 10)
+      end
+
+      it "state_properties(:y) adds y to desired state" do
+        old_value = resource_class.properties[:x]
+        resource_class.state_properties(:y)
+        resource.x 10
+
+        expect(resource_class.properties[:x].object_id).to eq old_value.object_id
+        expect(resource_class.properties[:x].desired_state?).to be_falsey
+        expect(resource_class.properties[:y].desired_state?).to be_truthy
+        expect(resource_class.state_properties).to eq [
+          resource_class.properties[:y]
+        ]
+        expect(resource.state_for_resource_reporter).to eq(y: 20)
+      end
+
+      context "With a subclassed resource" do
+        let(:subresource_class) do
+          new_resource_name = self.class.new_resource_name
+          Class.new(resource_class) do
+            resource_name new_resource_name
+          end
+        end
+        let(:subresource) do
+          subresource_class.new("blah")
+        end
+
+        it "state_properties(:x) adds x to desired state" do
+          old_value = resource_class.properties[:y]
+          subresource_class.state_properties(:x)
+          subresource.x 10
+
+          expect(subresource_class.properties[:y].object_id).to eq old_value.object_id
+
+          expect(subresource_class.properties[:x].desired_state?).to be_truthy
+          expect(subresource_class.properties[:x].identity?).to be_truthy
+          expect(subresource_class.identity_properties).to eq [
+            subresource_class.properties[:x]
+          ]
+          expect(subresource.identity).to eq(10)
+          expect(subresource_class.state_properties).to eq [
+            subresource_class.properties[:x]
+          ]
+          expect(subresource.state_for_resource_reporter).to eq(x: 10)
+        end
+
+        it "state_properties(:y) adds y to desired state" do
+          old_value = resource_class.properties[:x]
+          subresource_class.state_properties(:y)
+          subresource.x 10
+
+          expect(subresource_class.properties[:x].object_id).to eq old_value.object_id
+          expect(subresource_class.properties[:y].desired_state?).to be_truthy
+          expect(subresource_class.state_properties).to eq [
+            subresource_class.properties[:y]
+          ]
+          expect(subresource.state_for_resource_reporter).to eq(y: 20)
+
+          expect(subresource_class.properties[:x].identity?).to be_truthy
+          expect(subresource_class.identity_properties).to eq [
+            subresource_class.properties[:x]
+          ]
+          expect(subresource.identity).to eq(10)
+        end
+      end
+    end
+  end
+
+end
diff --git a/spec/unit/property/validation_spec.rb b/spec/unit/property/validation_spec.rb
new file mode 100644
index 0000000..0b2a8e0
--- /dev/null
+++ b/spec/unit/property/validation_spec.rb
@@ -0,0 +1,704 @@
+require "support/shared/integration/integration_helper"
+
+describe "Chef::Resource.property validation" do
+  include IntegrationSupport
+
+  module Namer
+    @i = 0
+    def self.next_resource_name
+      "chef_resource_property_spec_#{@i += 1}"
+    end
+
+    def self.reset_index
+      @current_index = 0
+    end
+
+    def self.current_index
+      @current_index
+    end
+
+    def self.next_index
+      @current_index += 1
+    end
+  end
+
+  def lazy(&block)
+    Chef::DelayedEvaluator.new(&block)
+  end
+
+  before do
+    Namer.reset_index
+  end
+
+  def self.new_resource_name
+    Namer.next_resource_name
+  end
+
+  let(:resource_class) do
+    new_resource_name = self.class.new_resource_name
+    Class.new(Chef::Resource) do
+      resource_name new_resource_name
+      def blah
+        Namer.next_index
+      end
+
+      def self.blah
+        "class#{Namer.next_index}"
+      end
+    end
+  end
+
+  let(:resource) do
+    resource_class.new("blah")
+  end
+
+  def self.english_join(values)
+    return "<nothing>" if values.size == 0
+    return values[0].inspect if values.size == 1
+    "#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
+  end
+
+  def self.with_property(*properties, &block)
+    tags_index = properties.find_index { |p| !p.is_a?(String) }
+    if tags_index
+      properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
+    else
+      tags = []
+    end
+    properties = properties.map { |property| "property #{property}" }
+    context "With properties #{english_join(properties)}", *tags do
+      before do
+        properties.each do |property_str|
+          resource_class.class_eval(property_str, __FILE__, __LINE__)
+        end
+      end
+      instance_eval(&block)
+    end
+  end
+
+  def self.validation_test(validation, success_values, failure_values, *tags)
+    with_property ":x, #{validation}", *tags do
+      it "gets nil when retrieving the initial (non-set) value" do
+        expect(resource.x).to be_nil
+      end
+      success_values.each do |v|
+        it "value #{v.inspect} is valid" do
+          resource.instance_eval { @x = "default" }
+          expect(resource.x v).to eq v
+          expect(resource.x).to eq v
+        end
+      end
+      failure_values.each do |v|
+        it "value #{v.inspect} is invalid" do
+          expect { resource.x v }.to raise_error Chef::Exceptions::ValidationFailed
+          resource.instance_eval { @x = "default" }
+          expect { resource.x v }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+      end
+      it "setting x to nil when it is already nil does not emit a warning" do
+        expect(resource.x nil).to be_nil
+        expect(resource.x).to be_nil
+      end
+      it "changing x to nil warns that the get will change to a set in Chef 13 and does not change the value" do
+        resource.instance_eval { @x = "default" }
+        expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+          /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+        expect(resource.x nil).to eq "default"
+        expect(resource.x).to eq "default"
+      end
+    end
+    if tags.include?(:nil_is_valid)
+      with_property ":x, #{validation}, default: nil" do
+        it "setting x to nil when it is already nil does not emit a warning" do
+          expect(resource.x nil).to be_nil
+          expect(resource.x).to be_nil
+        end
+        it "changing x to nil warns that the get will change to a set in Chef 13 and does not change the value" do
+          resource.instance_eval { @x = "default" }
+          expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          expect(resource.x nil).to eq "default"
+          expect(resource.x).to eq "default"
+        end
+      end
+    else
+      it "property :x, #{validation}, default: nil warns that the default is invalid" do
+        expect { resource_class.class_eval("property :x, #{validation}, default: nil", __FILE__, __LINE__) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+          /Default value nil is invalid for property x of resource chef_resource_property_spec_(\d+). Possible fixes: 1. Remove 'default: nil' if nil means 'undefined'. 2. Set a valid default value if there is a reasonable one. 3. Allow nil as a valid value of your property \(for example, 'property :x, \[ String, nil \], default: nil'\)./
+      end
+      context "With property :x, #{validation}, default: nil" do
+        before do
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          resource_class.class_eval("property :x, #{validation}, default: nil", __FILE__, __LINE__)
+          Chef::Config[:treat_deprecation_warnings_as_errors] = true
+        end
+
+        it "changing x to nil emits a warning that the value is invalid and does not change the value" do
+          resource.instance_eval { @x = "default" }
+          expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /nil is an invalid value for x of resource chef_resource_property_spec_(\d+). In Chef 13, this warning will change to an error./
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          expect(resource.x nil).to eq "default"
+          expect(resource.x).to eq "default"
+        end
+      end
+    end
+  end
+
+  context "basic get, set, and nil set" do
+    with_property ":x, kind_of: String" do
+      context "when the variable already has a value" do
+        before do
+          resource.instance_eval { @x = "default" }
+        end
+        it "get succeeds" do
+          expect(resource.x).to eq "default"
+        end
+        it "set to valid value succeeds" do
+          expect(resource.x "str").to eq "str"
+          expect(resource.x).to eq "str"
+        end
+        it "set to invalid value raises ValidationFailed" do
+          expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+        it "set to nil emits a deprecation warning and does a get" do
+          expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          resource.x "str"
+          expect(resource.x nil).to eq "str"
+          expect(resource.x).to eq "str"
+        end
+      end
+      context "when the variable does not have an initial value" do
+        it "get succeeds" do
+          expect(resource.x).to be_nil
+        end
+        it "set to valid value succeeds" do
+          expect(resource.x "str").to eq "str"
+          expect(resource.x).to eq "str"
+        end
+        it "set to invalid value raises ValidationFailed" do
+          expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+        it "set to nil emits no warning because the value would not change" do
+          expect(resource.x nil).to be_nil
+        end
+      end
+    end
+    with_property ":x, [ String, nil ]" do
+      context "when the variable already has a value" do
+        before do
+          resource.instance_eval { @x = "default" }
+        end
+        it "get succeeds" do
+          expect(resource.x).to eq "default"
+        end
+        it "set(nil) emits a warning that the value will be set, but does not set the value" do
+          expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /An attempt was made to change x from "default" to nil by calling x\(nil\). In Chef 12, this does a get rather than a set. In Chef 13, this will change to set the value to nil./
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          expect(resource.x nil).to eq "default"
+          expect(resource.x).to eq "default"
+        end
+        it "set to valid value succeeds" do
+          expect(resource.x "str").to eq "str"
+          expect(resource.x).to eq "str"
+        end
+        it "set to invalid value raises ValidationFailed" do
+          expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+      end
+      context "when the variable does not have an initial value" do
+        it "get succeeds" do
+          expect(resource.x).to be_nil
+        end
+        it "set(nil) sets the value" do
+          expect(resource.x nil).to be_nil
+          expect(resource.x).to be_nil
+        end
+        it "set to valid value succeeds" do
+          expect(resource.x "str").to eq "str"
+          expect(resource.x).to eq "str"
+        end
+        it "set to invalid value raises ValidationFailed" do
+          expect { resource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+      end
+    end
+  end
+
+  # Bare types
+  context "bare types" do
+    validation_test "String",
+      [ "hi" ],
+      [ 10 ]
+
+    validation_test ":a",
+      [ :a ],
+      [ :b ]
+
+    validation_test ":a, is: :b",
+      [ :a, :b ],
+      [ :c ]
+
+    validation_test ":a, is: [ :b, :c ]",
+      [ :a, :b, :c ],
+      [ :d ]
+
+    validation_test "[ :a, :b ], is: :c",
+      [ :a, :b, :c ],
+      [ :d ]
+
+    validation_test "[ :a, :b ], is: [ :c, :d ]",
+      [ :a, :b, :c, :d ],
+      [ :e ]
+
+    validation_test "nil",
+      [ ],
+      [ :a ],
+      :nil_is_valid
+
+    validation_test "[ nil ]",
+      [ ],
+      [ :a ],
+      :nil_is_valid
+
+    validation_test "[]",
+      [],
+      [ :a ]
+  end
+
+  # is
+  context "is" do
+    # Class
+    validation_test "is: String",
+      [ "a", "" ],
+      [ :a, 1 ]
+
+    # Value
+    validation_test "is: :a",
+      [ :a ],
+      [ :b ]
+
+    validation_test "is: [ :a, :b ]",
+      [ :a, :b ],
+      [ [ :a, :b ] ]
+
+    validation_test "is: [ [ :a, :b ] ]",
+      [ [ :a, :b ] ],
+      [ :a, :b ]
+
+    # Regex
+    validation_test "is: /abc/",
+      [ "abc", "wowabcwow" ],
+      [ "", "abac" ]
+
+    # Property
+    validation_test "is: Chef::Property.new(is: :a)",
+      [ :a ],
+      [ :b ]
+
+    # RSpec Matcher
+    class Globalses
+      extend RSpec::Matchers
+    end
+
+    validation_test "is: Globalses.eq(10)",
+      [ 10 ],
+      [ 1 ]
+
+    # Proc
+    validation_test "is: proc { |x| x }",
+      [ true, 1 ],
+      [ false ]
+
+    validation_test "is: proc { |x| x > blah }",
+      [ 10 ],
+      [ -1 ]
+
+    validation_test "is: nil",
+      [ ],
+      [ "a" ],
+      :nil_is_valid
+
+    validation_test "is: [ String, nil ]",
+      [ "a" ],
+      [ :b ],
+      :nil_is_valid
+
+    validation_test "is: []",
+      [],
+      [ :a ]
+  end
+
+  # Combination
+  context "combination" do
+    validation_test 'kind_of: String, equal_to: "a"',
+      [ "a" ],
+      [ "b" ],
+      :nil_is_valid
+  end
+
+  # equal_to
+  context "equal_to" do
+    # Value
+    validation_test "equal_to: :a",
+      [ :a ],
+      [ :b ],
+      :nil_is_valid
+
+    validation_test "equal_to: [ :a, :b ]",
+      [ :a, :b ],
+      [ [ :a, :b ] ],
+      :nil_is_valid
+
+    validation_test "equal_to: [ [ :a, :b ] ]",
+      [ [ :a, :b ] ],
+      [ :a, :b ],
+      :nil_is_valid
+
+    validation_test "equal_to: nil",
+      [ ],
+      [ "a" ],
+      :nil_is_valid
+
+    validation_test 'equal_to: [ "a", nil ]',
+      [ "a" ],
+      [ "b" ],
+      :nil_is_valid
+
+    validation_test 'equal_to: [ nil, "a" ]',
+      [ "a" ],
+      [ "b" ],
+      :nil_is_valid
+
+    validation_test "equal_to: []",
+      [],
+      [ :a ],
+      :nil_is_valid
+
+  end
+
+  # kind_of
+  context "kind_of" do
+    validation_test "kind_of: String",
+      [ "a" ],
+      [ :b ],
+      :nil_is_valid
+
+    validation_test "kind_of: [ String, Symbol ]",
+      [ "a", :b ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "kind_of: [ Symbol, String ]",
+      [ "a", :b ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "kind_of: NilClass",
+      [ ],
+      [ "a" ],
+      :nil_is_valid
+
+    validation_test "kind_of: [ NilClass, String ]",
+      [ "a" ],
+      [ :a ],
+      :nil_is_valid
+
+    validation_test "kind_of: []",
+      [],
+      [ :a ],
+      :nil_is_valid
+
+    validation_test "kind_of: nil",
+      [],
+      [ :a ],
+      :nil_is_valid
+  end
+
+  # regex
+  context "regex" do
+    validation_test "regex: /abc/",
+      [ "xabcy" ],
+      [ "gbh", 123 ],
+      :nil_is_valid
+
+    validation_test "regex: [ /abc/, /z/ ]",
+      [ "xabcy", "aza" ],
+      [ "gbh", 123 ],
+      :nil_is_valid
+
+    validation_test "regex: [ /z/, /abc/ ]",
+      [ "xabcy", "aza" ],
+      [ "gbh", 123 ],
+      :nil_is_valid
+
+    validation_test "regex: [ [ /z/, /abc/ ], [ /n/ ] ]",
+      [ "xabcy", "aza", "ana" ],
+      [ "gbh", 123 ],
+      :nil_is_valid
+
+    validation_test "regex: []",
+      [],
+      [ :a ],
+      :nil_is_valid
+
+    validation_test "regex: nil",
+      [],
+      [ :a ],
+      :nil_is_valid
+  end
+
+  # callbacks
+  context "callbacks" do
+    validation_test 'callbacks: { "a" => proc { |x| x > 10 }, "b" => proc { |x| x%2 == 0 } }',
+      [ 12 ],
+      [ 11, 4 ],
+      :nil_is_valid
+
+    validation_test 'callbacks: { "a" => proc { |x| x%2 == 0 }, "b" => proc { |x| x > 10 } }',
+      [ 12 ],
+      [ 11, 4 ],
+      :nil_is_valid
+
+    validation_test 'callbacks: { "a" => proc { |x| x.nil? } }',
+      [ ],
+      [ "a" ],
+      :nil_is_valid
+
+    validation_test "callbacks: {}",
+      [ :a ],
+      [],
+      :nil_is_valid
+  end
+
+  # respond_to
+  context "respond_to" do
+    validation_test "respond_to: :split",
+      [ "hi" ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test 'respond_to: "split"',
+      [ "hi" ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "respond_to: :to_s",
+      [ :a ],
+      [],
+      :nil_is_valid
+
+    validation_test "respond_to: [ :split, :to_s ]",
+      [ "hi" ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "respond_to: %w(split to_s)",
+      [ "hi" ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "respond_to: [ :to_s, :split ]",
+      [ "hi" ],
+      [ 1 ],
+      :nil_is_valid
+
+    validation_test "respond_to: []",
+      [ :a ],
+      [],
+      :nil_is_valid
+
+    validation_test "respond_to: nil",
+      [ :a ],
+      [],
+      :nil_is_valid
+  end
+
+  context "cannot_be" do
+    validation_test "cannot_be: :empty",
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test 'cannot_be: "empty"',
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test "cannot_be: [ :empty, :nil ]",
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test 'cannot_be: [ "empty", "nil" ]',
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test "cannot_be: [ :nil, :empty ]",
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test "cannot_be: [ :empty, :nil, :blahblah ]",
+      [ 1, [1, 2], { a: 10 } ],
+      [ [] ],
+      :nil_is_valid
+
+    validation_test "cannot_be: []",
+      [ :a ],
+      [],
+      :nil_is_valid
+
+    validation_test "cannot_be: nil",
+      [ :a ],
+      [],
+      :nil_is_valid
+
+  end
+
+  context "required" do
+    with_property ":x, required: true" do
+      it "if x is not specified, retrieval fails" do
+        expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+      it "value 1 is valid" do
+        expect(resource.x 1).to eq 1
+        expect(resource.x).to eq 1
+      end
+      it "value nil emits a validation failed error because it must have a value" do
+        expect { resource.x nil }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+      context "and value is set to something other than nil" do
+        before { resource.x 10 }
+        it "value nil emits a deprecation warning and does a get" do
+          expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          resource.x 1
+          expect(resource.x nil).to eq 1
+          expect(resource.x).to eq 1
+        end
+      end
+    end
+
+    with_property ":x, [String, nil], required: true" do
+      it "if x is not specified, retrieval fails" do
+        expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+      it "value nil is not valid (required means 'not nil')" do
+        expect { resource.x nil }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+      it "value '1' is valid" do
+        expect(resource.x "1").to eq "1"
+        expect(resource.x).to eq "1"
+      end
+      it "value 1 is invalid" do
+        expect { resource.x 1 }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+    end
+
+    with_property ":x, name_property: true, required: true" do
+      it "if x is not specified, the name property is returned" do
+        expect(resource.x).to eq "blah"
+      end
+      it "value 1 is valid" do
+        expect(resource.x 1).to eq 1
+        expect(resource.x).to eq 1
+      end
+      it "value nil emits a deprecation warning and does a get" do
+        expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+        resource.x 1
+        expect(resource.x nil).to eq 1
+        expect(resource.x).to eq 1
+      end
+    end
+
+    with_property ":x, default: 10, required: true" do
+      it "if x is not specified, the default is returned" do
+        expect(resource.x).to eq 10
+      end
+      it "value 1 is valid" do
+        expect(resource.x 1).to eq 1
+        expect(resource.x).to eq 1
+      end
+      it "value nil is invalid" do
+        expect { resource.x nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+        Chef::Config[:treat_deprecation_warnings_as_errors] = false
+        resource.x 1
+        expect(resource.x nil).to eq 1
+        expect(resource.x).to eq 1
+      end
+    end
+  end
+
+  context "custom validators (def _pv_blarghle)" do
+    before do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+    end
+
+    with_property ":x, blarghle: 1" do
+      context "and a class that implements _pv_blarghle" do
+        before do
+          resource_class.class_eval do
+            def _pv_blarghle(opts, key, value)
+              if _pv_opts_lookup(opts, key) != value
+                raise Chef::Exceptions::ValidationFailed, "ouch"
+              end
+            end
+          end
+        end
+
+        it "value 1 is valid" do
+          expect(resource.x 1).to eq 1
+          expect(resource.x).to eq 1
+        end
+
+        it "value '1' is invalid" do
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          expect { resource.x "1" }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+
+        it "value nil does a get" do
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          resource.x 1
+          resource.x nil
+          expect(resource.x).to eq 1
+        end
+      end
+    end
+
+    with_property ":x, blarghle: 1" do
+      context "and a class that implements _pv_blarghle" do
+        before do
+          resource_class.class_eval do
+            def _pv_blarghle(opts, key, value)
+              if _pv_opts_lookup(opts, key) != value
+                raise Chef::Exceptions::ValidationFailed, "ouch"
+              end
+            end
+          end
+        end
+
+        it "value 1 is valid" do
+          expect(resource.x 1).to eq 1
+          expect(resource.x).to eq 1
+        end
+
+        it "value '1' is invalid" do
+          expect { resource.x "1" }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+
+        it "value nil does a get" do
+          resource.x 1
+          resource.x nil
+          expect(resource.x).to eq 1
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/property_spec.rb b/spec/unit/property_spec.rb
new file mode 100644
index 0000000..ecea666
--- /dev/null
+++ b/spec/unit/property_spec.rb
@@ -0,0 +1,1227 @@
+require "support/shared/integration/integration_helper"
+
+describe "Chef::Resource.property" do
+  include IntegrationSupport
+
+  module Namer
+    @i = 0
+    def self.next_resource_name
+      "chef_resource_property_spec_#{@i += 1}"
+    end
+
+    def self.reset_index
+      @current_index = 0
+    end
+
+    def self.current_index
+      @current_index
+    end
+
+    def self.next_index
+      @current_index += 1
+    end
+  end
+
+  def lazy(&block)
+    Chef::DelayedEvaluator.new(&block)
+  end
+
+  before do
+    Namer.reset_index
+  end
+
+  def self.new_resource_name
+    Namer.next_resource_name
+  end
+
+  let(:resource_class) do
+    new_resource_name = self.class.new_resource_name
+    Class.new(Chef::Resource) do
+      resource_name new_resource_name
+      def next_index
+        Namer.next_index
+      end
+    end
+  end
+
+  let(:resource) do
+    resource_class.new("blah")
+  end
+
+  def self.english_join(values)
+    return "<nothing>" if values.size == 0
+    return values[0].inspect if values.size == 1
+    "#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
+  end
+
+  def self.with_property(*properties, &block)
+    tags_index = properties.find_index { |p| !p.is_a?(String) }
+    if tags_index
+      properties, tags = properties[0..tags_index - 1], properties[tags_index..-1]
+    else
+      tags = []
+    end
+    if properties.size == 1
+      description = "With property #{properties.first}"
+    else
+      description = "With properties #{english_join(properties.map { |property| "#{property.inspect}" })}"
+    end
+    context description, *tags do
+      before do
+        properties.each do |property_str|
+          resource_class.class_eval("property #{property_str}", __FILE__, __LINE__)
+        end
+      end
+      instance_eval(&block)
+    end
+  end
+
+  # Basic properties
+  with_property ":bare_property" do
+    it "can be set" do
+      expect(resource.bare_property 10).to eq 10
+      expect(resource.bare_property).to eq 10
+    end
+    it "emits a deprecation warning and does a get, if set to nil" do
+      expect(resource.bare_property 10).to eq 10
+      expect { resource.bare_property nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      expect(resource.bare_property nil).to eq 10
+      expect(resource.bare_property).to eq 10
+    end
+    it "can be updated" do
+      expect(resource.bare_property 10).to eq 10
+      expect(resource.bare_property 20).to eq 20
+      expect(resource.bare_property).to eq 20
+    end
+    it "can be set with =" do
+      expect(resource.bare_property 10).to eq 10
+      expect(resource.bare_property).to eq 10
+    end
+    it "can be set to nil with =" do
+      expect(resource.bare_property 10).to eq 10
+      expect(resource.bare_property = nil).to be_nil
+      expect(resource.bare_property).to be_nil
+    end
+    it "can be updated with =" do
+      expect(resource.bare_property 10).to eq 10
+      expect(resource.bare_property = 20).to eq 20
+      expect(resource.bare_property).to eq 20
+    end
+  end
+
+  with_property ":x, name_property: true" do
+    context "and subclass" do
+      let(:subresource_class) do
+        new_resource_name = self.class.new_resource_name
+        Class.new(resource_class) do
+          resource_name new_resource_name
+        end
+      end
+      let(:subresource) do
+        subresource_class.new("blah")
+      end
+
+      context "with property :x on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x
+          end
+        end
+
+        it "x is still name_property" do
+          expect(subresource.x).to eq "blah"
+        end
+      end
+
+      context "with property :x, name_attribute: false on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x, name_attribute: false
+          end
+        end
+
+        it "x is no longer name_property" do
+          expect(subresource.x).to be_nil
+        end
+      end
+
+      context "with property :x, default: 10 on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x, default: 10
+          end
+        end
+
+        it "x is no longer name_property" do
+          expect(subresource.x).to eq(10)
+        end
+      end
+    end
+  end
+
+  with_property ":x, Integer" do
+    context "and subclass" do
+      let(:subresource_class) do
+        new_resource_name = self.class.new_resource_name
+        Class.new(resource_class) do
+          resource_name new_resource_name
+        end
+      end
+      let(:subresource) do
+        subresource_class.new("blah")
+      end
+
+      it "x is inherited" do
+        expect(subresource.x 10).to eq 10
+        expect(subresource.x).to eq 10
+        expect(subresource.x = 20).to eq 20
+        expect(subresource.x).to eq 20
+        expect(subresource_class.properties[:x]).not_to be_nil
+      end
+
+      it "x's validation is inherited" do
+        expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
+      end
+
+      context "with property :y on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :y
+          end
+        end
+
+        it "x is still there" do
+          expect(subresource.x 10).to eq 10
+          expect(subresource.x).to eq 10
+          expect(subresource.x = 20).to eq 20
+          expect(subresource.x).to eq 20
+          expect(subresource_class.properties[:x]).not_to be_nil
+        end
+        it "y is there" do
+          expect(subresource.y 10).to eq 10
+          expect(subresource.y).to eq 10
+          expect(subresource.y = 20).to eq 20
+          expect(subresource.y).to eq 20
+          expect(subresource_class.properties[:y]).not_to be_nil
+        end
+        it "y is not on the superclass" do
+          expect { resource_class.y 10 }.to raise_error NoMethodError
+          expect(resource_class.properties[:y]).to be_nil
+        end
+      end
+
+      context "with property :x on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x
+          end
+        end
+
+        it "x is still there" do
+          expect(subresource.x 10).to eq 10
+          expect(subresource.x).to eq 10
+          expect(subresource.x = 20).to eq 20
+          expect(subresource.x).to eq 20
+          expect(subresource_class.properties[:x]).not_to be_nil
+          expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
+        end
+
+        it "x's validation is inherited" do
+          expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+      end
+
+      context "with property :x, default: 80 on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x, default: 80
+          end
+        end
+
+        it "x is still there" do
+          expect(subresource.x 10).to eq 10
+          expect(subresource.x).to eq 10
+          expect(subresource.x = 20).to eq 20
+          expect(subresource.x).to eq 20
+          expect(subresource_class.properties[:x]).not_to be_nil
+          expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
+        end
+
+        it "x defaults to 80" do
+          expect(subresource.x).to eq 80
+        end
+
+        it "x's validation is inherited" do
+          expect { subresource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
+        end
+      end
+
+      context "with property :x, String on the subclass" do
+        before do
+          subresource_class.class_eval do
+            property :x, String
+          end
+        end
+
+        it "x is still there" do
+          expect(subresource.x "10").to eq "10"
+          expect(subresource.x).to eq "10"
+          expect(subresource.x = "20").to eq "20"
+          expect(subresource.x).to eq "20"
+          expect(subresource_class.properties[:x]).not_to be_nil
+          expect(subresource_class.properties[:x]).not_to eq resource_class.properties[:x]
+        end
+
+        it "x's validation is overwritten" do
+          expect { subresource.x 10 }.to raise_error Chef::Exceptions::ValidationFailed
+          expect(subresource.x "ohno").to eq "ohno"
+          expect(subresource.x).to eq "ohno"
+        end
+
+        it "the superclass's validation for x is still there" do
+          expect { resource.x "ohno" }.to raise_error Chef::Exceptions::ValidationFailed
+          expect(resource.x 10).to eq 10
+          expect(resource.x).to eq 10
+        end
+      end
+    end
+  end
+
+  context "Chef::Resource::Property#reset_property" do
+    it "when a resource is newly created, reset_property(:name) sets property to nil" do
+      expect(resource.property_is_set?(:name)).to be_truthy
+      resource.reset_property(:name)
+      expect(resource.property_is_set?(:name)).to be_falsey
+      expect(resource.name).to be_nil
+    end
+
+    it "when referencing an undefined property, reset_property(:x) raises an error" do
+      expect { resource.reset_property(:x) }.to raise_error(ArgumentError)
+    end
+
+    with_property ":x" do
+      it "when the resource is newly created, reset_property(:x) does nothing" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to be_nil
+      end
+      it "when x is set, reset_property resets it" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to be_nil
+      end
+    end
+
+    with_property ":x, Integer" do
+      it "when the resource is newly created, reset_property(:x) does nothing" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to be_nil
+      end
+      it "when x is set, reset_property resets it even though `nil` is technically invalid" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to be_nil
+      end
+    end
+
+    with_property ":x, default: 10" do
+      it "when the resource is newly created, reset_property(:x) does nothing" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to eq 10
+      end
+      it "when x is set, reset_property resets it and it returns the default" do
+        resource.x 20
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to eq 10
+      end
+    end
+
+    with_property ":x, default: lazy { 10 }" do
+      it "when the resource is newly created, reset_property(:x) does nothing" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to eq 10
+      end
+      it "when x is set, reset_property resets it and it returns the default" do
+        resource.x 20
+        resource.reset_property(:x)
+        expect(resource.property_is_set?(:x)).to be_falsey
+        expect(resource.x).to eq 10
+      end
+    end
+  end
+
+  context "Chef::Resource::Property#property_is_set?" do
+    it "when a resource is newly created, property_is_set?(:name) is true" do
+      expect(resource.property_is_set?(:name)).to be_truthy
+    end
+
+    it "when referencing an undefined property, property_is_set?(:x) raises an error" do
+      expect { resource.property_is_set?(:x) }.to raise_error(ArgumentError)
+    end
+
+    with_property ":x" do
+      it "when the resource is newly created, property_is_set?(:x) is false" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+      it "when x is set, property_is_set?(:x) is true" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set with =, property_is_set?(:x) is true" do
+        resource.x = 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set to a lazy value, property_is_set?(:x) is true" do
+        resource.x lazy { 10 }
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is retrieved, property_is_set?(:x) is false" do
+        resource.x
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+    end
+
+    with_property ":x, default: 10" do
+      it "when the resource is newly created, property_is_set?(:x) is false" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+      it "when x is set, property_is_set?(:x) is true" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set with =, property_is_set?(:x) is true" do
+        resource.x = 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set to a lazy value, property_is_set?(:x) is true" do
+        resource.x lazy { 10 }
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is retrieved, property_is_set?(:x) is false" do
+        resource.x
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+    end
+
+    with_property ":x, default: nil" do
+      it "when the resource is newly created, property_is_set?(:x) is false" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+      it "when x is set, property_is_set?(:x) is true" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set with =, property_is_set?(:x) is true" do
+        resource.x = 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set to a lazy value, property_is_set?(:x) is true" do
+        resource.x lazy { 10 }
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is retrieved, property_is_set?(:x) is false" do
+        resource.x
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+    end
+
+    with_property ":x, default: lazy { 10 }" do
+      it "when the resource is newly created, property_is_set?(:x) is false" do
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+      it "when x is set, property_is_set?(:x) is true" do
+        resource.x 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is set with =, property_is_set?(:x) is true" do
+        resource.x = 10
+        expect(resource.property_is_set?(:x)).to be_truthy
+      end
+      it "when x is retrieved, property_is_set?(:x) is false" do
+        resource.x
+        expect(resource.property_is_set?(:x)).to be_falsey
+      end
+    end
+  end
+
+  context "Chef::Resource::Property#default" do
+    with_property ":x, default: 10" do
+      it "when x is set, it returns its value" do
+        expect(resource.x 20).to eq 20
+        expect(resource.property_is_set?(:x)).to be_truthy
+        expect(resource.x).to eq 20
+      end
+      it "when x is not set, it returns 10" do
+        expect(resource.x).to eq 10
+      end
+      it "when x is not set, it is not included in state" do
+        expect(resource.state_for_resource_reporter).to eq({})
+      end
+      it "when x is set to nil, it returns nil" do
+        resource.instance_eval { @x = nil }
+        expect(resource.x).to be_nil
+      end
+
+      context "With a subclass" do
+        let(:subresource_class) do
+          new_resource_name = self.class.new_resource_name
+          Class.new(resource_class) do
+            resource_name new_resource_name
+          end
+        end
+        let(:subresource) { subresource_class.new("blah") }
+        it "The default is inherited" do
+          expect(subresource.x).to eq 10
+        end
+      end
+    end
+
+    with_property ":x, default: 10, identity: true" do
+      it "when x is not set, it is included in identity" do
+        expect(resource.identity).to eq(10)
+      end
+    end
+
+    with_property ":x, default: 1, identity: true", ":y, default: 2, identity: true" do
+      it "when x is not set, it is still included in identity" do
+        resource.y 20
+        expect(resource.identity).to eq(x: 1, y: 20)
+      end
+    end
+
+    with_property ":x, default: nil" do
+      it "when x is not set, it returns nil" do
+        expect(resource.x).to be_nil
+      end
+    end
+
+    with_property ":x" do
+      it "when x is not set, it returns nil" do
+        expect(resource.x).to be_nil
+      end
+    end
+
+    context "hash default" do
+      context "(deprecations allowed)" do
+        before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
+
+        with_property ":x, default: {}" do
+          it "when x is not set, it returns {}" do
+            expect(resource.x).to eq({})
+          end
+          it "The same exact value is returned multiple times in a row" do
+            value = resource.x
+            expect(value).to eq({})
+            expect(resource.x.object_id).to eq(value.object_id)
+          end
+          it "Multiple instances of x receive the exact same value" do
+            expect(resource.x.object_id).to eq(resource_class.new("blah2").x.object_id)
+          end
+        end
+      end
+
+      with_property ":x, default: lazy { {} }" do
+        it "when x is not set, it returns {}" do
+          expect(resource.x).to eq({})
+        end
+        # it "The value is different each time it is called" do
+        #   value = resource.x
+        #   expect(value).to eq({})
+        #   expect(resource.x.object_id).not_to eq(value.object_id)
+        # end
+        it "Multiple instances of x receive different values" do
+          expect(resource.x.object_id).not_to eq(resource_class.new("blah2").x.object_id)
+        end
+      end
+    end
+
+    context "with a class with 'blah' as both class and instance methods" do
+      before do
+        resource_class.class_eval do
+          def self.blah
+            "class"
+          end
+
+          def blah
+            "#{name}#{next_index}"
+          end
+        end
+      end
+
+      with_property ":x, default: lazy { blah }" do
+        it "x is run in context of the instance" do
+          expect(resource.x).to eq "blah1"
+        end
+        it "x is run in the context of each instance it is run in" do
+          expect(resource.x).to eq "blah1"
+          expect(resource_class.new("another").x).to eq "another2"
+          # expect(resource.x).to eq "blah3"
+        end
+      end
+
+      with_property ':x, default: lazy { |x| "#{blah}#{x.blah}" }' do
+        it "x is run in context of the class (where it was defined) and passed the instance" do
+          expect(resource.x).to eq "classblah1"
+        end
+        it "x is passed the value of each instance it is run in" do
+          expect(resource.x).to eq "classblah1"
+          expect(resource_class.new("another").x).to eq "classanother2"
+          # expect(resource.x).to eq "classblah3"
+        end
+      end
+    end
+
+    context "validation of defaults" do
+      it "When a class is declared with property :x, String, default: 10, a warning is emitted" do
+        expect { resource_class.class_eval { property :x, String, default: 10 } }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+          /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: String!  You passed 10./
+      end
+      context "With property :x, String, default: 10" do
+        before do
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          resource_class.class_eval { property :x, String, default: 10 }
+          Chef::Config[:treat_deprecation_warnings_as_errors] = true
+        end
+
+        it "when x is set, no error is raised" do
+          expect(resource.x "hi").to eq "hi"
+          expect(resource.x).to eq "hi"
+        end
+        it "when x is retrieved, no validation error is raised" do
+          expect(resource.x).to eq 10
+        end
+      end
+
+      with_property ":x, String, default: lazy { Namer.next_index }" do
+        it "when the resource is created, no error is raised" do
+          resource
+        end
+        it "when x is set, no error is raised" do
+          expect(resource.x "hi").to eq "hi"
+          expect(resource.x).to eq "hi"
+        end
+        it "when x is retrieved, an invalid default warning is emitted and the value is returned" do
+          expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /Default value 1 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: String!  You passed 1./
+          expect(Namer.current_index).to eq 1
+          Chef::Config[:treat_deprecation_warnings_as_errors] = false
+          expect(resource.x).to eq 2
+        end
+      end
+
+      with_property ":x, default: lazy { Namer.next_index.to_s }, is: proc { |v| Namer.next_index; true }" do
+        it "coercion and validation is only run the first time" do
+          expect(resource.x).to eq "1"
+          expect(Namer.current_index).to eq 2
+          expect(resource.x).to eq "1"
+          expect(Namer.current_index).to eq 2
+        end
+      end
+
+      with_property ":x, default: lazy { Namer.next_index.to_s.freeze }, is: proc { |v| Namer.next_index; true }" do
+        it "coercion and validation is run each time" do
+          expect(resource.x).to eq "1"
+          expect(Namer.current_index).to eq 2
+          expect(resource.x).to eq "3"
+          expect(Namer.current_index).to eq 4
+        end
+      end
+    end
+
+    context "coercion of defaults" do
+      # Frozen default, non-frozen coerce
+      with_property ':x, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
+        it "when the resource is created, the proc is not yet run" do
+          resource
+          expect(Namer.current_index).to eq 0
+        end
+        it "when x is set, coercion is run" do
+          expect(resource.x "hi").to eq "hi1"
+          expect(resource.x).to eq "hi1"
+          expect(Namer.current_index).to eq 1
+        end
+        it "when x is retrieved, coercion is run exactly once" do
+          expect(resource.x).to eq "101"
+          expect(resource.x).to eq "101"
+          expect(Namer.current_index).to eq 1
+        end
+      end
+
+      # Frozen default, frozen coerce
+      with_property ':x, coerce: proc { |v| "#{v}#{next_index}".freeze }, default: 10' do
+        it "when the resource is created, the proc is not yet run" do
+          resource
+          expect(Namer.current_index).to eq 0
+        end
+        it "when x is set, coercion is run" do
+          expect(resource.x "hi").to eq "hi1"
+          expect(resource.x).to eq "hi1"
+          expect(Namer.current_index).to eq 1
+        end
+        it "when x is retrieved, coercion is run each time" do
+          expect(resource.x).to eq "101"
+          expect(resource.x).to eq "102"
+          expect(Namer.current_index).to eq 2
+        end
+      end
+
+      # Frozen lazy default, non-frozen coerce
+      with_property ':x, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
+        it "when the resource is created, the proc is not yet run" do
+          resource
+          expect(Namer.current_index).to eq 0
+        end
+        it "when x is set, coercion is run" do
+          expect(resource.x "hi").to eq "hi1"
+          expect(resource.x).to eq "hi1"
+          expect(Namer.current_index).to eq 1
+        end
+        it "when x is retrieved, coercion is run exactly once" do
+          expect(resource.x).to eq "101"
+          expect(resource.x).to eq "101"
+          expect(Namer.current_index).to eq 1
+        end
+      end
+
+      # Non-frozen lazy default, frozen coerce
+      with_property ':x, coerce: proc { |v| "#{v}#{next_index}".freeze }, default: lazy { "10" }' do
+        it "when the resource is created, the proc is not yet run" do
+          resource
+          expect(Namer.current_index).to eq 0
+        end
+        it "when x is set, coercion is run" do
+          expect(resource.x "hi").to eq "hi1"
+          expect(resource.x).to eq "hi1"
+          expect(Namer.current_index).to eq 1
+        end
+        it "when x is retrieved, coercion is run each time" do
+          expect(resource.x).to eq "101"
+          expect(resource.x).to eq "102"
+          expect(Namer.current_index).to eq 2
+        end
+      end
+
+      with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
+        it "coercion and validation is only run the first time x is retrieved" do
+          expect(Namer.current_index).to eq 0
+          expect(resource.x).to eq "101"
+          expect(Namer.current_index).to eq 2
+          expect(resource.x).to eq "101"
+          expect(Namer.current_index).to eq 2
+        end
+      end
+
+      context "validation and coercion of defaults" do
+        with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
+          it "when x is retrieved, it is coerced before validating and passes" do
+            expect(resource.x).to eq "101"
+          end
+        end
+        with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: 10' do
+          it "when x is retrieved, it is coerced and emits an invalid default warning, but still returns the value" do
+            expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+              /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: Integer!  You passed "101"./
+            Chef::Config[:treat_deprecation_warnings_as_errors] = false
+            expect(resource.x).to eq "102"
+          end
+        end
+        with_property ':x, String, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
+          it "when x is retrieved, it is coerced before validating and passes" do
+            expect(resource.x).to eq "101"
+          end
+        end
+        with_property ':x, Integer, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
+          it "when x is retrieved, it is coerced and emits an invalid default warning; the value is still returned." do
+            expect { resource.x }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+              /Default value 10 is invalid for property x of resource chef_resource_property_spec_(\d+). In Chef 13 this will become an error: Property x must be one of: Integer!  You passed "101"./
+            Chef::Config[:treat_deprecation_warnings_as_errors] = false
+            expect(resource.x).to eq "102"
+          end
+        end
+        with_property ':x, proc { |v| Namer.next_index; true }, coerce: proc { |v| "#{v}#{next_index}" }, default: lazy { 10 }' do
+          it "coercion is only run the first time x is retrieved, and validation is run" do
+            expect(Namer.current_index).to eq 0
+            expect(resource.x).to eq "101"
+            expect(Namer.current_index).to eq 2
+            expect(resource.x).to eq "101"
+            expect(Namer.current_index).to eq 2
+          end
+        end
+      end
+    end
+  end
+
+  context "Chef::Resource#lazy" do
+    with_property ":x" do
+      it "setting x to a lazy value does not run it immediately" do
+        resource.x lazy { Namer.next_index }
+        expect(Namer.current_index).to eq 0
+      end
+      it "you can set x to a lazy value in the instance" do
+        resource.instance_eval do
+          x lazy { Namer.next_index }
+        end
+        expect(resource.x).to eq 1
+        expect(Namer.current_index).to eq 1
+      end
+      it "retrieving a lazy value pops it open" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq 1
+        expect(Namer.current_index).to eq 1
+      end
+      it "retrieving a lazy value twice evaluates it twice" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq 1
+        expect(resource.x).to eq 2
+        expect(Namer.current_index).to eq 2
+      end
+      it "setting the same lazy value on two different instances runs it on each instancee" do
+        resource2 = resource_class.new("blah2")
+        l = lazy { Namer.next_index }
+        resource.x l
+        resource2.x l
+        expect(resource2.x).to eq 1
+        expect(resource.x).to eq 2
+        expect(resource2.x).to eq 3
+      end
+
+      context "when the class has a class and instance method named blah" do
+        before do
+          resource_class.class_eval do
+            def self.blah
+              "class"
+            end
+
+            def blah
+              "#{name}#{Namer.next_index}"
+            end
+          end
+        end
+        def blah
+          "example"
+        end
+        # it "retrieving lazy { blah } gets the instance variable" do
+        #   resource.x lazy { blah }
+        #   expect(resource.x).to eq "blah1"
+        # end
+        # it "retrieving lazy { blah } from two different instances gets two different instance variables" do
+        #   resource2 = resource_class.new("another")
+        #   l = lazy { blah }
+        #   resource2.x l
+        #   resource.x l
+        #   expect(resource2.x).to eq "another1"
+        #   expect(resource.x).to eq "blah2"
+        #   expect(resource2.x).to eq "another3"
+        # end
+        it 'retrieving lazy { |x| "#{blah}#{x.blah}" } gets the example and instance variables' do
+          resource.x lazy { |x| "#{blah}#{x.blah}" }
+          expect(resource.x).to eq "exampleblah1"
+        end
+        it 'retrieving lazy { |x| "#{blah}#{x.blah}" } from two different instances gets two different instance variables' do
+          resource2 = resource_class.new("another")
+          l = lazy { |x| "#{blah}#{x.blah}" }
+          resource2.x l
+          resource.x l
+          expect(resource2.x).to eq "exampleanother1"
+          expect(resource.x).to eq "exampleblah2"
+          expect(resource2.x).to eq "exampleanother3"
+        end
+      end
+    end
+
+    with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
+      it "lazy values are not coerced on set" do
+        resource.x lazy { Namer.next_index }
+        expect(Namer.current_index).to eq 0
+      end
+      it "lazy values are coerced on get" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq "12"
+        expect(Namer.current_index).to eq 2
+      end
+      it "lazy values are coerced on each access" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq "12"
+        expect(Namer.current_index).to eq 2
+        expect(resource.x).to eq "34"
+        expect(Namer.current_index).to eq 4
+      end
+    end
+
+    with_property ":x, String" do
+      it "lazy values are not validated on set" do
+        resource.x lazy { Namer.next_index }
+        expect(Namer.current_index).to eq 0
+      end
+      it "lazy values are validated on get" do
+        resource.x lazy { Namer.next_index }
+        expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
+        expect(Namer.current_index).to eq 1
+      end
+    end
+
+    with_property ":x, is: proc { |v| Namer.next_index; true }" do
+      it "lazy values are validated on each access" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq 1
+        expect(Namer.current_index).to eq 2
+        expect(resource.x).to eq 3
+        expect(Namer.current_index).to eq 4
+      end
+    end
+
+    with_property ':x, Integer, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
+      it "lazy values are not validated or coerced on set" do
+        resource.x lazy { Namer.next_index }
+        expect(Namer.current_index).to eq 0
+      end
+      it "lazy values are coerced before being validated, which fails" do
+        resource.x lazy { Namer.next_index }
+        expect(Namer.current_index).to eq 0
+        expect { resource.x }.to raise_error Chef::Exceptions::ValidationFailed
+        expect(Namer.current_index).to eq 2
+      end
+    end
+
+    with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }, is: proc { |v| Namer.next_index; true }' do
+      it "lazy values are coerced and validated exactly once" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq "12"
+        expect(Namer.current_index).to eq 3
+        expect(resource.x).to eq "45"
+        expect(Namer.current_index).to eq 6
+      end
+    end
+
+    with_property ':x, String, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
+      it "lazy values are coerced before being validated, which succeeds" do
+        resource.x lazy { Namer.next_index }
+        expect(resource.x).to eq "12"
+        expect(Namer.current_index).to eq 2
+      end
+    end
+  end
+
+  context "Chef::Resource::Property#coerce" do
+    with_property ':x, coerce: proc { |v| "#{v}#{Namer.next_index}" }' do
+      it "coercion runs on set" do
+        expect(resource.x 10).to eq "101"
+        expect(Namer.current_index).to eq 1
+      end
+      it "does not emit a deprecation warning if set to nil" do
+        # nil is never coerced
+        expect(resource.x nil).to be_nil
+      end
+      it "coercion sets the value (and coercion does not run on get)" do
+        expect(resource.x 10).to eq "101"
+        expect(resource.x).to eq "101"
+        expect(Namer.current_index).to eq 1
+      end
+      it "coercion runs each time set happens" do
+        expect(resource.x 10).to eq "101"
+        expect(Namer.current_index).to eq 1
+        expect(resource.x 10).to eq "102"
+        expect(Namer.current_index).to eq 2
+      end
+    end
+    with_property ":x, coerce: proc { |x| x }" do
+      it "does not emit a deprecation warning if set to nil" do
+        expect(resource.x nil).to be_nil
+      end
+    end
+    with_property ':x, coerce: proc { |x| Namer.next_index; raise "hi" if x == 10; x }, is: proc { |x| Namer.next_index; x != 10 }' do
+      it "failed coercion fails to set the value" do
+        resource.x 20
+        expect(resource.x).to eq 20
+        expect(Namer.current_index).to eq 2
+        expect { resource.x 10 }.to raise_error "hi"
+        expect(resource.x).to eq 20
+        expect(Namer.current_index).to eq 3
+      end
+      it "validation does not run if coercion fails" do
+        expect { resource.x 10 }.to raise_error "hi"
+        expect(Namer.current_index).to eq 1
+      end
+    end
+  end
+
+  context "Chef::Resource::Property validation" do
+    with_property ":x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }" do
+      it "validation runs on set" do
+        expect(resource.x 10).to eq 10
+        expect(Namer.current_index).to eq 1
+      end
+      it "validation sets the value (and validation does not run on get)" do
+        expect(resource.x 10).to eq 10
+        expect(resource.x).to eq 10
+        expect(Namer.current_index).to eq 1
+      end
+      it "validation runs each time set happens" do
+        expect(resource.x 10).to eq 10
+        expect(Namer.current_index).to eq 1
+        expect(resource.x 10).to eq 10
+        expect(Namer.current_index).to eq 2
+      end
+      it "failed validation fails to set the value" do
+        expect(resource.x 10).to eq 10
+        expect(Namer.current_index).to eq 1
+        expect { resource.x "blah" }.to raise_error Chef::Exceptions::ValidationFailed
+        expect(resource.x).to eq 10
+        expect(Namer.current_index).to eq 2
+      end
+    end
+  end
+
+  [ "name_attribute", "name_property" ].each do |name|
+    context "Chef::Resource::Property##{name}" do
+      with_property ":x, #{name}: true" do
+        it "defaults x to resource.name" do
+          expect(resource.x).to eq "blah"
+        end
+        it "does not pick up resource.name if set" do
+          expect(resource.x 10).to eq 10
+          expect(resource.x).to eq 10
+        end
+        it "binds to the latest resource.name when run" do
+          resource.name "foo"
+          expect(resource.x).to eq "foo"
+        end
+        it "caches resource.name" do
+          expect(resource.x).to eq "blah"
+          resource.name "foo"
+          expect(resource.x).to eq "blah"
+        end
+      end
+
+      with_property ":x, #{name}: false" do
+        it "defaults to nil" do
+          expect(resource.x).to be_nil
+        end
+      end
+
+      with_property ":x, #{name}: nil" do
+        it "defaults to nil" do
+          expect(resource.x).to be_nil
+        end
+      end
+
+      context "default ordering deprecation warnings" do
+        it "emits a deprecation warning for property :x, default: 10, #{name}: true" do
+          expect { resource_class.property :x, :default => 10, name.to_sym => true }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /Cannot specify both default and name_property together on property x of resource chef_resource_property_spec_(\d+). Only one \(default\) will be obeyed./
+        end
+        it "emits a deprecation warning for property :x, default: nil, #{name}: true" do
+          expect { resource_class.property :x, :default => nil, name.to_sym => true }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /Cannot specify both default and name_property together on property x of resource chef_resource_property_spec_(\d+). Only one \(name_property\) will be obeyed./
+        end
+        it "emits a deprecation warning for property :x, #{name}: true, default: 10" do
+          expect { resource_class.property :x, name.to_sym => true, :default => 10 }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /Cannot specify both default and name_property together on property x of resource chef_resource_property_spec_(\d+). Only one \(name_property\) will be obeyed./
+        end
+        it "emits a deprecation warning for property :x, #{name}: true, default: nil" do
+          expect { resource_class.property :x, name.to_sym => true, :default => nil }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+            /Cannot specify both default and name_property together on property x of resource chef_resource_property_spec_(\d+). Only one \(name_property\) will be obeyed./
+        end
+      end
+
+      context "default ordering" do
+        before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
+        with_property ":x, default: 10, #{name}: true" do
+          it "chooses default over #{name}" do
+            expect(resource.x).to eq 10
+          end
+        end
+        with_property ":x, default: nil, #{name}: true" do
+          it "chooses #{name} over default" do
+            expect(resource.x).to eq "blah"
+          end
+        end
+        with_property ":x, #{name}: true, default: 10" do
+          it "chooses #{name} over default" do
+            expect(resource.x).to eq "blah"
+          end
+        end
+        with_property ":x, #{name}: true, default: nil" do
+          it "chooses #{name} over default" do
+            expect(resource.x).to eq "blah"
+          end
+        end
+      end
+
+      context "default ordering when #{name} is nil" do
+        with_property ":x, #{name}: nil, default: 10" do
+          it "chooses default" do
+            expect(resource.x).to eq 10
+          end
+        end
+        with_property ":x, default: 10, #{name}: nil" do
+          it "chooses default" do
+            expect(resource.x).to eq 10
+          end
+        end
+      end
+
+      context "default ordering when #{name} is false" do
+        with_property ":x, #{name}: false, default: 10" do
+          it "chooses default" do
+            expect(resource.x).to eq 10
+          end
+        end
+        with_property ":x, default: 10, #{name}: nil" do
+          it "chooses default" do
+            expect(resource.x).to eq 10
+          end
+        end
+      end
+
+    end
+  end
+
+  it "raises an error if both name_property and name_attribute are specified" do
+    expect { resource_class.property :x, :name_property => false, :name_attribute => 1 }.to raise_error ArgumentError,
+      /Cannot specify both name_property and name_attribute together on property x of resource chef_resource_property_spec_(\d+)./
+    expect { resource_class.property :x, :name_property => false, :name_attribute => nil }.to raise_error ArgumentError,
+      /Cannot specify both name_property and name_attribute together on property x of resource chef_resource_property_spec_(\d+)./
+    expect { resource_class.property :x, :name_property => false, :name_attribute => false }.to raise_error ArgumentError,
+      /Cannot specify both name_property and name_attribute together on property x of resource chef_resource_property_spec_(\d+)./
+    expect { resource_class.property :x, :name_property => true, :name_attribute => true }.to raise_error ArgumentError,
+      /Cannot specify both name_property and name_attribute together on property x of resource chef_resource_property_spec_(\d+)./
+  end
+
+  context "property_type" do
+    it "property_types validate their defaults" do
+      expect {
+        module ::PropertySpecPropertyTypes
+          include Chef::Mixin::Properties
+          property_type(is: [:a, :b], default: :c)
+        end
+      }.to raise_error(Chef::Exceptions::DeprecatedFeatureError, /Default value :c is invalid for property <property type>./)
+      expect {
+        module ::PropertySpecPropertyTypes
+          include Chef::Mixin::Properties
+          property_type(is: [:a, :b], default: :b)
+        end
+      }.not_to raise_error
+    end
+
+    context "With property_type ABType (is: [:a, :b]) and CDType (is: [:c, :d])" do
+      before :all do
+        module ::PropertySpecPropertyTypes
+          include Chef::Mixin::Properties
+          ABType = property_type(is: [:a, :b])
+          CDType = property_type(is: [:c, :d])
+        end
+      end
+
+      with_property ":x, [PropertySpecPropertyTypes::ABType, nil, PropertySpecPropertyTypes::CDType]" do
+        it "The property can be set to nil without triggering a warning" do
+          expect(resource.x nil).to be_nil
+          expect(resource.x).to be_nil
+        end
+        it "The property can be set to :a" do
+          expect(resource.x :a).to eq(:a)
+          expect(resource.x).to eq(:a)
+        end
+        it "The property can be set to :c" do
+          expect(resource.x :c).to eq(:c)
+          expect(resource.x).to eq(:c)
+        end
+        it "The property cannot be set to :z" do
+          expect { resource.x :z }.to raise_error(Chef::Exceptions::ValidationFailed, /Property x must be one of/)
+        end
+      end
+
+      with_property ":x, [nil, PropertySpecPropertyTypes::ABType, PropertySpecPropertyTypes::CDType]" do
+        it "The property can be set to nil without triggering a warning" do
+          expect(resource.x nil).to be_nil
+          expect(resource.x).to be_nil
+        end
+        it "The property can be set to :a" do
+          expect(resource.x :a).to eq(:a)
+          expect(resource.x).to eq(:a)
+        end
+        it "The property can be set to :c" do
+          expect(resource.x :c).to eq(:c)
+          expect(resource.x).to eq(:c)
+        end
+        it "The property cannot be set to :z" do
+          expect { resource.x :z }.to raise_error(Chef::Exceptions::ValidationFailed, /Property x must be one of/)
+        end
+      end
+
+      with_property ":x, [PropertySpecPropertyTypes::ABType, nil], default: nil" do
+        it "The value defaults to nil" do
+          expect(resource.x).to be_nil
+        end
+      end
+
+      with_property ":x, [PropertySpecPropertyTypes::ABType, nil], default: lazy { nil }" do
+        it "The value defaults to nil" do
+          expect(resource.x).to be_nil
+        end
+      end
+    end
+
+  end
+
+  context "with a custom property type" do
+    class CustomPropertyType < Chef::Property
+    end
+
+    with_property ":x, CustomPropertyType.new" do
+      it "creates x with the given type" do
+        expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+      end
+
+      context "and a subclass" do
+        let(:subresource_class) do
+          new_resource_name = self.class.new_resource_name
+          Class.new(resource_class) do
+            resource_name new_resource_name
+          end
+        end
+        let(:subresource) do
+          subresource_class.new("blah")
+        end
+
+        context "with property :x, default: 10 on the subclass" do
+          before do
+            subresource_class.class_eval do
+              property :x, default: 10
+            end
+          end
+
+          it "x has the given type and default on the subclass" do
+            expect(subresource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+            expect(subresource_class.properties[:x].default).to eq(10)
+          end
+
+          it "x does not have the default on the superclass" do
+            expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+            expect(resource_class.properties[:x].default).to be_nil
+          end
+        end
+      end
+    end
+
+    with_property ":x, CustomPropertyType.new, default: 10" do
+      it "passes the default to the custom property type" do
+        expect(resource_class.properties[:x]).to be_kind_of(CustomPropertyType)
+        expect(resource_class.properties[:x].default).to eq(10)
+      end
+    end
+  end
+end
diff --git a/spec/unit/provider/apt_update_spec.rb b/spec/unit/provider/apt_update_spec.rb
new file mode 100644
index 0000000..b72f7d9
--- /dev/null
+++ b/spec/unit/provider/apt_update_spec.rb
@@ -0,0 +1,113 @@
+#
+# Author:: Thom May (<thom at chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::AptUpdate do
+  let(:new_resource) { Chef::Resource::AptUpdate.new("update") }
+
+  let(:config_dir) { Dir.mktmpdir("apt_update_apt_conf_d") }
+  let(:config_file) { File.join(config_dir, "15update-stamp") }
+  let(:stamp_dir) { Dir.mktmpdir("apt_update_periodic") }
+
+  before do
+    stub_const("Chef::Provider::AptUpdate::APT_CONF_DIR", config_dir)
+    stub_const("Chef::Provider::AptUpdate::STAMP_DIR", stamp_dir)
+  end
+
+  let(:provider) do
+    node = Chef::Node.new
+    events = Chef::EventDispatch::Dispatcher.new
+    run_context = Chef::RunContext.new(node, {}, events)
+    Chef::Provider::AptUpdate.new(new_resource, run_context)
+  end
+
+  it "responds to load_current_resource" do
+    expect(provider).to respond_to(:load_current_resource)
+  end
+
+  context "when the apt config directory does not exist" do
+    before do
+      FileUtils.rmdir config_dir
+      expect(File.exist?(config_dir)).to be_falsey
+      allow(provider).to receive(:shell_out!).with("apt-get -q update")
+    end
+
+    it "should create the directory" do
+      provider.run_action(:update)
+      expect(File.exist?(config_dir)).to be_truthy
+      expect(File.directory?(config_dir)).to be_truthy
+    end
+
+    it "should create the config file" do
+      provider.run_action(:update)
+      expect(File.exist?(config_file)).to be_truthy
+      expect(File.read(config_file)).to match(/^APT::Update.*#{stamp_dir}/)
+    end
+  end
+
+  describe "#action_update" do
+    it "should update the apt cache" do
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("apt-get -q update").and_return(double)
+      provider.run_action(:update)
+      expect(new_resource).to be_updated_by_last_action
+    end
+  end
+
+  describe "#action_periodic" do
+    before do
+      allow(File).to receive(:exist?)
+      expect(File).to receive(:exist?).with("#{stamp_dir}/update-success-stamp").and_return(true)
+    end
+
+    it "should run if the time stamp is old" do
+      expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 86_500)
+      expect(provider).to receive(:shell_out!).with("apt-get -q update")
+      provider.run_action(:periodic)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should not run if the time stamp is new" do
+      expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now)
+      expect(provider).to_not receive(:shell_out!).with("apt-get -q update")
+      provider.run_action(:periodic)
+      expect(new_resource).to_not be_updated_by_last_action
+    end
+
+    context "with a different frequency" do
+      before do
+        new_resource.frequency(400)
+      end
+
+      it "should run if the time stamp is old" do
+        expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 500)
+        expect(provider).to receive(:shell_out!).with("apt-get -q update")
+        provider.run_action(:periodic)
+        expect(new_resource).to be_updated_by_last_action
+      end
+
+      it "should not run if the time stamp is new" do
+        expect(File).to receive(:mtime).with("#{stamp_dir}/update-success-stamp").and_return(Time.now - 300)
+        expect(provider).to_not receive(:shell_out!).with("apt-get -q update")
+        provider.run_action(:periodic)
+        expect(new_resource).to_not be_updated_by_last_action
+      end
+    end
+  end
+end
diff --git a/spec/unit/provider/breakpoint_spec.rb b/spec/unit/provider/breakpoint_spec.rb
index 386e5a1..ffe8c82 100644
--- a/spec/unit/provider/breakpoint_spec.rb
+++ b/spec/unit/provider/breakpoint_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
+require "spec_helper"
 describe Chef::Provider::Breakpoint do
 
   before do
diff --git a/spec/unit/provider/cookbook_file/content_spec.rb b/spec/unit/provider/cookbook_file/content_spec.rb
index 6946966..096ac85 100644
--- a/spec/unit/provider/cookbook_file/content_spec.rb
+++ b/spec/unit/provider/cookbook_file/content_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,24 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::CookbookFile::Content do
 
-  let(:new_resource) { double('Chef::Resource::CookbookFile (new)', :cookbook_name => 'apache2', :cookbook => 'apache2') }
+  let(:new_resource) { double("Chef::Resource::CookbookFile (new)", :cookbook_name => "apache2", :cookbook => "apache2") }
   let(:content) do
-    @run_context = double('Chef::RunContext')
-    @current_resource = double('Chef::Resource::CookbookFile (current)')
+    @run_context = double("Chef::RunContext")
+    @current_resource = double("Chef::Resource::CookbookFile (current)")
     Chef::Provider::CookbookFile::Content.new(new_resource, @current_resource, @run_context)
   end
 
   it "prefers the explicit cookbook name on the resource to the implicit one" do
-    allow(new_resource).to receive(:cookbook).and_return('nginx')
-    expect(content.send(:resource_cookbook)).to eq('nginx')
+    allow(new_resource).to receive(:cookbook).and_return("nginx")
+    expect(content.send(:resource_cookbook)).to eq("nginx")
   end
 
   it "falls back to the implicit cookbook name on the resource" do
-    expect(content.send(:resource_cookbook)).to eq('apache2')
+    expect(content.send(:resource_cookbook)).to eq("apache2")
   end
 
 end
-
diff --git a/spec/unit/provider/cookbook_file_spec.rb b/spec/unit/provider/cookbook_file_spec.rb
index a7cbba9..b375784 100644
--- a/spec/unit/provider/cookbook_file_spec.rb
+++ b/spec/unit/provider/cookbook_file_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2009-2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
-require 'support/shared/unit/provider/file'
+require "support/shared/unit/provider/file"
 
 describe Chef::Provider::CookbookFile do
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
   let(:enclosing_directory) {
     canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
   }
@@ -44,12 +44,12 @@ describe Chef::Provider::CookbookFile do
   let(:resource) do
     resource = Chef::Resource::CookbookFile.new("seattle", @run_context)
     resource.path(resource_path)
-    resource.cookbook_name = 'apache2'
+    resource.cookbook_name = "apache2"
     resource
   end
 
   let(:content) do
-    content = double('Chef::Provider::CookbookFile::Content')
+    content = double("Chef::Provider::CookbookFile::Content")
   end
 
   it_behaves_like Chef::Provider::File
diff --git a/spec/unit/provider/cron/unix_spec.rb b/spec/unit/provider/cron/unix_spec.rb
index 3d7a567..83e0f43 100644
--- a/spec/unit/provider/cron/unix_spec.rb
+++ b/spec/unit/provider/cron/unix_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
 # Author:: Toomas Pelberg (toomasp at gmx.net)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2010-2016, Toomas Pelberg
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Cron::Unix do
 
@@ -37,9 +37,9 @@ describe Chef::Provider::Cron::Unix do
     end
   end
 
-  let(:status) { double('Process::Status', :exitstatus => exitstatus) }
+  let(:status) { double("Process::Status", :exitstatus => exitstatus) }
   let(:exitstatus) { 0 }
-  let(:shell_out) { double('Mixlib::ShellOut', :status => status, :stdout => stdout, :stderr => stderr) }
+  let(:shell_out) { double("Mixlib::ShellOut", :status => status, :stdout => stdout, :stderr => stderr) }
 
   it "is a Chef::Provider:Cron" do
     expect(provider).to be_a(Chef::Provider::Cron)
@@ -61,12 +61,12 @@ describe Chef::Provider::Cron::Unix do
     before do
       allow(Chef::Log).to receive(:debug)
       allow(shell_out).to receive(:format_for_exception).and_return("formatted command output")
-      allow(provider).to receive(:shell_out).with('/usr/bin/crontab -l', :user => username).and_return(shell_out)
+      allow(provider).to receive(:shell_out).with("/usr/bin/crontab -l", :user => username).and_return(shell_out)
     end
 
     it "should call crontab -l with the user" do
       provider.send(:read_crontab)
-      expect(provider).to have_received(:shell_out).with('/usr/bin/crontab -l', :user => username)
+      expect(provider).to have_received(:shell_out).with("/usr/bin/crontab -l", :user => username)
     end
 
     it "should return the contents of the crontab" do
diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb
index 7a917a4..010b1b0 100644
--- a/spec/unit/provider/cron_spec.rb
+++ b/spec/unit/provider/cron_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Cron do
   describe "when with special time string" do
@@ -56,7 +56,7 @@ CRONTAB
       it "should pull the details out of the cron line" do
         cron = @provider.load_current_resource
         expect(cron.time).to eq(:reboot)
-        expect(cron.command).to eq('/bin/true param1 param2')
+        expect(cron.command).to eq("/bin/true param1 param2")
       end
 
       it "should pull env vars out" do
@@ -75,12 +75,12 @@ HOME=/home/foo
 # Another comment
 CRONTAB
         cron = @provider.load_current_resource
-        expect(cron.mailto).to eq('foo at example.com')
-        expect(cron.shell).to eq('/bin/foosh')
-        expect(cron.path).to eq('/bin:/foo')
-        expect(cron.home).to eq('/home/foo')
+        expect(cron.mailto).to eq("foo at example.com")
+        expect(cron.shell).to eq("/bin/foosh")
+        expect(cron.path).to eq("/bin:/foo")
+        expect(cron.home).to eq("/home/foo")
         expect(cron.time).to eq(:reboot)
-        expect(cron.command).to eq('/bin/true param1 param2')
+        expect(cron.command).to eq("/bin/true param1 param2")
       end
 
       it "should parse and load generic and standard environment variables from cron entry" do
@@ -94,7 +94,7 @@ CRONTAB
         cron = @provider.load_current_resource
 
         expect(cron.mailto).to eq("warn at example.com")
-        expect(cron.environment).to eq({"TEST" => "lol", "FLAG" => "1"})
+        expect(cron.environment).to eq({ "TEST" => "lol", "FLAG" => "1" })
       end
 
       it "should not break with variables that match the cron resource internals" do
@@ -109,7 +109,7 @@ CRONTAB
         cron = @provider.load_current_resource
 
         expect(cron.time).to eq(:reboot)
-        expect(cron.environment).to eq({"MINUTE" => "40", "REBOOT" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"})
+        expect(cron.environment).to eq({ "MINUTE" => "40", "REBOOT" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production" })
       end
 
       it "should report the match" do
@@ -227,13 +227,13 @@ CRONTAB
 
       it "should pull the details out of the cron line" do
         cron = @provider.load_current_resource
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('5')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('1')
-        expect(cron.weekday).to eq('*')
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("5")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("1")
+        expect(cron.weekday).to eq("*")
         expect(cron.time).to eq(nil)
-        expect(cron.command).to eq('/bin/true param1 param2')
+        expect(cron.command).to eq("/bin/true param1 param2")
       end
 
       it "should pull env vars out" do
@@ -252,17 +252,17 @@ HOME=/home/foo
 # Another comment
 CRONTAB
         cron = @provider.load_current_resource
-        expect(cron.mailto).to eq('foo at example.com')
-        expect(cron.shell).to eq('/bin/foosh')
-        expect(cron.path).to eq('/bin:/foo')
-        expect(cron.home).to eq('/home/foo')
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('5')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('1')
-        expect(cron.weekday).to eq('*')
+        expect(cron.mailto).to eq("foo at example.com")
+        expect(cron.shell).to eq("/bin/foosh")
+        expect(cron.path).to eq("/bin:/foo")
+        expect(cron.home).to eq("/home/foo")
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("5")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("1")
+        expect(cron.weekday).to eq("*")
         expect(cron.time).to eq(nil)
-        expect(cron.command).to eq('/bin/true param1 param2')
+        expect(cron.command).to eq("/bin/true param1 param2")
       end
 
       it "should parse and load generic and standard environment variables from cron entry" do
@@ -276,7 +276,7 @@ CRONTAB
         cron = @provider.load_current_resource
 
         expect(cron.mailto).to eq("warn at example.com")
-        expect(cron.environment).to eq({"TEST" => "lol", "FLAG" => "1"})
+        expect(cron.environment).to eq({ "TEST" => "lol", "FLAG" => "1" })
       end
 
       it "should not break with variabels that match the cron resource internals" do
@@ -290,9 +290,9 @@ ENVIRONMENT=production
 CRONTAB
         cron = @provider.load_current_resource
 
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('5')
-        expect(cron.environment).to eq({"MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"})
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("5")
+        expect(cron.environment).to eq({ "MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production" })
       end
 
       it "should report the match" do
@@ -323,12 +323,12 @@ CRONTAB
 
       it "should pull the details out of the cron line" do
         cron = @provider.load_current_resource
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('5')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('Jan')
-        expect(cron.weekday).to eq('Mon')
-        expect(cron.command).to eq('/bin/true param1 param2')
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("5")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("Jan")
+        expect(cron.weekday).to eq("Mon")
+        expect(cron.command).to eq("/bin/true param1 param2")
       end
 
       it "should report the match" do
@@ -346,11 +346,11 @@ CRONTAB
 CRONTAB
         cron = @provider.load_current_resource
         expect(@provider.cron_exists).to eq(true)
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('*')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('*')
-        expect(cron.weekday).to eq('*')
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("*")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("*")
+        expect(cron.weekday).to eq("*")
         expect(cron.time).to eq(nil)
         expect(cron.command).to eq(nil)
       end
@@ -364,11 +364,11 @@ CRONTAB
 CRONTAB
         cron = @provider.load_current_resource
         expect(@provider.cron_exists).to eq(true)
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('*')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('*')
-        expect(cron.weekday).to eq('*')
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("*")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("*")
+        expect(cron.weekday).to eq("*")
         expect(cron.time).to eq(nil)
         expect(cron.command).to eq(nil)
       end
@@ -386,11 +386,11 @@ CRONTAB
 CRONTAB
         cron = @provider.load_current_resource
         expect(@provider.cron_exists).to eq(true)
-        expect(cron.minute).to eq('*')
-        expect(cron.hour).to eq('*')
-        expect(cron.day).to eq('*')
-        expect(cron.month).to eq('*')
-        expect(cron.weekday).to eq('*')
+        expect(cron.minute).to eq("*")
+        expect(cron.hour).to eq("*")
+        expect(cron.day).to eq("*")
+        expect(cron.month).to eq("*")
+        expect(cron.weekday).to eq("*")
         expect(cron.time).to eq(nil)
         expect(cron.command).to eq(nil)
       end
@@ -455,10 +455,10 @@ CRONTAB
       end
 
       it "should include env variables that are set" do
-        @new_resource.mailto 'foo at example.com'
-        @new_resource.path '/usr/bin:/my/custom/path'
-        @new_resource.shell '/bin/foosh'
-        @new_resource.home '/home/foo'
+        @new_resource.mailto "foo at example.com"
+        @new_resource.path "/usr/bin:/my/custom/path"
+        @new_resource.shell "/bin/foosh"
+        @new_resource.home "/home/foo"
         @new_resource.environment "TEST" => "LOL"
         expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
 # Chef Name: cronhole some stuff
@@ -511,10 +511,10 @@ TEST=LOL
       end
 
       it "should include env variables that are set" do
-        @new_resource.mailto 'foo at example.com'
-        @new_resource.path '/usr/bin:/my/custom/path'
-        @new_resource.shell '/bin/foosh'
-        @new_resource.home '/home/foo'
+        @new_resource.mailto "foo at example.com"
+        @new_resource.path "/usr/bin:/my/custom/path"
+        @new_resource.shell "/bin/foosh"
+        @new_resource.home "/home/foo"
         @new_resource.environment "TEST" => "LOL"
         expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
 0 2 * * * /some/other/command
@@ -576,10 +576,10 @@ TEST=LOL
       end
 
       it "should include env variables that are set" do
-        @new_resource.mailto 'foo at example.com'
-        @new_resource.path '/usr/bin:/my/custom/path'
-        @new_resource.shell '/bin/foosh'
-        @new_resource.home '/home/foo'
+        @new_resource.mailto "foo at example.com"
+        @new_resource.path "/usr/bin:/my/custom/path"
+        @new_resource.shell "/bin/foosh"
+        @new_resource.home "/home/foo"
         @new_resource.environment "TEST" => "LOL"
         expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
 0 2 * * * /some/other/command
@@ -671,10 +671,10 @@ HOME=/home/foo
 
 # Another comment
         CRONTAB
-        @new_resource.mailto 'foo at example.com'
-        @new_resource.path '/usr/bin:/my/custom/path'
-        @new_resource.shell '/bin/foosh'
-        @new_resource.home '/home/foo'
+        @new_resource.mailto "foo at example.com"
+        @new_resource.path "/usr/bin:/my/custom/path"
+        @new_resource.shell "/bin/foosh"
+        @new_resource.home "/home/foo"
         expect(@provider).to receive(:write_crontab).with(<<-ENDCRON)
 0 2 * * * /some/other/command
 
diff --git a/spec/unit/provider/deploy/revision_spec.rb b/spec/unit/provider/deploy/revision_spec.rb
index 4ca64e3..8f8280e 100644
--- a/spec/unit/provider/deploy/revision_spec.rb
+++ b/spec/unit/provider/deploy/revision_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Deploy::Revision do
 
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
     @temp_dir = Dir.mktmpdir
     Chef::Config[:file_cache_path] = @temp_dir
     @resource = Chef::Resource::Deploy.new("/my/deploy/dir")
@@ -41,7 +41,6 @@ describe Chef::Provider::Deploy::Revision do
     FileUtils.rm_rf @temp_dir if File.directory?( @temp_dir )
   end
 
-
   it "uses the resolved revision from the SCM as the release slug" do
     allow(@provider.scm_provider).to receive(:revision_slug).and_return("uglySlugly")
     expect(@provider.send(:release_slug)).to eq("uglySlugly")
@@ -60,7 +59,7 @@ describe Chef::Provider::Deploy::Revision do
     @provider.cleanup!
     second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2"
 
-    expect(@provider.all_releases).to eq([@expected_release_dir,second_release])
+    expect(@provider.all_releases).to eq([@expected_release_dir, second_release])
   end
 
   it "removes a release from the file cache when it's used again in another release and append it to the end" do
@@ -71,7 +70,7 @@ describe Chef::Provider::Deploy::Revision do
     @provider.load_current_resource
     @provider.cleanup!
     second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2"
-    expect(@provider.all_releases).to eq([@expected_release_dir,second_release])
+    expect(@provider.all_releases).to eq([@expected_release_dir, second_release])
     @provider.cleanup!
 
     allow(@provider).to receive(:release_slug).and_return("8a3195bf3efa246f743c5dfa83683201880f935c")
@@ -82,7 +81,7 @@ describe Chef::Provider::Deploy::Revision do
 
   it "removes a release from the file cache when it's deleted by :cleanup!" do
     release_paths = %w{first second third fourth fifth}.map do |release_name|
-       "/my/deploy/dir/releases/#{release_name}"
+      "/my/deploy/dir/releases/#{release_name}"
     end
     release_paths.each do |release_path|
       @provider.send(:release_created, release_path)
@@ -93,7 +92,7 @@ describe Chef::Provider::Deploy::Revision do
     @provider.cleanup!
 
     expected_release_paths = (%w{second third fourth fifth} << @resource.revision).map do |release_name|
-       "/my/deploy/dir/releases/#{release_name}"
+      "/my/deploy/dir/releases/#{release_name}"
     end
 
     expect(@provider.all_releases).to eq(expected_release_paths)
diff --git a/spec/unit/provider/deploy/timestamped_spec.rb b/spec/unit/provider/deploy/timestamped_spec.rb
index b189d33..fdb90bf 100644
--- a/spec/unit/provider/deploy/timestamped_spec.rb
+++ b/spec/unit/provider/deploy/timestamped_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Deploy::Timestamped do
 
diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb
index c95a9b3..62d9123 100644
--- a/spec/unit/provider/deploy_spec.rb
+++ b/spec/unit/provider/deploy_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Deploy do
 
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
     @release_time = Time.utc( 2004, 8, 15, 16, 23, 42)
     allow(Time).to receive(:now).and_return(@release_time)
     @expected_release_dir = "/my/deploy/dir/releases/20040815162342"
@@ -163,9 +163,9 @@ describe Chef::Provider::Deploy do
   end
 
   it "dont care by default if error happens on deploy" do
-    allow(@provider).to receive(:all_releases).and_return(['previous_release'])
-    allow(@provider).to receive(:deploy){ raise "Unexpected error" }
-    allow(@provider).to receive(:previous_release_path).and_return('previous_release')
+    allow(@provider).to receive(:all_releases).and_return(["previous_release"])
+    allow(@provider).to receive(:deploy) { raise "Unexpected error" }
+    allow(@provider).to receive(:previous_release_path).and_return("previous_release")
     expect(@provider).not_to receive(:rollback)
     expect {
       @provider.run_action(:deploy)
@@ -174,9 +174,9 @@ describe Chef::Provider::Deploy do
 
   it "rollbacks to previous release if error happens on deploy" do
     @resource.rollback_on_error true
-    allow(@provider).to receive(:all_releases).and_return(['previous_release'])
-    allow(@provider).to receive(:deploy){ raise "Unexpected error" }
-    allow(@provider).to receive(:previous_release_path).and_return('previous_release')
+    allow(@provider).to receive(:all_releases).and_return(["previous_release"])
+    allow(@provider).to receive(:deploy) { raise "Unexpected error" }
+    allow(@provider).to receive(:previous_release_path).and_return("previous_release")
     expect(@provider).to receive(:rollback)
     expect {
       @provider.run_action(:deploy)
@@ -266,7 +266,7 @@ describe Chef::Provider::Deploy do
   it "raises a runtime error when there's no release to rollback to" do
     all_releases = []
     allow(Dir).to receive(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases)
-    expect {@provider.run_action(:rollback)}.to raise_error(RuntimeError)
+    expect { @provider.run_action(:rollback) }.to raise_error(RuntimeError)
   end
 
   it "runs the new resource collection in the runner during a callback" do
@@ -286,12 +286,12 @@ describe Chef::Provider::Deploy do
   end
 
   it "raises a runtime error if a callback file is explicitly specified but does not exist" do
-    baz_callback =   "/deploy/baz.rb"
+    baz_callback = "/deploy/baz.rb"
     expect(::File).to receive(:exist?).with("#{@expected_release_dir}/#{baz_callback}").and_return(false)
-    @resource.before_migrate  baz_callback
+    @resource.before_migrate baz_callback
     @provider.define_resource_requirements
     @provider.action = :deploy
-    expect {@provider.process_resource_requirements}.to raise_error(RuntimeError)
+    expect { @provider.process_resource_requirements }.to raise_error(RuntimeError)
   end
 
   it "runs a default callback if the callback code is nil" do
@@ -356,13 +356,13 @@ describe Chef::Provider::Deploy do
   it "chowns the whole release dir to user and group specified in the resource" do
     @resource.user "foo"
     @resource.group "bar"
-    expect(FileUtils).to receive(:chown_R).with("foo", "bar", "/my/deploy/dir")
+    expect(FileUtils).to receive(:chown_R).with("foo", "bar", "/my/deploy/dir", { :force => true })
     @provider.enforce_ownership
   end
 
   it "skips the migration when resource.migrate => false but runs symlinks before migration" do
     @resource.migrate false
-    expect(@provider).not_to receive :run_command
+    expect(@provider).not_to receive :shell_out!
     expect(@provider).to receive :run_symlinks_before_migrate
     @provider.migrate
   end
@@ -378,11 +378,11 @@ describe Chef::Provider::Deploy do
 
     allow(STDOUT).to receive(:tty?).and_return(true)
     allow(Chef::Log).to receive(:info?).and_return(true)
-    expect(@provider).to receive(:run_command).with(:command => "migration_foo", :cwd => @expected_release_dir,
-                                                :user => "deployNinja", :group => "deployNinjas",
-                                                :log_level => :info, :live_stream => STDOUT,
-                                                :log_tag => "deploy[/my/deploy/dir]",
-                                                :environment => {"RAILS_ENV"=>"production"})
+    expect(@provider).to receive(:shell_out!).with("migration_foo", :cwd => @expected_release_dir,
+                                                                    :user => "deployNinja", :group => "deployNinjas",
+                                                                    :log_level => :info, :live_stream => STDOUT,
+                                                                    :log_tag => "deploy[/my/deploy/dir]",
+                                                                    :environment => { "RAILS_ENV" => "production" })
     @provider.migrate
   end
 
@@ -445,13 +445,13 @@ describe Chef::Provider::Deploy do
   end
 
   it "does nothing for restart if restart_command is empty" do
-    expect(@provider).not_to receive(:run_command)
+    expect(@provider).not_to receive(:shell_out!)
     @provider.restart
   end
 
   it "runs the restart command in the current application dir when the resource has a restart_command" do
     @resource.restart_command "restartcmd"
-    expect(@provider).to receive(:run_command).with(:command => "restartcmd", :cwd => "/my/deploy/dir/current", :log_tag => "deploy[/my/deploy/dir]", :log_level => :debug)
+    expect(@provider).to receive(:shell_out!).with("restartcmd", :cwd => "/my/deploy/dir/current", :log_tag => "deploy[/my/deploy/dir]", :log_level => :debug)
     @provider.restart
   end
 
@@ -509,7 +509,7 @@ describe Chef::Provider::Deploy do
   it "shouldn't give a no method error on migrate if the environment is nil" do
     allow(@provider).to receive(:enforce_ownership)
     allow(@provider).to receive(:run_symlinks_before_migrate)
-    allow(@provider).to receive(:run_command)
+    allow(@provider).to receive(:shell_out!)
     @provider.migrate
 
   end
@@ -518,7 +518,7 @@ describe Chef::Provider::Deploy do
 
     it "runs an inline recipe with the provided block for :callback_name == {:recipe => &block} " do
       snitch = nil
-      recipe_code = Proc.new {snitch = 42}
+      recipe_code = Proc.new { snitch = 42 }
       #@provider.should_receive(:instance_eval).with(&recipe_code)
       @provider.callback(:whateverz, recipe_code)
       expect(snitch).to eq(42)
@@ -533,7 +533,7 @@ describe Chef::Provider::Deploy do
 
     it "instance_evals a block/proc for restart command" do
       snitch = nil
-      restart_cmd = Proc.new {snitch = 42}
+      restart_cmd = Proc.new { snitch = 42 }
       @resource.restart(&restart_cmd)
       @provider.restart
       expect(snitch).to eq(42)
@@ -552,11 +552,11 @@ describe Chef::Provider::Deploy do
       expect(@provider).to receive(:execute).with("iGoToHell4this").and_return(mock_execution)
       @resource.user("notCoolMan")
       @resource.group("Ggroup")
-      @resource.environment("APP_ENV" => 'staging')
+      @resource.environment("APP_ENV" => "staging")
       @resource.deploy_to("/my/app")
       expect(mock_execution).to receive(:user).with("notCoolMan")
       expect(mock_execution).to receive(:group).with("Ggroup")
-      expect(mock_execution).to receive(:cwd){|*args|
+      expect(mock_execution).to receive(:cwd) {|*args|
         if args.empty?
           nil
         else
@@ -564,12 +564,12 @@ describe Chef::Provider::Deploy do
           expect(args.first).to eq(@provider.release_path)
         end
       }.twice
-      expect(mock_execution).to receive(:environment){ |*args|
+      expect(mock_execution).to receive(:environment) { |*args|
         if args.empty?
           nil
         else
           expect(args.size).to eq(1)
-          expect(args.first).to eq({"APP_ENV" => "staging"})
+          expect(args.first).to eq({ "APP_ENV" => "staging" })
         end
       }.twice
       @provider.run("iGoToHell4this")
@@ -586,7 +586,6 @@ describe Chef::Provider::Deploy do
       @provider.run("iGoToHell4this")
     end
 
-
     it "converts sudo and run to exec resources in hooks" do
       runner = double("tehRunner")
       allow(Chef::Runner).to receive(:new).and_return(runner)
@@ -613,7 +612,7 @@ describe Chef::Provider::Deploy do
 
     before do
       allow(::File).to receive(:exist?).with("#{@expected_release_dir}/gems.yml").and_return(true)
-      @gem_list = [{:name=>"eventmachine", :version=>"0.12.9"}]
+      @gem_list = [{ :name => "eventmachine", :version => "0.12.9" }]
     end
 
     it "reads a gems.yml file, creating gem providers for each with action :upgrade" do
@@ -622,7 +621,7 @@ describe Chef::Provider::Deploy do
 
       gems = @provider.send(:gem_packages)
 
-      expect(gems.map { |g| g.action }).to eq([[:install]])
+      expect(gems.map { |g| g.action }).to eq([%i{install}])
       expect(gems.map { |g| g.name }).to eq(%w{eventmachine})
       expect(gems.map { |g| g.version }).to eq(%w{0.12.9})
     end
diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb
index 13c57bf..c8bec3e 100644
--- a/spec/unit/provider/directory_spec.rb
+++ b/spec/unit/provider/directory_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,173 +16,272 @@
 # limitations under the License.
 #
 
-require 'ostruct'
-
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 describe Chef::Provider::Directory do
-  before(:each) do
-    @new_resource = Chef::Resource::Directory.new(Dir.tmpdir)
-    if !windows?
-      @new_resource.owner(500)
-      @new_resource.group(500)
-      @new_resource.mode(0644)
+  let(:tmp_dir) { Dir.mktmpdir }
+  let(:new_resource) { Chef::Resource::Directory.new(tmp_dir) }
+  let(:node) { Chef::Node.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:directory) { Chef::Provider::Directory.new(new_resource, run_context) }
+
+  describe "#load_current_resource" do
+    describe "scanning file security metadata"
+    describe "on unix", unix_only: true do
+      describe "when the directory exists" do
+        let(:dir_stat) { File::Stat.new(tmp_dir) }
+        let(:expected_uid) { dir_stat.uid }
+        let(:expected_gid) { dir_stat.gid }
+        let(:expected_mode) { "0%o" % ( dir_stat.mode & 007777 ) }
+        let(:expected_pwnam) { Etc.getpwuid(expected_uid).name }
+        let(:expected_grnam) { Etc.getgrgid(expected_gid).name }
+
+        it "describes the access mode as a String of octal integers" do
+          directory.load_current_resource
+          expect(directory.current_resource.mode).to eq(expected_mode)
+        end
+
+        it "when the new_resource.owner is numeric, describes the owner as a numeric uid" do
+          new_resource.owner(500)
+          directory.load_current_resource
+          expect(directory.current_resource.owner).to eql(expected_uid)
+        end
+
+        it "when the new_resource.group is numeric, describes the group as a numeric gid" do
+          new_resource.group(500)
+          directory.load_current_resource
+          expect(directory.current_resource.group).to eql(expected_gid)
+        end
+
+        it "when the new_resource.owner is a string, describes the owner as a string" do
+          new_resource.owner("foo")
+          directory.load_current_resource
+          expect(directory.current_resource.owner).to eql(expected_pwnam)
+        end
+
+        it "when the new_resource.group is a string, describes the group as a string" do
+          new_resource.group("bar")
+          directory.load_current_resource
+          expect(directory.current_resource.group).to eql(expected_grnam)
+        end
+      end
     end
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
 
-    @directory = Chef::Provider::Directory.new(@new_resource, @run_context)
-  end
+    describe "on windows", windows_only: true do
+      describe "when the directory exists" do
+        it "the mode is always nil" do
+          directory.load_current_resource
+          expect(directory.current_resource.mode).to be nil
+        end
+
+        it "the owner is always nil" do
+          directory.load_current_resource
+          expect(directory.current_resource.owner).to be nil
+        end
 
+        it "the group is always nil" do
+          directory.load_current_resource
+          expect(directory.current_resource.group).to be nil
+        end
 
-  describe "scanning file security metadata on windows" do
-    before do
+        it "rights are always nil (incorrectly)" do
+          directory.load_current_resource
+          expect(directory.current_resource.rights).to be nil
+        end
+
+        it "inherits is always nil (incorrectly)" do
+          directory.load_current_resource
+          expect(directory.current_resource.inherits).to be nil
+        end
+      end
     end
 
-    it "describes the directory's access rights" do
-      skip
+    describe "when the directory does not exist" do
+      before do
+        FileUtils.rmdir tmp_dir
+      end
+
+      it "sets the mode, group and owner to nil" do
+        directory.load_current_resource
+        expect(directory.current_resource.mode).to eq(nil)
+        expect(directory.current_resource.group).to eq(nil)
+        expect(directory.current_resource.owner).to eq(nil)
+      end
     end
+
   end
 
-  describe "scanning file security metadata on unix" do
-    before do
-      allow(Chef::Platform).to receive(:windows?).and_return(false)
-    end
-    let(:mock_stat) do
-      cstats = double("stats")
-      allow(cstats).to receive(:uid).and_return(500)
-      allow(cstats).to receive(:gid).and_return(500)
-      allow(cstats).to receive(:mode).and_return(0755)
-      cstats
+  describe "#define_resource_requirements" do
+    describe "on unix", unix_only: true do
+      it "raises an exception if the user does not exist" do
+        new_resource.owner("arglebargle_iv")
+        expect(Etc).to receive(:getpwnam).with("arglebargle_iv").and_raise(ArgumentError)
+        directory.action = :create
+        directory.load_current_resource
+        expect(directory.access_controls).to receive(:define_resource_requirements).and_call_original
+        directory.define_resource_requirements
+        expect { directory.process_resource_requirements }.to raise_error(ArgumentError)
+      end
+
+      it "raises an exception if the group does not exist" do
+        new_resource.group("arglebargle_iv")
+        expect(Etc).to receive(:getgrnam).with("arglebargle_iv").and_raise(ArgumentError)
+        directory.action = :create
+        directory.load_current_resource
+        expect(directory.access_controls).to receive(:define_resource_requirements).and_call_original
+        directory.define_resource_requirements
+        expect { directory.process_resource_requirements }.to raise_error(ArgumentError)
+      end
     end
+  end
+
+  describe "#run_action(:create)" do
+    describe "when the directory exists" do
+      it "does not create the directory" do
+        expect(Dir).not_to receive(:mkdir).with(new_resource.path)
+        directory.run_action(:create)
+      end
 
-    it "describes the access mode as a String of octal integers" do
-      allow(File).to receive(:exists?).and_return(true)
-      expect(File).to receive(:stat).and_return(mock_stat)
-      @directory.load_current_resource
-      expect(@directory.current_resource.mode).to eq("0755")
+      it "should not set the resource as updated" do
+        directory.run_action(:create)
+        expect(new_resource).not_to be_updated
+      end
     end
 
-    context "when user and group are specified with UID/GID" do
-      it "describes the current owner and group as UID and GID" do
-        allow(File).to receive(:exists?).and_return(true)
-        expect(File).to receive(:stat).and_return(mock_stat)
-        @directory.load_current_resource
-        expect(@directory.current_resource.path).to eql(@new_resource.path)
-        expect(@directory.current_resource.owner).to eql(500)
-        expect(@directory.current_resource.group).to eql(500)
+    describe "when the directory does not exist" do
+      before do
+        FileUtils.rmdir tmp_dir
+      end
+
+      it "creates the directory" do
+        directory.run_action(:create)
+        expect(File.exist?(tmp_dir)).to be true
+      end
+
+      it "sets the new resource as updated" do
+        directory.run_action(:create)
+        expect(new_resource).to be_updated
       end
     end
 
-    context "when user/group are specified with user/group names" do
+    describe "when the parent directory does not exist" do
+      before do
+        new_resource.path "#{tmp_dir}/foobar"
+        FileUtils.rmdir tmp_dir
+      end
+
+      it "raises an exception when recursive is false" do
+        new_resource.recursive false
+        expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+      end
+
+      it "creates the directories when recursive is true" do
+        new_resource.recursive true
+        directory.run_action(:create)
+        expect(new_resource).to be_updated
+        expect(File.exist?("#{tmp_dir}/foobar")).to be true
+      end
+
+      it "raises an exception when the parent directory is a file and recursive is true" do
+        FileUtils.touch tmp_dir
+        new_resource.recursive true
+        expect { directory.run_action(:create) }.to raise_error
+      end
+
+      it "raises the right exception when the parent directory is a file and recursive is true" do
+        pending "this seems to return the wrong error" # FIXME
+        FileUtils.touch tmp_dir
+        new_resource.recursive true
+        expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+      end
     end
-  end
 
-  # Unix only for now. While file security attribute reporting for windows is
-  # disabled, unix and windows differ in the number of exists? calls that are
-  # made by the provider.
-  it "should create a new directory on create, setting updated to true", :unix_only do
-    @new_resource.path "/tmp/foo"
+    describe "on OS X" do
+      before do
+        allow(node).to receive(:[]).with("platform").and_return("mac_os_x")
+        new_resource.path "/usr/bin/chef_test"
+        new_resource.recursive false
+        allow_any_instance_of(Chef::Provider::File).to receive(:do_selinux)
+      end
 
-    expect(File).to receive(:exists?).at_least(:once).and_return(false)
-    expect(File).to receive(:directory?).with("/tmp").and_return(true)
-    expect(Dir).to receive(:mkdir).with(@new_resource.path).once.and_return(true)
+      it "os x 10.10 can write to sip locations" do
+        allow(node).to receive(:[]).with("platform_version").and_return("10.10")
+        allow(Dir).to receive(:mkdir).and_return([true], [])
+        allow(::File).to receive(:directory?).and_return(true)
+        allow(Chef::FileAccessControl).to receive(:writable?).and_return(true)
+        directory.run_action(:create)
+        expect(new_resource).to be_updated
+      end
 
-    expect(@directory).to receive(:do_acl_changes)
-    allow(@directory).to receive(:do_selinux)
-    @directory.run_action(:create)
-    expect(@directory.new_resource).to be_updated
-  end
+      it "os x 10.11 cannot write to sip locations" do
+        allow(node).to receive(:[]).with("platform_version").and_return("10.11")
+        allow(::File).to receive(:directory?).and_return(true)
+        allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
+        expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
+      end
 
-  it "should raise an exception if the parent directory does not exist and recursive is false" do
-    @new_resource.path "/tmp/some/dir"
-    @new_resource.recursive false
-    expect { @directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
+      it "os x 10.11 can write to sip exlcusions" do
+        new_resource.path "/usr/local/chef_test"
+        allow(node).to receive(:[]).with("platform_version").and_return("10.11")
+        allow(::File).to receive(:directory?).and_return(true)
+        allow(Dir).to receive(:mkdir).and_return([true], [])
+        allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
+        directory.run_action(:create)
+        expect(new_resource).to be_updated
+      end
+    end
   end
 
-  # Unix only for now. While file security attribute reporting for windows is
-  # disabled, unix and windows differ in the number of exists? calls that are
-  # made by the provider.
-  it "should create a new directory when parent directory does not exist if recursive is true and permissions are correct", :unix_only do
-    @new_resource.path "/path/to/dir"
-    @new_resource.recursive true
-    expect(File).to receive(:exists?).with(@new_resource.path).ordered.and_return(false)
-
-    expect(File).to receive(:exists?).with('/path/to').ordered.and_return(false)
-    expect(File).to receive(:exists?).with('/path').ordered.and_return(true)
-    expect(Chef::FileAccessControl).to receive(:writable?).with('/path').ordered.and_return(true)
-    expect(File).to receive(:exists?).with(@new_resource.path).ordered.and_return(false)
-
-    expect(FileUtils).to receive(:mkdir_p).with(@new_resource.path).and_return(true)
-    expect(@directory).to receive(:do_acl_changes)
-    allow(@directory).to receive(:do_selinux)
-    @directory.run_action(:create)
-    expect(@new_resource).to be_updated
-  end
+  describe "#run_action(:create)" do
+    describe "when the directory exists" do
+      it "deletes the directory" do
+        directory.run_action(:delete)
+        expect(File.exist?(tmp_dir)).to be false
+      end
 
+      it "sets the new resource as updated" do
+        directory.run_action(:delete)
+        expect(new_resource).to be_updated
+      end
+    end
 
-  it "should raise an error when creating a directory when parent directory is a file" do
-    expect(File).to receive(:directory?).and_return(false)
-    expect(Dir).not_to receive(:mkdir).with(@new_resource.path)
-    expect { @directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist)
-    expect(@directory.new_resource).not_to be_updated
-  end
+    describe "when the directory does not exist" do
+      before do
+        FileUtils.rmdir tmp_dir
+      end
 
-  # Unix only for now. While file security attribute reporting for windows is
-  # disabled, unix and windows differ in the number of exists? calls that are
-  # made by the provider.
-  it "should not create the directory if it already exists", :unix_only do
-    stub_file_cstats
-    @new_resource.path "/tmp/foo"
-    expect(File).to receive(:directory?).at_least(:once).and_return(true)
-    expect(Chef::FileAccessControl).to receive(:writable?).with("/tmp").and_return(true)
-    expect(File).to receive(:exists?).at_least(:once).and_return(true)
-    expect(Dir).not_to receive(:mkdir).with(@new_resource.path)
-    expect(@directory).to receive(:do_acl_changes)
-    @directory.run_action(:create)
-  end
+      it "does not delete the directory" do
+        expect(Dir).not_to receive(:delete).with(new_resource.path)
+        directory.run_action(:delete)
+      end
 
-  it "should delete the directory if it exists, and is writable with action_delete" do
-    expect(File).to receive(:directory?).and_return(true)
-    expect(Chef::FileAccessControl).to receive(:writable?).once.and_return(true)
-    expect(Dir).to receive(:delete).with(@new_resource.path).once.and_return(true)
-    @directory.run_action(:delete)
-  end
+      it "sets the new resource as updated" do
+        directory.run_action(:delete)
+        expect(new_resource).not_to be_updated
+      end
+    end
 
-  it "should raise an exception if it cannot delete the directory due to bad permissions" do
-    allow(File).to receive(:exists?).and_return(true)
-    allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
-    expect {  @directory.run_action(:delete) }.to raise_error(RuntimeError)
-  end
+    describe "when the directory is not writable" do
+      before do
+        allow(Chef::FileAccessControl).to receive(:writable?).and_return(false)
+      end
 
-  it "should take no action when deleting a target directory that does not exist" do
-    @new_resource.path "/an/invalid/path"
-    allow(File).to receive(:exists?).and_return(false)
-    expect(Dir).not_to receive(:delete).with(@new_resource.path)
-    @directory.run_action(:delete)
-    expect(@directory.new_resource).not_to be_updated
-  end
+      it "cannot delete it and raises an exception" do
+        expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+      end
+    end
 
-  it "should raise an exception when deleting a directory when target directory is a file" do
-    stub_file_cstats
-    @new_resource.path "/an/invalid/path"
-    allow(File).to receive(:exists?).and_return(true)
-    expect(File).to receive(:directory?).and_return(false)
-    expect(Dir).not_to receive(:delete).with(@new_resource.path)
-    expect { @directory.run_action(:delete) }.to raise_error(RuntimeError)
-    expect(@directory.new_resource).not_to be_updated
-  end
+    describe "when the target directory is a file" do
+      before do
+        FileUtils.rmdir tmp_dir
+        FileUtils.touch tmp_dir
+      end
 
-  def stub_file_cstats
-    cstats = double("stats")
-    allow(cstats).to receive(:uid).and_return(500)
-    allow(cstats).to receive(:gid).and_return(500)
-    allow(cstats).to receive(:mode).and_return(0755)
-    # File.stat is called in:
-    # - Chef::Provider::File.load_current_resource_attrs
-    # - Chef::ScanAccessControl via Chef::Provider::File.setup_acl
-    allow(File).to receive(:stat).and_return(cstats)
+      it "cannot delete it and raises an exception" do
+        expect { directory.run_action(:delete) }.to raise_error(RuntimeError)
+      end
+    end
   end
 end
diff --git a/spec/unit/provider/dsc_resource_spec.rb b/spec/unit/provider/dsc_resource_spec.rb
index 0a6c22b..c0b4129 100644
--- a/spec/unit/provider/dsc_resource_spec.rb
+++ b/spec/unit/provider/dsc_resource_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-require 'chef'
-require 'spec_helper'
+require "chef"
+require "spec_helper"
 
 describe Chef::Provider::DscResource do
   let (:events) { Chef::EventDispatch::Dispatcher.new }
@@ -28,57 +27,92 @@ describe Chef::Provider::DscResource do
     Chef::Provider::DscResource.new(resource, run_context)
   end
 
-  context 'when Powershell does not support Invoke-DscResource' do
+  context "when Powershell does not support Invoke-DscResource" do
     let (:node) {
       node = Chef::Node.new
-      node.automatic[:languages][:powershell][:version] = '4.0'
+      node.automatic[:languages][:powershell][:version] = "4.0"
       node
     }
-
-    it 'raises a NoProviderAvailable exception' do
+    it "raises a ProviderNotFound exception" do
       expect(provider).not_to receive(:meta_configuration)
-      expect{provider.run_action(:run)}.to raise_error(
-              Chef::Exceptions::NoProviderAvailable, /5\.0\.10018\.0/)
+      expect { provider.run_action(:run) }.to raise_error(
+              Chef::Exceptions::ProviderNotFound, /5\.0\.10018\.0/)
+    end
+  end
+
+  context "when Powershell supports Invoke-DscResource" do
+
+    context "when RefreshMode is not set to Disabled" do
+      context "and the WMF 5 is a preview release" do
+        let (:node) {
+          node = Chef::Node.new
+          node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
+          node
+        }
+        it "raises an exception" do
+          expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(false)
+          expect { provider.run_action(:run) }.to raise_error(
+            Chef::Exceptions::ProviderNotFound, /Disabled/)
+        end
+      end
+      context "and the WMF is 5 RTM or newer" do
+        let (:node) {
+          node = Chef::Node.new
+          node.automatic[:languages][:powershell][:version] = "5.0.10586.0"
+          node
+        }
+        it "does not raises an exception" do
+          expect(provider).to receive(:test_resource)
+          expect(provider).to receive(:set_resource)
+          expect(provider).to receive(:reboot_if_required)
+          expect { provider.run_action(:run) }.to_not raise_error
+        end
+      end
     end
   end
 
-  context 'when Powershell supports Invoke-DscResource' do
+  context "when the LCM supports Invoke-DscResource" do
     let (:node) {
       node = Chef::Node.new
-      node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+      node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
       node
     }
 
-    context 'when RefreshMode is not set to Disabled' do
-      let (:meta_configuration) { {'RefreshMode' => 'AnythingElse'}}
-
-      it 'raises an exception' do
-        expect(provider).to receive(:meta_configuration).and_return(
-                                                             meta_configuration)
-        expect { provider.run_action(:run) }.to raise_error(
-          Chef::Exceptions::NoProviderAvailable, /Disabled/)
-      end
+    it "does not update the resource if it is up to date" do
+      expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
+      expect(provider).to receive(:test_resource).and_return(true)
+      provider.run_action(:run)
+      expect(resource).not_to be_updated
     end
 
-    context 'when RefreshMode is set to Disabled' do
-      let (:meta_configuration) { {'RefreshMode' => 'Disabled'}}
+    it "converges the resource if it is not up to date" do
+      expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
+      expect(provider).to receive(:test_resource).and_return(false)
+      expect(provider).to receive(:set_resource)
+      provider.run_action(:run)
+      expect(resource).to be_updated
+    end
 
-      it 'does not update the resource if it is up to date' do
-        expect(provider).to receive(:meta_configuration).and_return(
-                                                             meta_configuration)
-        expect(provider).to receive(:test_resource).and_return(true)
-        provider.run_action(:run)
-        expect(resource).not_to be_updated
-      end
+    it "flags the resource as reboot required when required" do
+      expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
+      expect(provider).to receive(:test_resource).and_return(false)
+      expect(provider).to receive(:invoke_resource).
+        and_return(double(:stdout => "", :return_value => nil))
+      expect(provider).to receive(:add_dsc_verbose_log)
+      expect(provider).to receive(:return_dsc_resource_result).and_return(true)
+      expect(provider).to receive(:create_reboot_resource)
+      provider.run_action(:run)
+    end
 
-      it 'converges the resource if it is not up to date' do
-        expect(provider).to receive(:meta_configuration).and_return(
-                                                             meta_configuration)
-        expect(provider).to receive(:test_resource).and_return(false)
-        expect(provider).to receive(:set_resource)
-        provider.run_action(:run)
-        expect(resource).to be_updated
-      end
+    it "does not flag the resource as reboot required when not required" do
+      expect(provider).to receive(:dsc_refresh_mode_disabled?).and_return(true)
+      expect(provider).to receive(:test_resource).and_return(false)
+      expect(provider).to receive(:invoke_resource).
+        and_return(double(:stdout => "", :return_value => nil))
+      expect(provider).to receive(:add_dsc_verbose_log)
+      expect(provider).to receive(:return_dsc_resource_result).and_return(false)
+      expect(provider).to_not receive(:create_reboot_resource)
+      provider.run_action(:run)
     end
   end
 end
diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb
index d4b2eb3..3877a37 100644
--- a/spec/unit/provider/dsc_script_spec.rb
+++ b/spec/unit/provider/dsc_script_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Jay Mundrawala (<jdm at getchef.com>)
+# Author:: Jay Mundrawala (<jdm at chef.io>)
 #
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,15 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/dsc/resource_info'
-require 'spec_helper'
+require "chef"
+require "chef/util/dsc/resource_info"
+require "spec_helper"
 
 describe Chef::Provider::DscScript do
-  context 'when DSC is available' do
+  context "when DSC is available" do
     let (:node) {
       node = Chef::Node.new
-      node.automatic[:languages][:powershell][:version] = '4.0'
+      node.automatic[:languages][:powershell][:version] = "4.0"
       node
     }
     let (:events) { Chef::EventDispatch::Dispatcher.new }
@@ -39,75 +39,75 @@ describe Chef::Provider::DscScript do
       it "describes the resource as converged if there were 0 DSC resources" do
         allow(provider).to receive(:run_configuration).with(:test).and_return([])
         provider.load_current_resource
-        expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+        expect(provider.instance_variable_get("@resource_converged")).to be_truthy
       end
 
       it "describes the resource as not converged if there is 1 DSC resources that is converged" do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
         allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
         provider.load_current_resource
-        expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+        expect(provider.instance_variable_get("@resource_converged")).to be_truthy
       end
 
       it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
         allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
         provider.load_current_resource
-        expect(provider.instance_variable_get('@resource_converged')).to be_falsey
+        expect(provider.instance_variable_get("@resource_converged")).to be_falsey
       end
 
       it "describes the resource as not converged if there are any DSC resources that are not converged" do
-        dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
-        dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+        dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
+        dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
 
         allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
         provider.load_current_resource
-        expect(provider.instance_variable_get('@resource_converged')).to be_falsey
+        expect(provider.instance_variable_get("@resource_converged")).to be_falsey
       end
 
       it "describes the resource as converged if all DSC resources that are converged" do
-        dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
-        dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
+        dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
+        dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new("resource", false, ["nothing will change something"])
 
         allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
         provider.load_current_resource
-        expect(provider.instance_variable_get('@resource_converged')).to be_truthy
+        expect(provider.instance_variable_get("@resource_converged")).to be_truthy
       end
     end
 
     describe '#generate_configuration_document' do
       # I think integration tests should cover these cases
 
-      it 'uses configuration_document_from_script_path when a dsc script file is given' do
+      it "uses configuration_document_from_script_path when a dsc script file is given" do
         allow(provider).to receive(:load_current_resource)
         resource.command("path_to_script")
-        generator = double('Chef::Util::DSC::ConfigurationGenerator')
+        generator = double("Chef::Util::DSC::ConfigurationGenerator")
         expect(generator).to receive(:configuration_document_from_script_path)
         allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
-        provider.send(:generate_configuration_document, 'tmp', nil)
+        provider.send(:generate_configuration_document, "tmp", nil)
       end
 
-      it 'uses configuration_document_from_script_code when a the dsc resource is given' do
+      it "uses configuration_document_from_script_code when a the dsc resource is given" do
         allow(provider).to receive(:load_current_resource)
         resource.code("ImADSCResource{}")
-        generator = double('Chef::Util::DSC::ConfigurationGenerator')
+        generator = double("Chef::Util::DSC::ConfigurationGenerator")
         expect(generator).to receive(:configuration_document_from_script_code)
         allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
-        provider.send(:generate_configuration_document, 'tmp', nil)
+        provider.send(:generate_configuration_document, "tmp", nil)
       end
 
-      it 'should noop if neither code or command are provided' do
+      it "should noop if neither code or command are provided" do
         allow(provider).to receive(:load_current_resource)
-        generator = double('Chef::Util::DSC::ConfigurationGenerator')
-        expect(generator).to receive(:configuration_document_from_script_code).with('', anything(), anything(), anything())
+        generator = double("Chef::Util::DSC::ConfigurationGenerator")
+        expect(generator).to receive(:configuration_document_from_script_code).with("", anything(), anything(), anything())
         allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
-        provider.send(:generate_configuration_document, 'tmp', nil)
+        provider.send(:generate_configuration_document, "tmp", nil)
       end
     end
 
-    describe 'action_run' do
-      it 'should converge the script if it is not converged' do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
+    describe "action_run" do
+      it "should converge the script if it is not converged" do
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resource", true, ["will change something"])
         allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
         allow(provider).to receive(:run_configuration).with(:set)
 
@@ -115,60 +115,59 @@ describe Chef::Provider::DscScript do
         expect(resource).to be_updated
       end
 
-      it 'should not converge if the script is already converged' do
+      it "should not converge if the script is already converged" do
         allow(provider).to receive(:run_configuration).with(:test).and_return([])
-        
+
         provider.run_action(:run)
         expect(resource).not_to be_updated
       end
     end
 
     describe '#generate_description' do
-      it 'removes the resource name from the beginning of any log line from the LCM' do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
-        provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+      it "removes the resource name from the beginning of any log line from the LCM" do
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", true, ["resourcename doing something", "lastline"])
+        provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
         expect(provider.send(:generate_description)[1]).to match(/converge DSC resource resourcename by doing something/)
       end
 
-      it 'ignores the last line' do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
-        provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+      it "ignores the last line" do
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", true, ["resourcename doing something", "lastline"])
+        provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
         expect(provider.send(:generate_description)[1]).not_to match(/lastline/)
       end
 
-      it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
-        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
-        provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
+      it "reports a dsc resource has not been changed if the LCM reported no change was required" do
+        dsc_resource_info = Chef::Util::DSC::ResourceInfo.new("resourcename", false, ["resourcename does nothing", "lastline"])
+        provider.instance_variable_set("@dsc_resources_info", [dsc_resource_info])
         expect(provider.send(:generate_description)[1]).to match(/converge DSC resource resourcename by doing nothing/)
       end
     end
   end
 
-  context 'when Dsc is not available' do
+  context "when Dsc is not available" do
     let (:node) { Chef::Node.new }
     let (:events) { Chef::EventDispatch::Dispatcher.new }
     let (:run_context) { Chef::RunContext.new(node, {}, events) }
-    let (:resource) { Chef::Resource::DscScript.new('script', run_context) }
+    let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
     let (:provider) { Chef::Provider::DscScript.new(resource, run_context) }
 
-    describe 'action_run' do
-      ['1.0', '2.0', '3.0'].each do |version|
+    describe "action_run" do
+      ["1.0", "2.0", "3.0"].each do |version|
         it "raises an exception for powershell version '#{version}'" do
           node.automatic[:languages][:powershell][:version] = version
 
           expect {
             provider.run_action(:run)
-          }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+          }.to raise_error(Chef::Exceptions::ProviderNotFound)
         end
       end
 
-      it 'raises an exception if Powershell is not present' do
+      it "raises an exception if Powershell is not present" do
         expect {
           provider.run_action(:run)
-        }.to raise_error(Chef::Exceptions::NoProviderAvailable)
+        }.to raise_error(Chef::Exceptions::ProviderNotFound)
       end
 
     end
   end
 end
-
diff --git a/spec/unit/provider/env/windows_spec.rb b/spec/unit/provider/env/windows_spec.rb
index 99f33d3..abe2344 100644
--- a/spec/unit/provider/env/windows_spec.rb
+++ b/spec/unit/provider/env/windows_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Sander van Harmelen <svanharmelen at schubergphilis.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,86 +16,86 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Env::Windows, :windows_only do
   let(:node) { Chef::Node.new }
-  let(:events) {Chef::EventDispatch::Dispatcher.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
 
-  context 'when environment variable is not PATH' do
+  context "when environment variable is not PATH" do
     let(:new_resource) {
       new_resource = Chef::Resource::Env.new("CHEF_WINDOWS_ENV_TEST")
       new_resource.value("foo")
       new_resource
     }
-    let(:provider) { 
-      provider = Chef::Provider::Env::Windows.new(new_resource, run_context) 
-      allow(provider).to receive(:env_obj).and_return(double('null object').as_null_object)
+    let(:provider) {
+      provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
+      allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
       provider
     }
 
     describe "action_create" do
       before do
-        ENV.delete('CHEF_WINDOWS_ENV_TEST')
+        ENV.delete("CHEF_WINDOWS_ENV_TEST")
         provider.key_exists = false
       end
 
       it "should update the ruby ENV object when it creates the key" do
         provider.action_create
-        expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foo')
+        expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foo")
       end
     end
 
     describe "action_modify" do
       before do
-        ENV['CHEF_WINDOWS_ENV_TEST'] = 'foo'
+        ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
       end
 
       it "should update the ruby ENV object when it updates the value" do
         expect(provider).to receive(:requires_modify_or_create?).and_return(true)
         new_resource.value("foobar")
         provider.action_modify
-        expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foobar')
+        expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foobar")
       end
 
       describe "action_delete" do
         before do
-          ENV['CHEF_WINDOWS_ENV_TEST'] = 'foo'
+          ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
         end
 
         it "should update the ruby ENV object when it deletes the key" do
           provider.action_delete
-          expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql(nil)
+          expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql(nil)
         end
       end
     end
   end
 
-  context 'when environment is PATH' do
+  context "when environment is PATH" do
     describe "for PATH" do
-      let(:system_root) {'%SystemRoot%'}
+      let(:system_root) { "%SystemRoot%" }
       let(:system_root_value) { 'D:\Windows' }
       let(:new_resource) {
-        new_resource = Chef::Resource::Env.new('PATH')
+        new_resource = Chef::Resource::Env.new("PATH")
         new_resource.value(system_root)
         new_resource
       }
-      let(:provider) { 
-        provider = Chef::Provider::Env::Windows.new(new_resource, run_context) 
-        allow(provider).to receive(:env_obj).and_return(double('null object').as_null_object)
+      let(:provider) {
+        provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
+        allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
         provider
       }
 
       before do
-        stub_const('ENV', {'PATH' => ''})
+        stub_const("ENV", { "PATH" => "" })
       end
 
       it "replaces Windows system variables" do
         expect(provider).to receive(:requires_modify_or_create?).and_return(true)
         expect(provider).to receive(:expand_path).with(system_root).and_return(system_root_value)
         provider.action_modify
-        expect(ENV['PATH']).to eql(system_root_value)
+        expect(ENV["PATH"]).to eql(system_root_value)
       end
     end
 
diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb
index 230603d..e99aee5 100644
--- a/spec/unit/provider/env_spec.rb
+++ b/spec/unit/provider/env_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Env do
 
@@ -199,12 +199,12 @@ describe Chef::Provider::Env do
       expect(@new_resource).to be_updated
     end
 
-    context "when new_resource's value contains the delimiter"  do
+    context "when new_resource's value contains the delimiter" do
       it "should return false if all the elements are deleted" do
         # This indicates that the entire key needs to be deleted
         @new_resource.value("C:/foo/bin;C:/bar/bin")
         expect(@provider.delete_element).to eql(false)
-        expect(@new_resource).not_to be_updated  # This will be updated in action_delete
+        expect(@new_resource).not_to be_updated # This will be updated in action_delete
       end
 
       it "should return true if any, but not all, of the elements are deleted" do
@@ -251,7 +251,7 @@ describe Chef::Provider::Env do
       expect(@provider.requires_modify_or_create?).to be_truthy
     end
 
-    context "when new_resource's value contains the delimiter"  do
+    context "when new_resource's value contains the delimiter" do
       it "should return false if all the current values are contained in specified order" do
         @new_resource.value("C:/biz;C:/baz")
         @new_resource.delim(";")
diff --git a/spec/unit/provider/erl_call_spec.rb b/spec/unit/provider/erl_call_spec.rb
index 2fb7e5b..f1c2290 100644
--- a/spec/unit/provider/erl_call_spec.rb
+++ b/spec/unit/provider/erl_call_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::ErlCall do
   before(:each) do
@@ -33,7 +33,7 @@ describe Chef::Provider::ErlCall do
 
     allow(@provider).to receive(:popen4).and_return(@status)
     @stdin = StringIO.new
-    @stdout = StringIO.new('{ok, woohoo}')
+    @stdout = StringIO.new("{ok, woohoo}")
     @stderr = StringIO.new
     @pid = 2342999
   end
@@ -83,4 +83,3 @@ describe Chef::Provider::ErlCall do
   end
 
 end
-
diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb
index 51305b6..c0646f2 100644
--- a/spec/unit/provider/execute_spec.rb
+++ b/spec/unit/provider/execute_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Execute do
 
@@ -25,6 +25,8 @@ describe Chef::Provider::Execute do
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
   let(:provider) { Chef::Provider::Execute.new(new_resource, run_context) }
   let(:current_resource) { Chef::Resource::Ifconfig.new("foo_resource", run_context) }
+  # You will be the same object, I promise.
+  @live_stream = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
 
   let(:opts) do
     {
@@ -32,21 +34,23 @@ describe Chef::Provider::Execute do
       returns:      0,
       log_level:    :info,
       log_tag:      new_resource.to_s,
-      live_stream:  STDOUT,
     }
   end
 
   let(:new_resource) { Chef::Resource::Execute.new("foo_resource", run_context) }
 
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(Chef::EventDispatch::EventsOutputStream).to receive(:new) { @live_stream }
+    allow(ChefConfig).to receive(:windows?) { false }
     @original_log_level = Chef::Log.level
     Chef::Log.level = :info
-    allow(STDOUT).to receive(:tty?).and_return(true)
+    allow(STDOUT).to receive(:tty?).and_return(false)
   end
 
   after do
     Chef::Log.level = @original_log_level
+    Chef::Config[:always_stream_execute] = false
+    Chef::Config[:daemon] = false
   end
 
   describe "#initialize" do
@@ -126,7 +130,7 @@ describe Chef::Provider::Execute do
         expect(Chef::Log).to receive(:warn).with(/relative path/)
         expect(FileTest).to receive(:exist?).with(new_resource.creates).and_return(true)
         expect(provider).not_to receive(:shell_out!)
-        expect { provider.run_action(:run) }.to raise_error  # @todo: add a real error for Chef-13
+        expect { provider.run_action(:run) }.to raise_error # @todo: add a real error for Chef-13
       end
     end
 
@@ -142,35 +146,98 @@ describe Chef::Provider::Execute do
       expect(new_resource).not_to be_updated
     end
 
-    it "should unset the live_stream if STDOUT is not a tty" do
-      expect(STDOUT).to receive(:tty?).and_return(false)
+    it "should not include stdout/stderr in failure exception for sensitive resource" do
       opts.delete(:live_stream)
-      expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
-      expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
-      expect(Chef::Log).not_to receive(:warn)
-      provider.run_action(:run)
-      expect(new_resource).to be_updated
+      new_resource.sensitive true
+      expect(provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+      expect do
+        provider.run_action(:run)
+      end.to raise_error(Mixlib::ShellOut::ShellCommandFailed, /suppressed for sensitive resource/)
     end
 
-    it "should unset the live_stream if chef is running as a daemon" do
-      allow(Chef::Config).to receive(:[]).and_call_original
-      expect(Chef::Config).to receive(:[]).with(:daemon).and_return(true)
-      opts.delete(:live_stream)
-      expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
-      expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
-      expect(Chef::Log).not_to receive(:warn)
-      provider.run_action(:run)
-      expect(new_resource).to be_updated
-    end
+    describe "streaming output" do
+      it "should not set the live_stream if sensitive is on" do
+        new_resource.sensitive true
+        expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+        expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+        expect(Chef::Log).not_to receive(:warn)
+        provider.run_action(:run)
+        expect(new_resource).to be_updated
+      end
 
-    it "should unset the live_stream if we are not running with a log level of at least :info" do
-      expect(Chef::Log).to receive(:info?).and_return(false)
-      opts.delete(:live_stream)
-      expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
-      expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
-      expect(Chef::Log).not_to receive(:warn)
-      provider.run_action(:run)
-      expect(new_resource).to be_updated
+      describe "with an output formatter listening" do
+        let(:events) { d = Chef::EventDispatch::Dispatcher.new; d.register(Chef::Formatters::Doc.new(StringIO.new, StringIO.new)); d }
+
+        before do
+          Chef::Config[:stream_execute_output] = true
+        end
+
+        it "should set the live_stream if the log level is info or above" do
+          nopts = opts
+          nopts[:live_stream] = @live_stream
+          expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+          expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+
+        it "should set the live_stream if the resource requests live streaming" do
+          Chef::Log.level = :warn
+          new_resource.live_stream true
+          nopts = opts
+          nopts[:live_stream] = @live_stream
+          expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+          expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+
+        it "should not set the live_stream if the resource is sensitive" do
+          new_resource.sensitive true
+          expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+          expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+      end
+
+      describe "with only logging enabled" do
+        it "should set the live_stream to STDOUT if we are a TTY, not daemonized, not sensitive, and info is enabled" do
+          nopts = opts
+          nopts[:live_stream] = STDOUT
+          allow(STDOUT).to receive(:tty?).and_return(true)
+          expect(provider).to receive(:shell_out!).with(new_resource.name, nopts)
+          expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+
+        it "should not set the live_stream to STDOUT if we are a TTY, not daemonized, but sensitive" do
+          new_resource.sensitive true
+          allow(STDOUT).to receive(:tty?).and_return(true)
+          expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+          expect(provider).to receive(:converge_by).with("execute sensitive resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+
+        it "should not set the live_stream to STDOUT if we are a TTY, but daemonized" do
+          Chef::Config[:daemon] = true
+          allow(STDOUT).to receive(:tty?).and_return(true)
+          expect(provider).to receive(:shell_out!).with(new_resource.name, opts)
+          expect(provider).to receive(:converge_by).with("execute foo_resource").and_call_original
+          expect(Chef::Log).not_to receive(:warn)
+          provider.run_action(:run)
+          expect(new_resource).to be_updated
+        end
+
+      end
     end
+
   end
 end
diff --git a/spec/unit/provider/file/content_spec.rb b/spec/unit/provider/file/content_spec.rb
index 0a45d15..ebef4fa 100644
--- a/spec/unit/provider/file/content_spec.rb
+++ b/spec/unit/provider/file/content_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::File::Content do
 
@@ -89,7 +89,7 @@ describe Chef::Provider::File::Content do
 
       it "fails when :file_desployment_uses_destdir is set" do
         Chef::Config[:file_staging_uses_destdir] = true
-        expect{content.tempfile}.to raise_error
+        expect { content.tempfile }.to raise_error
       end
 
       it "returns a tempfile in the tempdir when :file_desployment_uses_destdir is not set" do
diff --git a/spec/unit/provider/file_spec.rb b/spec/unit/provider/file_spec.rb
index 504ae04..11bef8a 100644
--- a/spec/unit/provider/file_spec.rb
+++ b/spec/unit/provider/file_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'support/shared/unit/provider/file'
+require "support/shared/unit/provider/file"
 
 describe Chef::Provider::File do
 
@@ -29,12 +29,12 @@ describe Chef::Provider::File do
   end
 
   let(:content) do
-    content = double('Chef::Provider::File::Content')
+    content = double("Chef::Provider::File::Content")
   end
 
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
   let(:enclosing_directory) {
     canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
   }
@@ -54,4 +54,3 @@ describe Chef::Provider::File do
 
   it_behaves_like "a file provider with content field"
 end
-
diff --git a/spec/unit/provider/git_spec.rb b/spec/unit/provider/git_spec.rb
index 0106244..97f04a5 100644
--- a/spec/unit/provider/git_spec.rb
+++ b/spec/unit/provider/git_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
+require "spec_helper"
 describe Chef::Provider::Git do
 
   before(:each) do
@@ -59,7 +58,7 @@ describe Chef::Provider::Git do
     it "determines the current revision when there is one" do
       expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
       @stdout = "9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\n"
-      expect(@provider).to receive(:shell_out!).with('git rev-parse HEAD', {:cwd => '/my/deploy/dir', :returns => [0,128]}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with("git rev-parse HEAD", { :cwd => "/my/deploy/dir", :returns => [0, 128] }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.find_current_revision).to eql("9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13")
     end
 
@@ -67,7 +66,7 @@ describe Chef::Provider::Git do
       expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
       @stderr = "fatal: Not a git repository (or any of the parent directories): .git"
       @stdout = ""
-      expect(@provider).to receive(:shell_out!).with('git rev-parse HEAD', :cwd => '/my/deploy/dir', :returns => [0,128]).and_return(double("ShellOut result", :stdout => "", :stderr => @stderr))
+      expect(@provider).to receive(:shell_out!).with("git rev-parse HEAD", :cwd => "/my/deploy/dir", :returns => [0, 128]).and_return(double("ShellOut result", :stdout => "", :stderr => @stderr))
       expect(@provider.find_current_revision).to be_nil
     end
   end
@@ -98,7 +97,7 @@ describe Chef::Provider::Git do
       @resource.revision "v1.0"
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
                  "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -107,7 +106,7 @@ describe Chef::Provider::Git do
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
                  "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n" +
                  "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0^{}\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("663c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -116,7 +115,7 @@ describe Chef::Provider::Git do
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
                  "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/releases/v1.0\n" +
                  "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -125,7 +124,7 @@ describe Chef::Provider::Git do
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
           "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
           "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("663c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -134,7 +133,7 @@ describe Chef::Provider::Git do
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
           "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.1\n" +
           "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -144,7 +143,7 @@ describe Chef::Provider::Git do
           "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
           "805c22a5e41f5ae3193460cca044ed1435029f53\trefs/pulls/v1.0\n" +
           "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/pulls/v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("805c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -153,7 +152,7 @@ describe Chef::Provider::Git do
       @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" +
           "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/tags/v1.0\n" +
           "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n")
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"refs/heads/v1.0*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("503c22a5e41f5ae3193460cca044ed1435029f53")
     end
 
@@ -162,7 +161,7 @@ describe Chef::Provider::Git do
       @provider.action = :checkout
       @provider.define_resource_requirements
       allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-      expect {@provider.process_resource_requirements}.to raise_error(Chef::Exceptions::InvalidRemoteGitReference)
+      expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::InvalidRemoteGitReference)
     end
 
     it "raises an unresolvable git reference error if the revision can't be resolved to any revision and assertions are run" do
@@ -182,7 +181,7 @@ describe Chef::Provider::Git do
     it "does not raise an error when the revision is valid and assertions are run." do
       @resource.revision "0.8-alpha"
       @stdout = "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n"
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"0.8-alpha*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"0.8-alpha*\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       @provider.action = :checkout
       allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
       @provider.define_resource_requirements
@@ -190,7 +189,7 @@ describe Chef::Provider::Git do
     end
 
     it "gives the latest HEAD revision SHA if nothing is specified" do
-      @stdout =<<-SHAS
+      @stdout = <<-SHAS
 28af684d8460ba4793eda3e7ac238c864a5d029a\tHEAD
 503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha
 28af684d8460ba4793eda3e7ac238c864a5d029a\trefs/heads/master
@@ -206,8 +205,8 @@ d7b9957f67236fa54e660cc3ab45ffecd6e0ba38\trefs/tags/0.7.8
 b7d19519a1c15f1c1a324e2683bd728b6198ce5a\trefs/tags/0.7.8^{}
 ebc1b392fe7e8f0fbabc305c299b4d365d2b4d9b\trefs/tags/chef-server-package
 SHAS
-      @resource.revision ''
-      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"HEAD\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout))
+      @resource.revision ""
+      expect(@provider).to receive(:shell_out!).with(@git_ls_remote + "\"HEAD\"", { :log_tag => "git[web2.0 app]" }).and_return(double("ShellOut result", :stdout => @stdout))
       expect(@provider.target_revision).to eql("28af684d8460ba4793eda3e7ac238c864a5d029a")
     end
   end
@@ -224,7 +223,7 @@ SHAS
       {
         :user => deploy_user,
         :environment => { "GIT_SSH" => wrapper, "HOME" => "/home/deployNinja" },
-        :log_tag => "git[web2.0 app]"
+        :log_tag => "git[web2.0 app]",
       }
     end
     before do
@@ -248,13 +247,13 @@ SHAS
     end
     context "with a specific home" do
       let (:override_home) do
-        {"HOME" => "/home/masterNinja"}
+        { "HOME" => "/home/masterNinja" }
       end
       let(:overrided_options) do
         {
           :user => deploy_user,
           :environment => { "GIT_SSH" => wrapper, "HOME" => "/home/masterNinja" },
-          :log_tag => "git[web2.0 app]"
+          :log_tag => "git[web2.0 app]",
         }
       end
       before do
@@ -275,17 +274,17 @@ SHAS
     @resource.ssh_wrapper "do_it_this_way.sh"
     expected_cmd = "git clone  \"git://github.com/opscode/chef.git\" \"/Application Support/with/space\""
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :user => "deployNinja",
-                                                :environment =>{"GIT_SSH"=>"do_it_this_way.sh",
-                                                                "HOME" => "/home/deployNinja"},
-                                                :log_tag => "git[web2.0 app]")
+                                                                 :environment => { "GIT_SSH" => "do_it_this_way.sh",
+                                                                                   "HOME" => "/home/deployNinja" },
+                                                                 :log_tag => "git[web2.0 app]")
     @provider.clone
   end
 
   it "compiles a clone command using --depth for shallow cloning" do
     @resource.depth 5
     expected_cmd = "git clone --depth 5 \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\""
-    version_response = double('shell_out')
-    allow(version_response).to receive(:stdout) { 'git version 1.7.9' }
+    version_response = double("shell_out")
+    allow(version_response).to receive(:stdout) { "git version 1.7.9" }
     expect(@provider).to receive(:shell_out!).with("git --version",
                                                :log_tag => "git[web2.0 app]").and_return(version_response)
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]")
@@ -295,8 +294,8 @@ SHAS
   it "compiles a clone command using --no-single-branch for shallow cloning when git >= 1.7.10" do
     @resource.depth 5
     expected_cmd = "git clone --depth 5 --no-single-branch \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\""
-    version_response = double('shell_out')
-    allow(version_response).to receive(:stdout) { 'git version 1.7.10' }
+    version_response = double("shell_out")
+    allow(version_response).to receive(:stdout) { "git version 1.7.10" }
     expect(@provider).to receive(:shell_out!).with("git --version",
                                                :log_tag => "git[web2.0 app]").and_return(version_response)
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]")
@@ -311,10 +310,10 @@ SHAS
   end
 
   it "runs a checkout command with default options" do
-    expect(@provider).to receive(:shell_out!).with('git branch -f deploy d35af14d41ae22b19da05d7d03a0bafc321b244c', :cwd => "/my/deploy/dir",
-                                                             :log_tag => "git[web2.0 app]").ordered
-    expect(@provider).to receive(:shell_out!).with('git checkout deploy', :cwd => "/my/deploy/dir",
-                                                             :log_tag => "git[web2.0 app]").ordered
+    expect(@provider).to receive(:shell_out!).with("git branch -f deploy d35af14d41ae22b19da05d7d03a0bafc321b244c", :cwd => "/my/deploy/dir",
+                                                                                                                    :log_tag => "git[web2.0 app]").ordered
+    expect(@provider).to receive(:shell_out!).with("git checkout deploy", :cwd => "/my/deploy/dir",
+                                                                          :log_tag => "git[web2.0 app]").ordered
     @provider.checkout
   end
 
@@ -322,7 +321,7 @@ SHAS
     @resource.enable_submodules true
     expected_cmd = "git submodule sync"
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir",
-                                                             :log_tag => "git[web2.0 app]")
+                                                                 :log_tag => "git[web2.0 app]")
     expected_cmd = "git submodule update --init --recursive"
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
     @provider.enable_submodules
@@ -336,7 +335,7 @@ SHAS
   it "runs a sync command with default options" do
     expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
     expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
-    expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd=> "/my/deploy/dir", :log_tag => "git[web2.0 app]")
+    expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]")
     @provider.fetch_updates
   end
 
@@ -347,9 +346,9 @@ SHAS
     expect(@provider).to receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository)
     expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c"
     expect(@provider).to receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir",
-                                                :user => "whois", :group => "thisis",
-                                                :log_tag => "git[web2.0 app]",
-                                                :environment=>{"HOME"=>"/home/whois"})
+                                                                 :user => "whois", :group => "thisis",
+                                                                 :log_tag => "git[web2.0 app]",
+                                                                 :environment => { "HOME" => "/home/whois" })
     @provider.fetch_updates
   end
 
@@ -372,13 +371,13 @@ SHAS
   context "configuring remote tracking branches" do
 
     it "checks if a remote with this name already exists" do
-      command_response = double('shell_out')
+      command_response = double("shell_out")
       allow(command_response).to receive(:exitstatus) { 1 }
       expected_command = "git config --get remote.#{@resource.remote}.url"
       expect(@provider).to receive(:shell_out!).with(expected_command,
                                                  :cwd => "/my/deploy/dir",
                                                  :log_tag => "git[web2.0 app]",
-                                                 :returns => [0,1,2]).and_return(command_response)
+                                                 :returns => [0, 1, 2]).and_return(command_response)
       add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}"
       expect(@provider).to receive(:shell_out!).with(add_remote_command,
                                                  :cwd => "/my/deploy/dir",
@@ -390,7 +389,7 @@ SHAS
       @resource.user("whois")
       @resource.group("thisis")
       allow(Etc).to receive(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/whois"))
-      command_response = double('shell_out')
+      command_response = double("shell_out")
       allow(command_response).to receive(:exitstatus) { 1 }
       expected_command = "git config --get remote.#{@resource.remote}.url"
       expect(@provider).to receive(:shell_out!).with(expected_command,
@@ -398,27 +397,27 @@ SHAS
                                                  :log_tag => "git[web2.0 app]",
                                                  :user => "whois",
                                                  :group => "thisis",
-                                                 :environment=>{"HOME"=>"/home/whois"},
-                                                 :returns => [0,1,2]).and_return(command_response)
+                                                 :environment => { "HOME" => "/home/whois" },
+                                                 :returns => [0, 1, 2]).and_return(command_response)
       add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}"
       expect(@provider).to receive(:shell_out!).with(add_remote_command,
                                                  :cwd => "/my/deploy/dir",
                                                  :log_tag => "git[web2.0 app]",
                                                  :user => "whois",
                                                  :group => "thisis",
-                                                 :environment=>{"HOME"=>"/home/whois"})
+                                                 :environment => { "HOME" => "/home/whois" })
       @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository)
     end
 
     describe "when a remote with a given name hasn't been configured yet" do
       it "adds a new remote " do
-        command_response = double('shell_out')
+        command_response = double("shell_out")
         allow(command_response).to receive(:exitstatus) { 1 }
         check_remote_command = "git config --get remote.#{@resource.remote}.url"
         expect(@provider).to receive(:shell_out!).with(check_remote_command,
                                                    :cwd => "/my/deploy/dir",
                                                    :log_tag => "git[web2.0 app]",
-                                                   :returns => [0,1,2]).and_return(command_response)
+                                                   :returns => [0, 1, 2]).and_return(command_response)
         expected_command = "git remote add #{@resource.remote} #{@resource.repository}"
         expect(@provider).to receive(:shell_out!).with(expected_command,
                                                    :cwd => "/my/deploy/dir",
@@ -429,14 +428,14 @@ SHAS
 
     describe "when a remote with a given name has already been configured" do
       it "updates remote url when the url is different" do
-        command_response = double('shell_out')
+        command_response = double("shell_out")
         allow(command_response).to receive(:exitstatus) { 0 }
         allow(command_response).to receive(:stdout) { "some_other_url" }
         check_remote_command = "git config --get remote.#{@resource.remote}.url"
         expect(@provider).to receive(:shell_out!).with(check_remote_command,
                                                    :cwd => "/my/deploy/dir",
                                                    :log_tag => "git[web2.0 app]",
-                                                   :returns => [0,1,2]).and_return(command_response)
+                                                   :returns => [0, 1, 2]).and_return(command_response)
         expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
         expect(@provider).to receive(:shell_out!).with(expected_command,
                                                    :cwd => "/my/deploy/dir",
@@ -445,14 +444,14 @@ SHAS
       end
 
       it "doesn't update remote url when the url is the same" do
-        command_response = double('shell_out')
+        command_response = double("shell_out")
         allow(command_response).to receive(:exitstatus) { 0 }
         allow(command_response).to receive(:stdout) { @resource.repository }
         check_remote_command = "git config --get remote.#{@resource.remote}.url"
         expect(@provider).to receive(:shell_out!).with(check_remote_command,
                                                    :cwd => "/my/deploy/dir",
                                                    :log_tag => "git[web2.0 app]",
-                                                   :returns => [0,1,2]).and_return(command_response)
+                                                   :returns => [0, 1, 2]).and_return(command_response)
         unexpected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
         expect(@provider).not_to receive(:shell_out!).with(unexpected_command,
                                                        :cwd => "/my/deploy/dir",
@@ -461,13 +460,13 @@ SHAS
       end
 
       it "resets remote url when it has multiple values" do
-        command_response = double('shell_out')
+        command_response = double("shell_out")
         allow(command_response).to receive(:exitstatus) { 2 }
         check_remote_command = "git config --get remote.#{@resource.remote}.url"
         expect(@provider).to receive(:shell_out!).with(check_remote_command,
                                                    :cwd => "/my/deploy/dir",
                                                    :log_tag => "git[web2.0 app]",
-                                                   :returns => [0,1,2]).and_return(command_response)
+                                                   :returns => [0, 1, 2]).and_return(command_response)
         expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}"
         expect(@provider).to receive(:shell_out!).with(expected_command,
                                                    :cwd => "/my/deploy/dir",
@@ -479,7 +478,7 @@ SHAS
 
   it "raises an error if the git clone command would fail because the enclosing directory doesn't exist" do
     allow(@provider).to receive(:shell_out!)
-    expect {@provider.run_action(:sync)}.to raise_error(Chef::Exceptions::MissingParentDirectory)
+    expect { @provider.run_action(:sync) }.to raise_error(Chef::Exceptions::MissingParentDirectory)
   end
 
   it "does a checkout by cloning the repo and then enabling submodules" do
@@ -488,7 +487,7 @@ SHAS
 
     allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..'])
+    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", ".."])
     expect(@provider).to receive(:clone)
     expect(@provider).to receive(:checkout)
     expect(@provider).to receive(:enable_submodules)
@@ -504,7 +503,7 @@ SHAS
 
     allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..'])
+    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", ".."])
 
     @resource.enable_checkout false
     expect(@provider).to receive(:clone)
@@ -519,7 +518,7 @@ SHAS
     allow(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(false)
     allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(false)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['..','.'])
+    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(["..", "."])
     expect(@provider).to receive(:clone)
     expect(@provider).to receive(:checkout)
     expect(@provider).to receive(:enable_submodules)
@@ -534,7 +533,7 @@ SHAS
 
     allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar'])
+    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", "..", "foo", "bar"])
     expect(@provider).not_to receive(:clone)
     expect(@provider).not_to receive(:checkout)
     expect(@provider).not_to receive(:enable_submodules)
@@ -546,7 +545,7 @@ SHAS
   it "syncs the code by updating the source when the repo has already been checked out" do
     expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    expect(@provider).to receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
+    expect(@provider).to receive(:find_current_revision).exactly(1).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
     expect(@provider).not_to receive(:fetch_updates)
     expect(@provider).to receive(:add_remotes)
     @provider.run_action(:sync)
@@ -557,8 +556,8 @@ SHAS
     expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
     # invoked twice - first time from load_current_resource
-    expect(@provider).to receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
-    allow(@provider).to receive(:target_revision).and_return('28af684d8460ba4793eda3e7ac238c864a5d029a')
+    expect(@provider).to receive(:find_current_revision).exactly(1).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
+    allow(@provider).to receive(:target_revision).and_return("28af684d8460ba4793eda3e7ac238c864a5d029a")
     expect(@provider).to receive(:fetch_updates)
     expect(@provider).to receive(:enable_submodules)
     expect(@provider).to receive(:add_remotes)
@@ -569,8 +568,8 @@ SHAS
   it "does not fetch any updates if the remote revision matches the current revision" do
     expect(::File).to receive(:exist?).with("/my/deploy/dir/.git").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(@provider).to receive(:find_current_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
-    allow(@provider).to receive(:target_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c')
+    allow(@provider).to receive(:find_current_revision).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
+    allow(@provider).to receive(:target_revision).and_return("d35af14d41ae22b19da05d7d03a0bafc321b244c")
     expect(@provider).not_to receive(:fetch_updates)
     expect(@provider).to receive(:add_remotes)
     @provider.run_action(:sync)
@@ -606,10 +605,10 @@ SHAS
 
   describe "calling add_remotes" do
     it "adds a new remote for each entry in additional remotes hash" do
-      @resource.additional_remotes({:opscode => "opscode_repo_url",
-        :another_repo => "some_other_repo_url"})
+      @resource.additional_remotes({ :opscode => "opscode_repo_url",
+                                     :another_repo => "some_other_repo_url" })
       allow(STDOUT).to receive(:tty?).and_return(false)
-      command_response = double('shell_out')
+      command_response = double("shell_out")
       allow(command_response).to receive(:exitstatus) { 0 }
       @resource.additional_remotes.each_pair do |remote_name, remote_url|
         expect(@provider).to receive(:setup_remote_tracking_branches).with(remote_name, remote_url)
@@ -620,7 +619,7 @@ SHAS
 
   describe "calling multiple_remotes?" do
     before(:each) do
-      @command_response = double('shell_out')
+      @command_response = double("shell_out")
     end
 
     describe "when check remote command returns with status 2" do
@@ -647,7 +646,7 @@ SHAS
 
   describe "calling remote_matches?" do
     before(:each) do
-      @command_response = double('shell_out')
+      @command_response = double("shell_out")
     end
 
     describe "when output of the check remote command matches the repository url" do
diff --git a/spec/unit/provider/group/dscl_spec.rb b/spec/unit/provider/group/dscl_spec.rb
index d84e4e1..52aff87 100644
--- a/spec/unit/provider/group/dscl_spec.rb
+++ b/spec/unit/provider/group/dscl_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dreamcat4 (<dreamcat4 at gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Dscl do
   before do
@@ -40,7 +40,7 @@ describe Chef::Provider::Group::Dscl do
   it "should return an array of four elements - cmd, status, stdout, stderr" do
     dscl_retval = @provider.dscl("cmd /Path args")
     expect(dscl_retval).to be_a_kind_of(Array)
-    expect(dscl_retval).to eq(["dscl . -cmd /Path args", at status,"\n",""])
+    expect(dscl_retval).to eq(["dscl . -cmd /Path args", @status, "\n", ""])
   end
 
   describe "safe_dscl" do
@@ -293,7 +293,7 @@ describe Chef::Provider::Group::Dscl do
   end
 end
 
-describe 'Test DSCL loading' do
+describe "Test DSCL loading" do
   before do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
@@ -320,12 +320,12 @@ EOF
 
   end
 
-  it 'should parse gid properly' do
+  it "should parse gid properly" do
     allow(File).to receive(:exists?).and_return(true)
     expect(@current_resource.gid).to eq("999")
   end
-  it 'should parse members properly' do
+  it "should parse members properly" do
     allow(File).to receive(:exists?).and_return(true)
-    expect(@current_resource.members).to eq(['waka', 'bar'])
+    expect(@current_resource.members).to eq(["waka", "bar"])
   end
 end
diff --git a/spec/unit/provider/group/gpasswd_spec.rb b/spec/unit/provider/group/gpasswd_spec.rb
index 55d978f..16e6ad1 100644
--- a/spec/unit/provider/group/gpasswd_spec.rb
+++ b/spec/unit/provider/group/gpasswd_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Gpasswd, "modify_group_members" do
   before do
diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb
index 94150b7..b4295c9 100644
--- a/spec/unit/provider/group/groupadd_spec.rb
+++ b/spec/unit/provider/group/groupadd_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Groupadd, "set_options" do
   before do
@@ -42,10 +42,10 @@ describe Chef::Provider::Group::Groupadd, "set_options" do
   }
 
   field_list.each do |attribute, option|
-    it "should check for differences in #{attribute.to_s} between the current and new resources" do
-        expect(@new_resource).to receive(attribute)
-        expect(@current_resource).to receive(attribute)
-        @provider.set_options
+    it "should check for differences in #{attribute} between the current and new resources" do
+      expect(@new_resource).to receive(attribute)
+      expect(@current_resource).to receive(attribute)
+      @provider.set_options
     end
     it "should set the option for #{attribute} if the new resources #{attribute} is not null" do
       allow(@new_resource).to receive(attribute).and_return("wowaweea")
@@ -55,7 +55,7 @@ describe Chef::Provider::Group::Groupadd, "set_options" do
 
   it "should combine all the possible options" do
     match_string = ""
-    field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+    field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
       allow(@new_resource).to receive(attribute).and_return("hola")
       match_string << " #{option} 'hola'"
     end
@@ -145,7 +145,7 @@ describe Chef::Provider::Group::Groupadd do
 
   [:add_member, :remove_member, :set_members].each do |m|
     it "should raise an error when calling #{m}" do
-      expect { @provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{@provider.to_s}")
+      expect { @provider.send(m, [ ]) }.to raise_error(Chef::Exceptions::Group, "you must override #{m} in #{@provider}")
     end
   end
 
diff --git a/spec/unit/provider/group/groupmod_spec.rb b/spec/unit/provider/group/groupmod_spec.rb
index 496d1e2..21d0264 100644
--- a/spec/unit/provider/group/groupmod_spec.rb
+++ b/spec/unit/provider/group/groupmod_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dan Crosta (<dcrosta at late.am>)
-# Copyright:: Copyright (c) 2012 OpsCode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,19 +16,19 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Groupmod do
-    before do
-      @node = Chef::Node.new
-      @events = Chef::EventDispatch::Dispatcher.new
-      @run_context = Chef::RunContext.new(@node, {}, @events)
-      @new_resource = Chef::Resource::Group.new("wheel")
-      @new_resource.gid 123
-      @new_resource.members %w{lobster rage fist}
-      @new_resource.append false
-      @provider = Chef::Provider::Group::Groupmod.new(@new_resource, @run_context)
-    end
+  before do
+    @node = Chef::Node.new
+    @events = Chef::EventDispatch::Dispatcher.new
+    @run_context = Chef::RunContext.new(@node, {}, @events)
+    @new_resource = Chef::Resource::Group.new("wheel")
+    @new_resource.gid 123
+    @new_resource.members %w{lobster rage fist}
+    @new_resource.append false
+    @provider = Chef::Provider::Group::Groupmod.new(@new_resource, @run_context)
+  end
 
   describe "manage_group" do
     describe "when determining the current group state" do
diff --git a/spec/unit/provider/group/pw_spec.rb b/spec/unit/provider/group/pw_spec.rb
index af74b3b..2c56375 100644
--- a/spec/unit/provider/group/pw_spec.rb
+++ b/spec/unit/provider/group/pw_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Pw do
   before do
@@ -119,7 +119,7 @@ describe Chef::Provider::Group::Pw do
     end
   end
 
-  describe"load_current_resource" do
+  describe "load_current_resource" do
     before (:each) do
       @provider.action = :create
       @provider.load_current_resource
diff --git a/spec/unit/provider/group/usermod_spec.rb b/spec/unit/provider/group/usermod_spec.rb
index 3f06e9e..1a718b1 100644
--- a/spec/unit/provider/group/usermod_spec.rb
+++ b/spec/unit/provider/group/usermod_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Group::Usermod do
   before do
@@ -52,7 +52,7 @@ describe Chef::Provider::Group::Usermod do
         "suse" => "-a -G",
         "opensuse" => "-a -G",
         "smartos" => "-G",
-        "omnios" => "-G"
+        "omnios" => "-G",
       }
 
       before do
@@ -65,7 +65,7 @@ describe Chef::Provider::Group::Usermod do
         @provider.load_current_resource
         @provider.instance_variable_set("@group_exists", true)
         @provider.action = :modify
-        expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider.to_s}, must set append true in group")
+        expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider}, must set append true in group")
       end
 
       it "should raise an error when excluded_members are set" do
@@ -75,7 +75,7 @@ describe Chef::Provider::Group::Usermod do
         @provider.action = :modify
         allow(@new_resource).to receive(:append).and_return(true)
         allow(@new_resource).to receive(:excluded_members).and_return(["someone"])
-        expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "excluded_members is not supported by #{@provider.to_s}")
+        expect { @provider.run_action(@provider.process_resource_requirements) }.to raise_error(Chef::Exceptions::Group, "excluded_members is not supported by #{@provider}")
       end
 
       platforms.each do |platform, flags|
diff --git a/spec/unit/provider/group/windows_spec.rb b/spec/unit/provider/group/windows_spec.rb
index 23dfa83..c331e2b 100644
--- a/spec/unit/provider/group/windows_spec.rb
+++ b/spec/unit/provider/group/windows_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class Chef
   class Util
@@ -94,7 +94,7 @@ describe Chef::Provider::Group::Windows, "NetGroup" do
     @new_resource = Chef::Resource::Group.new("Creating a new group")
     @new_resource.group_name "Remote Desktop Users"
   end
-  it 'sets group_name correctly' do
+  it "sets group_name correctly" do
     expect(Chef::Util::Windows::NetGroup).to receive(:new).with("Remote Desktop Users")
     Chef::Provider::Group::Windows.new(@new_resource, @run_context)
   end
diff --git a/spec/unit/provider/group_spec.rb b/spec/unit/provider/group_spec.rb
index b36bfe3..d41b068 100644
--- a/spec/unit/provider/group_spec.rb
+++ b/spec/unit/provider/group_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::User do
 
@@ -39,9 +39,9 @@ describe Chef::Provider::User do
     @pw_group = double("Struct::Group",
       :name => "wheel",
       :gid => 20,
-      :mem => [ "root", "aj" ]
+      :mem => [ "root", "aj" ],
       )
-    allow(Etc).to receive(:getgrnam).with('wheel').and_return(@pw_group)
+    allow(Etc).to receive(:getgrnam).with("wheel").and_return(@pw_group)
   end
 
   it "assumes the group exists by default" do
@@ -52,7 +52,7 @@ describe Chef::Provider::User do
 
     it "sets the group name of the current resource to the group name of the new resource" do
       @provider.load_current_resource
-      expect(@provider.current_resource.group_name).to eq('wheel')
+      expect(@provider.current_resource.group_name).to eq("wheel")
     end
 
     it "does not modify the desired gid if set" do
@@ -120,7 +120,7 @@ describe Chef::Provider::User do
     end
 
     it "should return true if the append is true and excluded_members include an existing user" do
-      @new_resource.members.each {|m| @new_resource.excluded_members << m }
+      @new_resource.members.each { |m| @new_resource.excluded_members << m }
       @new_resource.members.clear
       allow(@new_resource).to receive(:append).and_return(true)
       expect(@provider.compare_group).to be_truthy
@@ -256,18 +256,18 @@ describe Chef::Provider::User do
 
   describe "when determining the reason for a change" do
     it "should report which group members are missing if members are missing and appending to the group" do
-       @new_resource.members << "user1"
-       @new_resource.members << "user2"
-       allow(@new_resource).to receive(:append).and_return true
-       expect(@provider.compare_group).to be_truthy
-       expect(@provider.change_desc).to eq([ "add missing member(s): user1, user2" ])
+      @new_resource.members << "user1"
+      @new_resource.members << "user2"
+      allow(@new_resource).to receive(:append).and_return true
+      expect(@provider.compare_group).to be_truthy
+      expect(@provider.change_desc).to eq([ "add missing member(s): user1, user2" ])
     end
 
     it "should report that the group members will be overwritten if not appending" do
-       @new_resource.members << "user1"
-       allow(@new_resource).to receive(:append).and_return false
-       expect(@provider.compare_group).to be_truthy
-       expect(@provider.change_desc).to eq([ "replace group members with new list of members" ])
+      @new_resource.members << "user1"
+      allow(@new_resource).to receive(:append).and_return false
+      expect(@provider.compare_group).to be_truthy
+      expect(@provider.change_desc).to eq([ "replace group members with new list of members" ])
     end
 
     it "should report the gid will be changed when it does not match" do
diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb
index a84dd5e..9a3519a 100644
--- a/spec/unit/provider/http_request_spec.rb
+++ b/spec/unit/provider/http_request_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::HttpRequest do
   before(:each) do
@@ -24,7 +24,7 @@ describe Chef::Provider::HttpRequest do
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
-    @new_resource = Chef::Resource::HttpRequest.new('adam')
+    @new_resource = Chef::Resource::HttpRequest.new("adam")
     @new_resource.name "adam"
     @new_resource.url "http://www.opscode.com/"
     @new_resource.message "is cool"
@@ -34,7 +34,7 @@ describe Chef::Provider::HttpRequest do
 
   describe "load_current_resource" do
 
-    it "should set up a Chef::REST client, with no authentication" do
+    it "should set up a Chef::ServerAPI client, with no authentication" do
       expect(Chef::HTTP::Simple).to receive(:new).with(@new_resource.url)
       @provider.load_current_resource
     end
@@ -45,7 +45,7 @@ describe Chef::Provider::HttpRequest do
       # run_action(x) forces load_current_resource to run;
       # that would overwrite our supplied mock Chef::Rest # object
       allow(@provider).to receive(:load_current_resource).and_return(true)
-      @http = double("Chef::REST")
+      @http = double("Chef::ServerAPI")
       @provider.http = @http
     end
 
@@ -138,7 +138,7 @@ describe Chef::Provider::HttpRequest do
       it "should not update a HEAD request if a not modified response (CHEF-4762)" do
         if_modified_since = File.mtime(__FILE__).httpdate
         @new_resource.headers "If-Modified-Since" => if_modified_since
-        expect(@http).to receive(:head).with("http://www.opscode.com/", {"If-Modified-Since" => if_modified_since}).and_return(false)
+        expect(@http).to receive(:head).with("http://www.opscode.com/", { "If-Modified-Since" => if_modified_since }).and_return(false)
         @provider.run_action(:head)
         expect(@new_resource).not_to be_updated
       end
diff --git a/spec/unit/provider/ifconfig/aix_spec.rb b/spec/unit/provider/ifconfig/aix_spec.rb
index 0b6fa33..7847fc9 100644
--- a/spec/unit/provider/ifconfig/aix_spec.rb
+++ b/spec/unit/provider/ifconfig/aix_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
 
 describe Chef::Provider::Ifconfig::Aix do
 
@@ -35,7 +35,6 @@ lo0: flags=e08084b,c0<UP,BROADCAST,LOOPBACK,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64
 IFCONFIG
   end
 
-
   before(:each) do
     @node = Chef::Node.new
     @cookbook_collection = Chef::CookbookCollection.new([])
@@ -87,7 +86,7 @@ IFCONFIG
         @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context))
       end
 
-      expect{@provider.run_action(:add)}.to raise_error(Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action")
+      expect { @provider.run_action(:add) }.to raise_error(Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action")
     end
   end
 
diff --git a/spec/unit/provider/ifconfig/debian_spec.rb b/spec/unit/provider/ifconfig/debian_spec.rb
index 351e734..1f61957 100644
--- a/spec/unit/provider/ifconfig/debian_spec.rb
+++ b/spec/unit/provider/ifconfig/debian_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
 
 describe Chef::Provider::Ifconfig::Debian do
 
@@ -37,7 +37,7 @@ describe Chef::Provider::Ifconfig::Debian do
     new_resource
   end
 
-  let(:current_resource) {  Chef::Resource::Ifconfig.new("10.0.0.1", run_context) }
+  let(:current_resource) { Chef::Resource::Ifconfig.new("10.0.0.1", run_context) }
 
   let(:provider) do
     status = double("Status", :exitstatus => 0)
@@ -120,7 +120,7 @@ iface eth0 inet static
   netmask 255.255.254.0
 EOF
         )
-        expect(File.exists?(tempdir_path)).to be_truthy  # since the file exists, the enclosing dir must also exist
+        expect(File.exists?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
       end
 
       context "when the /etc/network/interfaces file has the source line" do
@@ -144,11 +144,6 @@ EOF
           expect(IO.read(tempfile.path)).to eq(expected_string)
         end
 
-        it "should not mark the resource as updated" do
-          provider.run_action(:add)
-          pending "superclass ifconfig provider is not idempotent"
-          expect(new_resource.updated_by_last_action?).to be_falsey
-        end
       end
 
       context "when the /etc/network/interfaces file does not have the source line" do
@@ -258,7 +253,7 @@ iface eth0 inet static
                                            EOF
                                           )
           expect(File).not_to receive(:new).with(config_filename_ifcfg, "w")
-          expect(File.exists?(tempdir_path)).to be_truthy  # since the file exists, the enclosing dir must also exist
+          expect(File.exists?(tempdir_path)).to be_truthy # since the file exists, the enclosing dir must also exist
         end
 
         context "when the /etc/network/interfaces file has the source line" do
@@ -280,11 +275,6 @@ another line
             expect(IO.read(tempfile.path)).to eq(expected_string)
           end
 
-          it "should not mark the resource as updated" do
-            provider.run_action(:add)
-            pending "superclass ifconfig provider is not idempotent"
-            expect(new_resource.updated_by_last_action?).to be_falsey
-          end
         end
 
         context "when the /etc/network/interfaces file does not have the source line" do
diff --git a/spec/unit/provider/ifconfig/redhat_spec.rb b/spec/unit/provider/ifconfig/redhat_spec.rb
index 620fd34..0088cef 100644
--- a/spec/unit/provider/ifconfig/redhat_spec.rb
+++ b/spec/unit/provider/ifconfig/redhat_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (xabier at onddo.com)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
 
 describe Chef::Provider::Ifconfig::Redhat do
   before do
diff --git a/spec/unit/provider/ifconfig_spec.rb b/spec/unit/provider/ifconfig_spec.rb
index d290ab7..db45640 100644
--- a/spec/unit/provider/ifconfig_spec.rb
+++ b/spec/unit/provider/ifconfig_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Prajakta Purohit (prajakta at opscode.com)
-# Copyright:: Copyright (c) 2008 Opscode Inc.
+# Author:: Prajakta Purohit (prajakta at chef.io)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 #
 
 #require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
-require 'spec_helper'
-require 'chef/exceptions'
+require "spec_helper"
+require "chef/exceptions"
 
 describe Chef::Provider::Ifconfig do
   before do
@@ -39,14 +39,14 @@ describe Chef::Provider::Ifconfig do
     @provider.instance_variable_set("@status", status)
     @provider.current_resource = @current_resource
 
- end
+  end
   describe Chef::Provider::Ifconfig, "load_current_resource" do
     before do
       @status = double(:stdout => "", :exitstatus => 1)
       allow(@provider).to receive(:shell_out).and_return(@status)
       @provider.load_current_resource
     end
-    it "should track state of ifconfig failure." do
+    it "should track state of ifconfig failure" do
       expect(@provider.instance_variable_get("@status").exitstatus).not_to eq(0)
     end
     it "should thrown an exception when ifconfig fails" do
@@ -68,6 +68,16 @@ describe Chef::Provider::Ifconfig do
       expect(@new_resource).to be_updated
     end
 
+    it "should set the address to target if specified" do
+      allow(@provider).to receive(:load_current_resource)
+      @new_resource.target "172.16.32.2"
+      command = "ifconfig eth0 172.16.32.2 netmask 255.255.254.0 metric 1 mtu 1500"
+      expect(@provider).to receive(:run_command).with(:command => command)
+
+      @provider.run_action(:add)
+      expect(@new_resource).to be_updated
+    end
+
     it "should not add an interface if it already exists" do
       allow(@provider).to receive(:load_current_resource)
       expect(@provider).not_to receive(:run_command)
@@ -85,7 +95,7 @@ describe Chef::Provider::Ifconfig do
 
   describe Chef::Provider::Ifconfig, "action_enable" do
 
-    it "should enable interface if does not exist" do
+    it "should enable interface if it does not exist" do
       allow(@provider).to receive(:load_current_resource)
       @current_resource.inet_addr nil
       command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500"
@@ -96,6 +106,16 @@ describe Chef::Provider::Ifconfig do
       expect(@new_resource).to be_updated
     end
 
+    it "should set the address to target if specified" do
+      allow(@provider).to receive(:load_current_resource)
+      @new_resource.target "172.16.32.2"
+      command = "ifconfig eth0 172.16.32.2 netmask 255.255.254.0 metric 1 mtu 1500"
+      expect(@provider).to receive(:run_command).with(:command => command)
+
+      @provider.run_action(:enable)
+      expect(@new_resource).to be_updated
+    end
+
     it "should not enable interface if it already exists" do
       allow(@provider).to receive(:load_current_resource)
       expect(@provider).not_to receive(:run_command)
diff --git a/spec/unit/provider/link_spec.rb b/spec/unit/provider/link_spec.rb
index 0f95ce9..31065d7 100644
--- a/spec/unit/provider/link_spec.rb
+++ b/spec/unit/provider/link_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: AJ Christensen (<aj at junglist.gen.nz>)
-# Author:: John Keiser (<jkeiser at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: John Keiser (<jkeiser at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,12 +17,12 @@
 # limitations under the License.
 #
 
-require 'ostruct'
+require "ostruct"
 
-require 'spec_helper'
+require "spec_helper"
 
 if Chef::Platform.windows?
-  require 'chef/win32/file' #probably need this in spec_helper
+  require "chef/win32/file" #probably need this in spec_helper
 end
 
 describe Chef::Resource::Link, :not_supported_on_win2k3 do
@@ -39,7 +39,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
   end
 
   def canonicalize(path)
-    Chef::Platform.windows? ? path.gsub('/', '\\') : path
+    Chef::Platform.windows? ? path.gsub("/", '\\') : path
   end
 
   describe "when the target is a symlink" do
@@ -80,13 +80,13 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
       # We test create in unit tests because there is no other way to ensure
       # it does no work.  Other create and delete scenarios are covered in
       # the functional tests for links.
-      context 'when the desired state is identical' do
+      context "when the desired state is identical" do
         let(:new_resource) do
           result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link")
           result.to "#{CHEF_SPEC_DATA}/fofile"
           result
         end
-        it 'create does no work' do
+        it "create does no work" do
           expect(provider.access_controls).not_to receive(:set_all)
           provider.run_action(:create)
         end
@@ -164,7 +164,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
         expect(provider.current_resource.target_file).to eq("#{CHEF_SPEC_DATA}/fofile-link")
       end
       it "should update the current source of the existing link with an empty string" do
-        expect(provider.current_resource.to).to eq('')
+        expect(provider.current_resource.to).to eq("")
       end
       it "should not set the owner" do
         expect(provider.current_resource.owner).to eq(nil)
@@ -191,7 +191,7 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
         expect(provider.current_resource.target_file).to eq("#{CHEF_SPEC_DATA}/fofile-link")
       end
       it "should update the current source of the existing link with an empty string" do
-        expect(provider.current_resource.to).to eq('')
+        expect(provider.current_resource.to).to eq("")
       end
       it "should not set the owner" do
         expect(provider.current_resource.owner).to eq(nil)
@@ -233,14 +233,14 @@ describe Chef::Resource::Link, :not_supported_on_win2k3 do
       # We test create in unit tests because there is no other way to ensure
       # it does no work.  Other create and delete scenarios are covered in
       # the functional tests for links.
-      context 'when the desired state is identical' do
+      context "when the desired state is identical" do
         let(:new_resource) do
           result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link")
           result.to "#{CHEF_SPEC_DATA}/fofile"
           result.link_type :hard
           result
         end
-        it 'create does no work' do
+        it "create does no work" do
           expect(provider.file_class).not_to receive(:symlink)
           expect(provider.file_class).not_to receive(:link)
           expect(provider.access_controls).not_to receive(:set_all)
diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb
index 1ecc633..2e4f9c4 100644
--- a/spec/unit/provider/log_spec.rb
+++ b/spec/unit/provider/log_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Cary Penniman (<cary at rightscale.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Log::ChefLog do
 
diff --git a/spec/unit/provider/mdadm_spec.rb b/spec/unit/provider/mdadm_spec.rb
index 77ed579..421dd0c 100644
--- a/spec/unit/provider/mdadm_spec.rb
+++ b/spec/unit/provider/mdadm_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Mdadm do
 
@@ -25,8 +25,8 @@ describe Chef::Provider::Mdadm do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Mdadm.new('/dev/md1')
-    @new_resource.devices ["/dev/sdz1","/dev/sdz2","/dev/sdz3"]
+    @new_resource = Chef::Resource::Mdadm.new("/dev/md1")
+    @new_resource.devices ["/dev/sdz1", "/dev/sdz2", "/dev/sdz3"]
     @provider = Chef::Provider::Mdadm.new(@new_resource, @run_context)
   end
 
@@ -34,18 +34,18 @@ describe Chef::Provider::Mdadm do
     it "should set the current resources mount point to the new resources mount point" do
       allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:status => 0))
       @provider.load_current_resource
-      expect(@provider.current_resource.name).to eq('/dev/md1')
-      expect(@provider.current_resource.raid_device).to eq('/dev/md1')
+      expect(@provider.current_resource.name).to eq("/dev/md1")
+      expect(@provider.current_resource.raid_device).to eq("/dev/md1")
     end
 
     it "determines that the metadevice exists when mdadm exit code is zero" do
-      allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 0))
+      allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0, 4]).and_return(OpenStruct.new(:status => 0))
       @provider.load_current_resource
       expect(@provider.current_resource.exists).to be_truthy
     end
 
     it "determines that the metadevice does not exist when mdadm exit code is 4" do
-      allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 4))
+      allow(@provider).to receive(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0, 4]).and_return(OpenStruct.new(:status => 4))
       @provider.load_current_resource
       expect(@provider.current_resource.exists).to be_falsey
     end
@@ -53,7 +53,7 @@ describe Chef::Provider::Mdadm do
 
   describe "after the metadevice status is known" do
     before(:each) do
-      @current_resource = Chef::Resource::Mdadm.new('/dev/md1')
+      @current_resource = Chef::Resource::Mdadm.new("/dev/md1")
       @new_resource.level 5
       allow(@provider).to receive(:load_current_resource).and_return(true)
       @provider.current_resource = @current_resource
@@ -69,7 +69,7 @@ describe Chef::Provider::Mdadm do
 
       it "should specify a bitmap only if set" do
         @current_resource.exists(false)
-        @new_resource.bitmap('grow')
+        @new_resource.bitmap("grow")
         expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --bitmap=grow --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3"
         expect(@provider).to receive(:shell_out!).with(expected_command)
         @provider.run_action(:create)
@@ -102,7 +102,7 @@ describe Chef::Provider::Mdadm do
         expect(@new_resource).to be_updated_by_last_action
       end
 
-        it "should not assemble the raid device if it doesnt exist" do
+      it "should not assemble the raid device if it doesnt exist" do
         @current_resource.exists(true)
         expect(@provider).not_to receive(:shell_out!)
         @provider.run_action(:assemble)
diff --git a/spec/unit/provider/mount/aix_spec.rb b/spec/unit/provider/mount/aix_spec.rb
index ca0ddd0..9a34a6d 100644
--- a/spec/unit/provider/mount/aix_spec.rb
+++ b/spec/unit/provider/mount/aix_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh Deorukhkar (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2013 OpsCode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Mount::Aix do
 
@@ -40,7 +40,7 @@ UNMOUNTED
          /dev/sdz3         /tmp/foo         jfs2   Jul 17 13:22 rw,log=/dev/hd8
 MOUNT
 
-  @enabled_output = <<-ENABLED
+    @enabled_output = <<-ENABLED
 #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
 /tmp/foo:/dev/sdz1:jfs2::bootfs:10485760:rw:yes:no
 ENABLED
@@ -114,7 +114,7 @@ ENABLED
     expect(@provider.current_resource.mounted).to be_truthy
     expect(@provider.current_resource.mount_point).to eql(@new_resource.mount_point)
     expect(@provider.current_resource.fstype).to eql("jfs2")
-    expect(@provider.current_resource.options).to eql(['rw'])
+    expect(@provider.current_resource.options).to eql(["rw"])
   end
 
   describe "mount_fs" do
@@ -126,9 +126,10 @@ ENABLED
       @provider.run_action(:mount)
     end
 
-    it "should not mount resource if it is already mounted" do
+    it "should not mount resource if it is already mounted and the options have not changed" do
       stub_mounted_enabled(@provider, @mounted_output, "")
 
+      allow(@provider).to receive(:mount_options_unchanged?).and_return(true)
       expect(@provider).not_to receive(:mount_fs)
 
       @provider.run_action(:mount)
@@ -155,7 +156,7 @@ ENABLED
 
   describe "remount_fs" do
     it "should remount resource if it is already mounted and it supports remounting" do
-      @new_resource.supports({:remount => true})
+      @new_resource.supports({ :remount => true })
       stub_mounted_enabled(@provider, @mounted_output, "")
 
       expect(@provider).to receive(:shell_out!).with("mount -o remount #{@new_resource.device} #{@new_resource.mount_point}")
@@ -164,7 +165,7 @@ ENABLED
     end
 
     it "should remount with new mount options if it is already mounted and it supports remounting" do
-      @new_resource.supports({:remount => true})
+      @new_resource.supports({ :remount => true })
       @new_resource.options("nodev,rw")
       stub_mounted_enabled(@provider, @mounted_output, "")
 
diff --git a/spec/unit/provider/mount/mount_spec.rb b/spec/unit/provider/mount/mount_spec.rb
index 7a37ffe..50ed356 100644
--- a/spec/unit/provider/mount/mount_spec.rb
+++ b/spec/unit/provider/mount/mount_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Mount::Mount do
   before(:each) do
@@ -42,15 +42,15 @@ describe Chef::Provider::Mount::Mount do
 
   describe "when discovering the current fs state" do
     before do
-      allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => ''))
+      allow(@provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => ""))
       allow(::File).to receive(:foreach).with("/etc/fstab")
     end
 
     it "should create a current resource with the same mount point and device" do
       @provider.load_current_resource
-      expect(@provider.current_resource.name).to eq('/tmp/foo')
-      expect(@provider.current_resource.mount_point).to eq('/tmp/foo')
-      expect(@provider.current_resource.device).to eq('/dev/sdz1')
+      expect(@provider.current_resource.name).to eq("/tmp/foo")
+      expect(@provider.current_resource.mount_point).to eq("/tmp/foo")
+      expect(@provider.current_resource.device).to eq("/dev/sdz1")
     end
 
     it "should accecpt device_type :uuid", :not_supported_on_solaris do
@@ -134,7 +134,7 @@ describe Chef::Provider::Mount::Mount do
 
     it "should set mounted true if the symlink target of the device is found in the mounts list" do
       # expand the target path to correct specs on Windows
-      target = ::File.expand_path('/dev/mapper/target')
+      target = ::File.expand_path("/dev/mapper/target")
 
       allow(::File).to receive(:symlink?).with("#{@new_resource.device}").and_return(true)
       allow(::File).to receive(:readlink).with("#{@new_resource.device}").and_return(target)
@@ -239,12 +239,12 @@ describe Chef::Provider::Mount::Mount do
     end
 
     it "should ignore commented lines in fstab " do
-       fstab = "\# #{@new_resource.device}  #{@new_resource.mount_point}  ext3  defaults  1 2\n"
-       allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
+      fstab = "\# #{@new_resource.device}  #{@new_resource.mount_point}  ext3  defaults  1 2\n"
+      allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
 
-       @provider.load_current_resource
-       expect(@provider.current_resource.enabled).to be_falsey
-     end
+      @provider.load_current_resource
+      expect(@provider.current_resource.enabled).to be_falsey
+    end
 
     it "should set enabled to false if the mount point is not last in fstab" do
       line_1 = "#{@new_resource.device} #{@new_resource.mount_point}  ext3  defaults  1 2\n"
@@ -266,7 +266,7 @@ describe Chef::Provider::Mount::Mount do
       fstab = "#{@new_resource.device} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n"
       allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
       @provider.load_current_resource
-      expect(@provider.current_resource.options).to eq(options.split(','))
+      expect(@provider.current_resource.options).to eq(options.split(","))
     end
 
     it "should not mangle the mount options if the symlink target is in fstab" do
@@ -279,7 +279,7 @@ describe Chef::Provider::Mount::Mount do
       fstab = "#{target} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n"
       allow(::File).to receive(:foreach).with("/etc/fstab").and_yield fstab
       @provider.load_current_resource
-      expect(@provider.current_resource.options).to eq(options.split(','))
+      expect(@provider.current_resource.options).to eq(options.split(","))
     end
   end
 
@@ -311,7 +311,7 @@ describe Chef::Provider::Mount::Mount do
         @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a"
         @new_resource.device_type :uuid
         allow(@provider).to receive(:shell_out).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_return(status)
-        @stdout_mock = double('stdout mock')
+        @stdout_mock = double("stdout mock")
         allow(@stdout_mock).to receive(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}")
         expect(@provider).to receive(:shell_out!).with("mount -t #{@new_resource.fstype} -o defaults -U #{@new_resource.device} #{@new_resource.mount_point}").and_return(@stdout_mock)
         @provider.mount_fs()
@@ -323,6 +323,12 @@ describe Chef::Provider::Mount::Mount do
         @provider.mount_fs()
       end
 
+      it "should not mount the filesystem if it is mounted and the options have not changed" do
+        allow(@current_resource).to receive(:mounted).and_return(true)
+        expect(@provider).to_not receive(:shell_out!)
+        @provider.mount_fs()
+      end
+
     end
 
     describe "umount_fs" do
@@ -341,14 +347,14 @@ describe Chef::Provider::Mount::Mount do
 
     describe "remount_fs" do
       it "should use mount -o remount if remount is supported" do
-        @new_resource.supports({:remount => true})
+        @new_resource.supports({ :remount => true })
         @current_resource.mounted(true)
         expect(@provider).to receive(:shell_out!).with("mount -o remount,defaults #{@new_resource.mount_point}")
         @provider.remount_fs
       end
 
       it "should use mount -o remount with new mount options if remount is supported" do
-        @new_resource.supports({:remount => true})
+        @new_resource.supports({ :remount => true })
         options = "rw,noexec,noauto"
         @new_resource.options(%w{rw noexec noauto})
         @current_resource.mounted(true)
@@ -357,7 +363,7 @@ describe Chef::Provider::Mount::Mount do
       end
 
       it "should umount and mount if remount is not supported" do
-        @new_resource.supports({:remount => false})
+        @new_resource.supports({ :remount => false })
         @current_resource.mounted(true)
         expect(@provider).to receive(:umount_fs)
         expect(@provider).to receive(:sleep).with(1)
diff --git a/spec/unit/provider/mount/solaris_spec.rb b/spec/unit/provider/mount/solaris_spec.rb
index 9a9b09b..a6d0620 100644
--- a/spec/unit/provider/mount/solaris_spec.rb
+++ b/spec/unit/provider/mount/solaris_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2008-2014 Chef Software, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 # Do not run these tests on windows because some path handling
 # code is not implemented to handle windows paths.
@@ -57,7 +57,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
   }
 
   let(:vfstab_file_contents) {
-    <<-EOF.gsub /^\s*/, ''
+    <<-EOF.gsub /^\s*/, ""
     #device         device          mount           FS      fsck    mount   mount
     #to mount       to fsck         point           type    pass    at boot options
     #
@@ -84,7 +84,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
   }
 
   let(:mount_output) {
-    <<-EOF.gsub /^\s*/, ''
+    <<-EOF.gsub /^\s*/, ""
     /dev/dsk/c0t0d0s0 on / type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
     /dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
     EOF
@@ -103,7 +103,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
   describe "#define_resource_requirements" do
     before do
       # we're not testing the actual actions so stub them all out
-      [:mount_fs, :umount_fs, :remount_fs, :enable_fs, :disable_fs].each {|m| allow(provider).to receive(m) }
+      [:mount_fs, :umount_fs, :remount_fs, :enable_fs, :disable_fs].each { |m| allow(provider).to receive(m) }
     end
 
     it "run_action(:mount) should raise an error if the device does not exist" do
@@ -215,7 +215,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
     context "when loading a normal UFS filesystem with noauto, don't mount at boot" do
 
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #device         device          mount           FS      fsck    mount   mount
         #to mount       to fsck         point           type    pass    at boot options
         #
@@ -245,12 +245,12 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the device is an smbfs mount" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         //solarsystem/tmp on /mnt type smbfs read/write/setuid/devices/dev=5080000 on Tue Mar 29 11:40:18 2011
         EOF
       }
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         //WORKGROUP;username:password at host/share    -   /mountpoint smbfs   -   no  fileperms=0777,dirperms=0777
         EOF
       }
@@ -264,13 +264,13 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the device is an NFS mount" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         cartman:/share2 on /cartman type nfs rsize=32768,wsize=32768,NFSv4,dev=4000004 on Tue Mar 29 11:40:18 2011
         EOF
       }
 
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         cartman:/share2         -                       /cartman        nfs     -       yes     rw,soft
         EOF
       }
@@ -335,13 +335,13 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
       let(:target) { "/dev/mapper/target" }
 
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #{target} on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         EOF
       }
 
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #{target}       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         EOF
       }
@@ -372,13 +372,13 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
       let(:absolute_target) { File.expand_path(target, File.dirname(device)) }
 
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #{absolute_target} on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         EOF
       }
 
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #{absolute_target}       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         EOF
       }
@@ -405,7 +405,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the matching mount point is last in the mounts list" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t0d0s0 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
         /dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         EOF
@@ -418,7 +418,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the matching mount point is not last in the mounts list" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s7 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         /dev/dsk/c0t0d0s0 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200000 on Tue Jul 31 22:34:46 2012
         EOF
@@ -431,7 +431,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the matching mount point is not in the mounts list (mountpoint wrong)" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s7 on /mnt/foob type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         EOF
       }
@@ -443,7 +443,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the matching mount point is not in the mounts list (raw device wrong)" do
       let(:mount_output) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s72 on /mnt/foo type ufs read/write/setuid/intr/largefiles/xattr/onerror=panic/dev=2200007 on Tue Jul 31 22:34:46 2012
         EOF
       }
@@ -455,7 +455,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mount point is last in fstab" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s72       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         /dev/dsk/c0t2d0s7       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         EOF
@@ -469,7 +469,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mount point is not last in fstab and is a substring of another mount" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s7       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         /dev/dsk/c0t2d0s72       /dev/rdsk/c0t2d0s7      /mnt/foo/bar            ufs     2       yes     -
         EOF
@@ -483,7 +483,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mount point is not last in fstab" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s7       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         /dev/dsk/c0t2d0s72       /dev/rdsk/c0t2d0s72      /mnt/foo            ufs     2       yes     -
         EOF
@@ -497,7 +497,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mount point is not in fstab, but the mountpoint is a substring of one that is" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s7       /dev/rdsk/c0t2d0s7      /mnt/foob            ufs     2       yes     -
         EOF
       }
@@ -510,7 +510,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mount point is not in fstab, but the device is a substring of one that is" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         /dev/dsk/c0t2d0s72       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         EOF
       }
@@ -523,7 +523,7 @@ describe Chef::Provider::Mount::Solaris, :unix_only do
 
     context "when the mountpoint line is commented out" do
       let(:vfstab_file_contents) {
-        <<-EOF.gsub /^\s*/, ''
+        <<-EOF.gsub /^\s*/, ""
         #/dev/dsk/c0t2d0s7       /dev/rdsk/c0t2d0s7      /mnt/foo            ufs     2       yes     -
         EOF
       }
diff --git a/spec/unit/provider/mount/windows_spec.rb b/spec/unit/provider/mount/windows_spec.rb
index 467d923..ab7a161 100644
--- a/spec/unit/provider/mount/windows_spec.rb
+++ b/spec/unit/provider/mount/windows_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class Chef
   class Util
@@ -100,9 +100,9 @@ describe Chef::Provider::Mount::Windows do
 
       it "should mount the filesystem if it is not mounted" do
         expect(@vol).to receive(:add).with(:remote => @new_resource.device,
-                                       :username => @new_resource.username,
-                                       :domainname => @new_resource.domain,
-                                       :password => @new_resource.password)
+                                           :username => @new_resource.username,
+                                           :domainname => @new_resource.domain,
+                                           :password => @new_resource.password)
         @provider.mount_fs
       end
 
@@ -111,6 +111,20 @@ describe Chef::Provider::Mount::Windows do
         allow(@current_resource).to receive(:mounted).and_return(true)
         @provider.mount_fs
       end
+
+      it "should remount the filesystem if it is mounted and the options have changed" do
+        expect(@vol).to receive(:add).with(:remote => @new_resource.device,
+                                           :username => @new_resource.username,
+                                           :domainname => @new_resource.domain,
+                                           :password => @new_resource.password)
+        @provider.mount_fs
+      end
+
+      it "should not mount the filesystem if it is mounted and the options have not changed" do
+        expect(@vol).to_not receive(:add)
+        allow(@current_resource).to receive(:mounted).and_return(true)
+        @provider.mount_fs
+      end
     end
 
     describe "when unmounting a file system" do
diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb
index e9fe3fa..fa168e5 100644
--- a/spec/unit/provider/mount_spec.rb
+++ b/spec/unit/provider/mount_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2008-2014 Chef Software, Inc.
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Mount do
 
@@ -28,7 +28,7 @@ describe Chef::Provider::Mount do
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
 
   let(:new_resource) do
-    new_resource = Chef::Resource::Mount.new('/tmp/foo')
+    new_resource = Chef::Resource::Mount.new("/tmp/foo")
     new_resource.device      "/dev/sdz1"
     new_resource.name        "/tmp/foo"
     new_resource.mount_point "/tmp/foo"
@@ -38,7 +38,7 @@ describe Chef::Provider::Mount do
 
   let(:current_resource) do
     # this abstract superclass has no load_current_resource to call
-    current_resource = Chef::Resource::Mount.new('/tmp/foo')
+    current_resource = Chef::Resource::Mount.new("/tmp/foo")
     current_resource.device      "/dev/sdz1"
     current_resource.name        "/tmp/foo"
     current_resource.mount_point "/tmp/foo"
@@ -61,8 +61,19 @@ describe Chef::Provider::Mount do
       expect(new_resource).to be_updated_by_last_action
     end
 
-    it "should not mount the filesystem if it is mounted" do
+    it "should remount the filesystem if it is mounted and the options have changed" do
       allow(current_resource).to receive(:mounted).and_return(true)
+      allow(provider).to receive(:mount_options_unchanged?).and_return(false)
+      expect(provider).to receive(:umount_fs).and_return(true)
+      expect(provider).to receive(:wait_until_unmounted)
+      expect(provider).to receive(:mount_fs).and_return(true)
+      provider.run_action(:mount)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should not mount the filesystem if it is mounted and the options have not changed" do
+      allow(current_resource).to receive(:mounted).and_return(true)
+      expect(provider).to receive(:mount_options_unchanged?).and_return(true)
       expect(provider).not_to receive(:mount_fs)
       provider.run_action(:mount)
       expect(new_resource).not_to be_updated_by_last_action
@@ -124,7 +135,7 @@ describe Chef::Provider::Mount do
       provider.unmount_retries = 1
       expect(provider).to receive(:umount_fs)
       expect(provider).to receive(:mounted?).and_return(true, true)
-      expect{ provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount)
+      expect { provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount)
     end
   end
 
@@ -170,7 +181,6 @@ describe Chef::Provider::Mount do
     end
   end
 
-
   it "should delegates the mount implementation to subclasses" do
     expect { provider.mount_fs }.to raise_error(Chef::Exceptions::UnsupportedAction)
   end
diff --git a/spec/unit/provider/ohai_spec.rb b/spec/unit/provider/ohai_spec.rb
index 45688ce..100eee5 100644
--- a/spec/unit/provider/ohai_spec.rb
+++ b/spec/unit/provider/ohai_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Michael Leinartas (<mleinartas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/run_context'
+require "chef/run_context"
 
 describe Chef::Provider::Ohai do
   before(:each) do
@@ -38,15 +38,15 @@ describe Chef::Provider::Ohai do
       },
       :data2 => {
         :origdata => "somevalue",
-        :newdata => "somevalue"
-      }
+        :newdata => "somevalue",
+      },
     }
     allow(mock_ohai).to receive(:all_plugins).and_return(true)
     allow(mock_ohai).to receive(:data).and_return(mock_ohai[:data],
                                       mock_ohai[:data2])
     allow(Ohai::System).to receive(:new).and_return(mock_ohai)
     allow(Chef::Platform).to receive(:find_platform_and_version).and_return({ "platform" => @platform,
-                                                                  "platform_version" => @platform_version})
+                                                                              "platform_version" => @platform_version })
     # Fake node with a dummy save
     @node = Chef::Node.new
     @node.name(@fqdn)
@@ -56,29 +56,29 @@ describe Chef::Provider::Ohai do
     @new_resource = Chef::Resource::Ohai.new("ohai_reload")
     ohai = Ohai::System.new
     ohai.all_plugins
-    @node.consume_external_attrs(ohai.data,{})
+    @node.consume_external_attrs(ohai.data, {})
 
     @provider = Chef::Provider::Ohai.new(@new_resource, @run_context)
   end
 
   describe "when reloading ohai" do
     before do
-      @node.automatic_attrs[:origdata] = 'somevalue'
+      @node.automatic_attrs[:origdata] = "somevalue"
     end
 
     it "applies updated ohai data to the node" do
-      expect(@node[:origdata]).to eq('somevalue')
+      expect(@node[:origdata]).to eq("somevalue")
       expect(@node[:newdata]).to be_nil
       @provider.run_action(:reload)
-      expect(@node[:origdata]).to eq('somevalue')
-      expect(@node[:newdata]).to eq('somevalue')
+      expect(@node[:origdata]).to eq("somevalue")
+      expect(@node[:newdata]).to eq("somevalue")
     end
 
     it "should reload a specific plugin and cause node to pick up new values" do
       @new_resource.plugin "someplugin"
       @provider.run_action(:reload)
-      expect(@node[:origdata]).to eq('somevalue')
-      expect(@node[:newdata]).to eq('somevalue')
+      expect(@node[:origdata]).to eq("somevalue")
+      expect(@node[:newdata]).to eq("somevalue")
     end
   end
 end
diff --git a/spec/unit/provider/osx_profile_spec.rb b/spec/unit/provider/osx_profile_spec.rb
new file mode 100644
index 0000000..260204f
--- /dev/null
+++ b/spec/unit/provider/osx_profile_spec.rb
@@ -0,0 +1,249 @@
+#
+# Author:: Nate Walck (<nate.walck at gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::OsxProfile do
+  let(:shell_out_success) do
+    double("shell_out", :exitstatus => 0, :error? => false)
+  end
+  describe "action_create" do
+    let(:node) { Chef::Node.new }
+    let(:events) { Chef::EventDispatch::Dispatcher.new }
+    let(:run_context) { Chef::RunContext.new(node, {}, events) }
+    let(:new_resource) { Chef::Resource::OsxProfile.new("Profile Test", run_context) }
+    let(:provider) { Chef::Provider::OsxProfile.new(new_resource, run_context) }
+    let(:all_profiles) do
+      { "_computerlevel" =>         [{ "ProfileDisplayName" => "Finder Settings",
+                                       "ProfileIdentifier" => "com.apple.finder",
+                                       "ProfileInstallDate" => "2015-11-08 23:15:21 +0000",
+                                       "ProfileItems" =>            [{ "PayloadContent" =>               { "PayloadContentManagedPreferences" =>                 { "com.apple.finder" =>                   { "Forced" => [{ "mcx_preference_settings" => { "ShowExternalHardDrivesOnDesktop" => false } }] } } },
+                                                                       "PayloadDisplayName" => "Custom: (com.apple.finder)",
+                                                                       "PayloadIdentifier" => "com.apple.finder",
+                                                                       "PayloadType" => "com.apple.ManagedClient.preferences",
+                                                                       "PayloadUUID" => "a017048f-684b-4e81-baa3-43afe316d739",
+                                                                       "PayloadVersion" => 1 }],
+                                       "ProfileOrganization" => "Chef",
+                                       "ProfileRemovalDisallowed" => "false",
+                                       "ProfileType" => "Configuration",
+                                       "ProfileUUID" => "e2e09bef-e673-44a6-bcbe-ecb5f1c1b740",
+                                       "ProfileVerificationState" => "unsigned",
+                                       "ProfileVersion" => 1 },
+        { "ProfileDisplayName" => "ScreenSaver Settings",
+          "ProfileIdentifier" => "com.testprofile.screensaver",
+          "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+          "ProfileItems" =>            [{ "PayloadContent" =>               { "PayloadContentManagedPreferences" =>                 { "com.apple.screensaver" =>                   { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+                                          "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+                                          "PayloadIdentifier" => "com.apple.screensaver",
+                                          "PayloadType" => "com.apple.ManagedClient.preferences",
+                                          "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c110",
+                                          "PayloadVersion" => 1 }],
+          "ProfileOrganization" => "Chef",
+          "ProfileRemovalDisallowed" => "false",
+          "ProfileType" => "Configuration",
+          "ProfileUUID" => "6e95927c-f200-54b4-85c7-52ab99b61c47",
+          "ProfileVerificationState" => "unsigned",
+          "ProfileVersion" => 1 }]
+      }
+    end
+      # If anything is changed within this profile, be sure to update the
+      # ProfileUUID in all_profiles to match the new config specific UUID
+    let(:test_profile) do
+      {
+        "PayloadIdentifier" => "com.testprofile.screensaver",
+        "PayloadRemovalDisallowed" => false,
+        "PayloadScope" => "System",
+        "PayloadType" => "Configuration",
+        "PayloadUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+        "PayloadOrganization" => "Chef",
+        "PayloadVersion" => 1,
+        "PayloadDisplayName" => "Screensaver Settings",
+        "PayloadContent" => [
+          {
+            "PayloadType" => "com.apple.ManagedClient.preferences",
+            "PayloadVersion" => 1,
+            "PayloadIdentifier" => "com.testprofile.screensaver",
+            "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c108",
+            "PayloadEnabled" => true,
+            "PayloadDisplayName" => "com.apple.screensaver",
+            "PayloadContent" => {
+              "com.apple.screensaver" => {
+                "Forced" => [
+                  {
+                    "mcx_preference_settings" => {
+                      "idleTime" => 0
+                    }
+                  },
+                ]
+              }
+            },
+          },
+        ],
+        }
+    end
+    let(:no_profiles) do
+      {}
+    end
+
+    before(:each) do
+      allow(provider).to receive(:cookbook_file_available?).and_return(true)
+      allow(provider).to receive(:cache_cookbook_profile).and_return("/tmp/test.mobileconfig.remote")
+      allow(provider).to receive(:get_new_profile_hash).and_return(test_profile)
+      allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+      allow(provider).to receive(:read_plist).and_return(all_profiles)
+      allow(::File).to receive(:unlink).and_return(true)
+    end
+
+    it "should build the get all profiles shellout command correctly" do
+      profile_name = "com.testprofile.screensaver.mobileconfig"
+      tempfile = "/tmp/allprofiles.plist"
+      new_resource.profile_name profile_name
+      allow(provider).to receive(:generate_tempfile).and_return(tempfile)
+      allow(provider).to receive(:get_installed_profiles).and_call_original
+      allow(provider).to receive(:read_plist).and_return(all_profiles)
+      expect(provider).to receive(:shell_out!).with("profiles -P -o '/tmp/allprofiles.plist'")
+      provider.load_current_resource
+    end
+
+    it "should use profile name as profile when no profile is set" do
+      profile_name = "com.testprofile.screensaver.mobileconfig"
+      new_resource.profile_name profile_name
+      provider.load_current_resource
+      expect(new_resource.profile_name).to eql(profile_name)
+    end
+
+    it "should use identifier from specified profile" do
+      new_resource.profile test_profile
+      provider.load_current_resource
+      expect(
+        provider.instance_variable_get(:@new_profile_identifier)
+        ).to eql(test_profile["PayloadIdentifier"])
+    end
+
+    it "should install when not installed" do
+      new_resource.profile test_profile
+      allow(provider).to receive(:get_installed_profiles).and_return(no_profiles)
+      provider.load_current_resource
+      expect { provider.run_action(:install) }.to_not raise_error
+    end
+
+    it "does not install if the profile is already installed" do
+      new_resource.profile test_profile
+      allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+      provider.load_current_resource
+      expect(provider).to_not receive(:install_profile)
+      expect { provider.action_install }.to_not raise_error
+    end
+
+    it "should install when installed but uuid differs" do
+      new_resource.profile test_profile
+      all_profiles["_computerlevel"][1]["ProfileUUID"] = "1781fbec-3325-565f-9022-9bb39245d4dd"
+      provider.load_current_resource
+      expect { provider.run_action(:install) }.to_not raise_error
+    end
+
+    it "should build the shellout install command correctly" do
+      profile_path = "/tmp/test.mobileconfig"
+      new_resource.profile test_profile
+      # Change the profile so it triggers an install
+      all_profiles["_computerlevel"][1]["ProfileUUID"] = "1781fbec-3325-565f-9022-9bb39245d4dd"
+      provider.load_current_resource
+      allow(provider).to receive(:write_profile_to_disk).and_return(profile_path)
+      expect(provider).to receive(:shell_out).with("profiles -I -F '#{profile_path}'").and_return(shell_out_success)
+      provider.action_install()
+    end
+
+    it "should fail if there is no identifier inside the profile" do
+      test_profile.delete("PayloadIdentifier")
+      new_resource.profile test_profile
+      error_message = "The specified profile does not seem to be valid"
+      expect { provider.run_action(:install) }.to raise_error(RuntimeError, error_message)
+    end
+
+  end
+
+  describe "action_remove" do
+    let(:node) { Chef::Node.new }
+    let(:events) { Chef::EventDispatch::Dispatcher.new }
+    let(:run_context) { Chef::RunContext.new(node, {}, events) }
+    let(:new_resource) { Chef::Resource::OsxProfile.new("Profile Test", run_context) }
+    let(:provider) { Chef::Provider::OsxProfile.new(new_resource, run_context) }
+    let(:current_resource) { Chef::Resource::OsxProfile.new("Profile Test") }
+    let(:all_profiles) do
+      { "_computerlevel" =>         [{ "ProfileDisplayName" => "ScreenSaver Settings",
+                                       "ProfileIdentifier" => "com.apple.screensaver",
+                                       "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+                                       "ProfileItems" =>            [{ "PayloadContent" =>               { "PayloadContentManagedPreferences" =>                 { "com.apple.screensaver" =>                   { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+                                                                       "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+                                                                       "PayloadIdentifier" => "com.apple.screensaver",
+                                                                       "PayloadType" => "com.apple.ManagedClient.preferences",
+                                                                       "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c108",
+                                                                       "PayloadVersion" => 1 }],
+                                       "ProfileOrganization" => "Chef",
+                                       "ProfileRemovalDisallowed" => "false",
+                                       "ProfileType" => "Configuration",
+                                       "ProfileUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+                                       "ProfileVerificationState" => "unsigned",
+                                       "ProfileVersion" => 1 },
+        { "ProfileDisplayName" => "ScreenSaver Settings",
+          "ProfileIdentifier" => "com.testprofile.screensaver",
+          "ProfileInstallDate" => "2015-10-05 23:15:21 +0000",
+          "ProfileItems" =>            [{ "PayloadContent" =>               { "PayloadContentManagedPreferences" =>                 { "com.apple.screensaver" =>                   { "Forced" => [{ "mcx_preference_settings" => { "idleTime" => 0 } }] } } },
+                                          "PayloadDisplayName" => "Custom: (com.apple.screensaver)",
+                                          "PayloadIdentifier" => "com.apple.screensaver",
+                                          "PayloadType" => "com.apple.ManagedClient.preferences",
+                                          "PayloadUUID" => "73fc30e0-1e57-0131-c32d-000c2944c110",
+                                          "PayloadVersion" => 1 }],
+          "ProfileOrganization" => "Chef",
+          "ProfileRemovalDisallowed" => "false",
+          "ProfileType" => "Configuration",
+          "ProfileUUID" => "1781fbec-3325-565f-9022-8aa28135c3cc",
+          "ProfileVerificationState" => "unsigned",
+          "ProfileVersion" => 1 }]
+      }
+    end
+    before(:each) do
+      provider.current_resource = current_resource
+      allow(provider).to receive(:get_installed_profiles).and_return(all_profiles)
+    end
+
+    it "should use resource name for identifier when not specified" do
+      new_resource.profile_name "com.testprofile.screensaver"
+      new_resource.action(:remove)
+      provider.load_current_resource
+      expect(provider.instance_variable_get(:@new_profile_identifier)
+        ).to eql(new_resource.profile_name)
+    end
+
+    it "should use specified identifier" do
+      new_resource.identifier "com.testprofile.screensaver"
+      new_resource.action(:remove)
+      provider.load_current_resource
+      expect(provider.instance_variable_get(:@new_profile_identifier)
+        ).to eql(new_resource.identifier)
+    end
+
+    it "should build the shellout remove command correctly" do
+      new_resource.identifier "com.testprofile.screensaver"
+      new_resource.action(:remove)
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out).with("profiles -R -p '#{new_resource.identifier}'").and_return(shell_out_success)
+      provider.action_remove()
+    end
+  end
+end
diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb
index 5bc861b..6940874 100644
--- a/spec/unit/provider/package/aix_spec.rb
+++ b/spec/unit/provider/package/aix_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Deepali Jagtap (deepali.jagtap at clogeny.com)
 # Author:: Prabhu Das (prabhu.das at clogeny.com)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Aix do
   before(:each) do
@@ -33,26 +33,30 @@ describe Chef::Provider::Package::Aix do
 
   describe "assessing the current package status" do
     before do
-     @bffinfo ="/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:
- /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
+      @bffinfo = "/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:
+  /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:"
 
-      @status = double("Status", :stdout => "", :exitstatus => 0)
+      @empty_status = double("Status", :stdout => "", :exitstatus => 0)
     end
 
     it "should create a current resource with the name of new_resource" do
-      allow(@provider).to receive(:shell_out).and_return(@status)
+      status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
       @provider.load_current_resource
       expect(@provider.current_resource.name).to eq("samba.base")
     end
 
     it "should set the current resource bff package name to the new resource bff package name" do
-      allow(@provider).to receive(:shell_out).and_return(@status)
+      status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
       @provider.load_current_resource
       expect(@provider.current_resource.package_name).to eq("samba.base")
     end
 
     it "should raise an exception if a source is supplied but not found" do
-      allow(@provider).to receive(:shell_out).and_return(@status)
+      allow(@provider).to receive(:shell_out).and_return(@empty_status)
       allow(::File).to receive(:exists?).and_return(false)
       @provider.load_current_resource
       @provider.define_resource_requirements
@@ -61,8 +65,8 @@ describe Chef::Provider::Package::Aix do
 
     it "should get the source package version from lslpp if provided" do
       status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
-      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(status)
-      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(@status)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
       @provider.load_current_resource
 
       expect(@provider.current_resource.package_name).to eq("samba.base")
@@ -73,8 +77,8 @@ describe Chef::Provider::Package::Aix do
       status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
       @stdout = StringIO.new(@bffinfo)
       @stdin, @stderr = StringIO.new, StringIO.new
-      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(@status)
-      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(status)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(status)
       @provider.load_current_resource
       expect(@provider.current_resource.version).to eq("3.3.12.0")
     end
@@ -94,12 +98,20 @@ describe Chef::Provider::Package::Aix do
     end
 
     it "should return a current resource with a nil version if the package is not found" do
-      status = double(:stdout => "", :exitstatus => 0)
-      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base").and_return(status)
-      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base").and_return(status)
+      status = double("Status", :stdout => @bffinfo, :exitstatus => 0)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect(@provider).to receive(:shell_out).with("lslpp -lcq samba.base", timeout: 900).and_return(@empty_status)
       @provider.load_current_resource
       expect(@provider.current_resource.version).to be_nil
     end
+
+    it "should raise an exception if the source doesn't provide the requested package" do
+      wrongbffinfo = "/usr/lib/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:
+/etc/objrepos:openssl.base:0.9.8.2400::COMMITTED:I:Open Secure Socket Layer:"
+      status = double("Status", :stdout => wrongbffinfo, :exitstatus => 0)
+      expect(@provider).to receive(:shell_out).with("installp -L -d /tmp/samba.base", timeout: 900).and_return(status)
+      expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+    end
   end
 
   describe "candidate_version" do
@@ -125,7 +137,7 @@ describe Chef::Provider::Package::Aix do
 
   describe "install and upgrade" do
     it "should run installp -aYF -d with the package source to install" do
-      expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base")
+      expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base", timeout: 900)
       @provider.install_package("samba.base", "3.3.12.0")
     end
 
@@ -133,26 +145,26 @@ describe Chef::Provider::Package::Aix do
       @new_resource = Chef::Resource::Package.new("/tmp/samba.base")
       @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context)
       expect(@new_resource.source).to eq("/tmp/samba.base")
-      expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base")
+      expect(@provider).to receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base", timeout: 900)
       @provider.install_package("/tmp/samba.base", "3.3.12.0")
     end
 
     it "should run installp with -eLogfile option." do
       allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
-      expect(@provider).to receive(:shell_out!).with("installp -aYF  -e/tmp/installp.log -d /tmp/samba.base samba.base")
+      expect(@provider).to receive(:shell_out!).with("installp -aYF  -e/tmp/installp.log -d /tmp/samba.base samba.base", timeout: 900)
       @provider.install_package("samba.base", "3.3.12.0")
     end
   end
 
   describe "remove" do
     it "should run installp -u samba.base to remove the package" do
-      expect(@provider).to receive(:shell_out!).with("installp -u samba.base")
+      expect(@provider).to receive(:shell_out!).with("installp -u samba.base", timeout: 900)
       @provider.remove_package("samba.base", "3.3.12.0")
     end
 
     it "should run installp -u -e/tmp/installp.log  with options -e/tmp/installp.log" do
       allow(@new_resource).to receive(:options).and_return("-e/tmp/installp.log")
-      expect(@provider).to receive(:shell_out!).with("installp -u  -e/tmp/installp.log samba.base")
+      expect(@provider).to receive(:shell_out!).with("installp -u  -e/tmp/installp.log samba.base", timeout: 900)
       @provider.remove_package("samba.base", "3.3.12.0")
     end
 
diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb
index 8528480..f87c1e8 100644
--- a/spec/unit/provider/package/apt_spec.rb
+++ b/spec/unit/provider/package/apt_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Apt do
   # XXX: sorry this is ugly and was done quickly to get 12.0.2 out, this file needs a rewrite to use
@@ -34,7 +34,7 @@ describe Chef::Provider::Package::Apt do
         @status = double("Status", :exitstatus => 0)
         @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context)
         @stdin = StringIO.new
-        @stdout =<<-PKG_STATUS
+        @stdout = <<-PKG_STATUS
 irssi:
   Installed: (none)
   Candidate: 0.8.14-1ubuntu4
@@ -43,7 +43,7 @@ irssi:
         500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages
         PKG_STATUS
         @stderr = ""
-        @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0)
+        @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
         @timeout = 900
       end
 
@@ -52,7 +52,7 @@ irssi:
         it "should create a current resource with the name of the new_resource" do
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache policy #{@new_resource.package_name}",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(@shell_out)
           @provider.load_current_resource
 
@@ -86,18 +86,18 @@ sudo:
         # list of virtual packages: http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt
         it "should not install the virtual package there is a single provider package and it is installed" do
           @new_resource.package_name("libmysqlclient15-dev")
-          virtual_package_out=<<-VPKG_STDOUT
+          virtual_package_out = <<-VPKG_STDOUT
 libmysqlclient15-dev:
   Installed: (none)
   Candidate: (none)
   Version table:
           VPKG_STDOUT
-          virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0)
+          virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache policy libmysqlclient15-dev",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(virtual_package)
-          showpkg_out =<<-SHOWPKG_STDOUT
+          showpkg_out = <<-SHOWPKG_STDOUT
 Package: libmysqlclient15-dev
 Versions:
 
@@ -115,12 +115,12 @@ libmysqlclient-dev 5.1.41-3ubuntu12.7
 libmysqlclient-dev 5.1.41-3ubuntu12.10
 libmysqlclient-dev 5.1.41-3ubuntu12
           SHOWPKG_STDOUT
-          showpkg = double(:stdout => showpkg_out,:exitstatus => 0)
+          showpkg = double(:stdout => showpkg_out, :exitstatus => 0)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache showpkg libmysqlclient15-dev",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(showpkg)
-          real_package_out=<<-RPKG_STDOUT
+          real_package_out = <<-RPKG_STDOUT
 libmysqlclient-dev:
   Installed: 5.1.41-3ubuntu12.10
   Candidate: 5.1.41-3ubuntu12.10
@@ -133,28 +133,28 @@ libmysqlclient-dev:
      5.1.41-3ubuntu12 0
         500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages
           RPKG_STDOUT
-          real_package = double(:stdout => real_package_out,:exitstatus => 0)
+          real_package = double(:stdout => real_package_out, :exitstatus => 0)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache policy libmysqlclient-dev",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(real_package)
           @provider.load_current_resource
         end
 
         it "should raise an exception if you specify a virtual package with multiple provider packages" do
           @new_resource.package_name("mp3-decoder")
-          virtual_package_out=<<-VPKG_STDOUT
+          virtual_package_out = <<-VPKG_STDOUT
 mp3-decoder:
   Installed: (none)
   Candidate: (none)
   Version table:
           VPKG_STDOUT
-          virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0)
+          virtual_package = double(:stdout => virtual_package_out, :exitstatus => 0)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache policy mp3-decoder",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(virtual_package)
-          showpkg_out=<<-SHOWPKG_STDOUT
+          showpkg_out = <<-SHOWPKG_STDOUT
 Package: mp3-decoder
 Versions:
 
@@ -175,10 +175,10 @@ opencubicplayer 1:0.1.17-2
 mpg321 0.2.10.6
 mpg123 1.12.1-0ubuntu1
           SHOWPKG_STDOUT
-          showpkg = double(:stdout => showpkg_out,:exitstatus => 0)
+          showpkg = double(:stdout => showpkg_out, :exitstatus => 0)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache showpkg mp3-decoder",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(showpkg)
           expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
         end
@@ -191,7 +191,7 @@ mpg123 1.12.1-0ubuntu1
           allow(@new_resource).to receive(:provider).and_return(nil)
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache -o APT::Default-Release=lenny-backports policy irssi",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(@shell_out)
           @provider.load_current_resource
         end
@@ -200,11 +200,11 @@ mpg123 1.12.1-0ubuntu1
           @new_resource.source "pluto"
           expect(@provider).to receive(:shell_out!).with(
             "apt-cache policy #{@new_resource.package_name}",
-            :timeout => @timeout
+            :timeout => @timeout,
           ).and_return(@shell_out)
           @provider.load_current_resource
           @provider.define_resource_requirements
-          expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", {:timeout=>900}).and_return(@shell_out)
+          expect(@provider).to receive(:shell_out!).with("apt-cache policy irssi", { :timeout => 900 }).and_return(@shell_out)
           expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
         end
       end
@@ -219,8 +219,8 @@ mpg123 1.12.1-0ubuntu1
           it "should run apt-get install with the package name and version" do
             expect(@provider).to receive(:shell_out!). with(
               "apt-get -q -y install irssi=0.8.12-7",
-              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @provider.install_package("irssi", "0.8.12-7")
           end
@@ -228,8 +228,8 @@ mpg123 1.12.1-0ubuntu1
           it "should run apt-get install with the package name and version and options if specified" do
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y --force-yes install irssi=0.8.12-7",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @new_resource.options("--force-yes")
             @provider.install_package("irssi", "0.8.12-7")
@@ -244,8 +244,8 @@ mpg123 1.12.1-0ubuntu1
 
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y -o APT::Default-Release=lenny-backports install irssi=0.8.12-7",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
 
             @provider.install_package("irssi", "0.8.12-7")
@@ -265,8 +265,8 @@ mpg123 1.12.1-0ubuntu1
           it "should run apt-get remove with the package name" do
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y remove irssi",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @provider.remove_package("irssi", "0.8.12-7")
           end
@@ -275,7 +275,7 @@ mpg123 1.12.1-0ubuntu1
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y --force-yes remove irssi",
               :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :timeout => @timeout,
             )
             @new_resource.options("--force-yes")
 
@@ -289,7 +289,7 @@ mpg123 1.12.1-0ubuntu1
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y purge irssi",
               :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :timeout => @timeout,
             )
             @provider.purge_package("irssi", "0.8.12-7")
           end
@@ -298,7 +298,7 @@ mpg123 1.12.1-0ubuntu1
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y --force-yes purge irssi",
               :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :timeout => @timeout,
             )
             @new_resource.options("--force-yes")
 
@@ -316,8 +316,8 @@ mpg123 1.12.1-0ubuntu1
 
             expect(@provider).to receive(:shell_out!).with(
               "debconf-set-selections /tmp/irssi-0.8.12-7.seed",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
 
             @provider.preseed_package(file)
@@ -326,8 +326,8 @@ mpg123 1.12.1-0ubuntu1
           it "should run debconf-set-selections on the preseed file if it has changed" do
             expect(@provider).to receive(:shell_out!).with(
               "debconf-set-selections /tmp/irssi-0.8.12-7.seed",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil},
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             file = @provider.get_preseed_file("irssi", "0.8.12-7")
             @provider.preseed_package(file)
@@ -347,8 +347,8 @@ mpg123 1.12.1-0ubuntu1
           it "should run dpkg-reconfigure package" do
             expect(@provider).to receive(:shell_out!).with(
               "dpkg-reconfigure irssi",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @provider.reconfig_package("irssi", "0.8.12-7")
           end
@@ -356,11 +356,11 @@ mpg123 1.12.1-0ubuntu1
 
         describe "when installing a virtual package" do
           it "should install the package without specifying a version" do
-            @provider.is_virtual_package['libmysqlclient-dev'] = true
+            @provider.is_virtual_package["libmysqlclient-dev"] = true
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y install libmysqlclient-dev",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @provider.install_package("libmysqlclient-dev", "not_a_real_version")
           end
@@ -369,12 +369,12 @@ mpg123 1.12.1-0ubuntu1
         describe "when installing multiple packages" do
           it "can install a virtual package followed by a non-virtual package" do
             # https://github.com/chef/chef/issues/2914
-            @provider.is_virtual_package['libmysqlclient-dev'] = true
-            @provider.is_virtual_package['irssi'] = false
+            @provider.is_virtual_package["libmysqlclient-dev"] = true
+            @provider.is_virtual_package["irssi"] = false
             expect(@provider).to receive(:shell_out!).with(
               "apt-get -q -y install libmysqlclient-dev irssi=0.8.12-7",
-              :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
-              :timeout => @timeout
+              :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil },
+              :timeout => @timeout,
             )
             @provider.install_package(["libmysqlclient-dev", "irssi"], ["not_a_real_version", "0.8.12-7"])
           end
diff --git a/spec/unit/provider/package/chocolatey_spec.rb b/spec/unit/provider/package/chocolatey_spec.rb
new file mode 100644
index 0000000..aeb420f
--- /dev/null
+++ b/spec/unit/provider/package/chocolatey_spec.rb
@@ -0,0 +1,504 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::Package::Chocolatey do
+  let(:timeout) { 900 }
+
+  let(:new_resource) { Chef::Resource::ChocolateyPackage.new("git") }
+
+  let(:provider) do
+    node = Chef::Node.new
+    events = Chef::EventDispatch::Dispatcher.new
+    run_context = Chef::RunContext.new(node, {}, events)
+    Chef::Provider::Package::Chocolatey.new(new_resource, run_context)
+  end
+
+  let(:choco_install_path) { "C:\\ProgramData\\chocolatey" }
+  let(:choco_exe) { "#{choco_install_path}\\bin\\choco.exe" }
+
+  # installed packages (ConEmu is upgradable)
+  let(:local_list_stdout) do
+    <<-EOF
+chocolatey|0.9.9.11
+ConEmu|15.10.25.0
+    EOF
+  end
+
+  before do
+    allow(provider).to receive(:choco_install_path).and_return(choco_install_path)
+    allow(provider).to receive(:choco_exe).and_return(choco_exe)
+    local_list_obj = double(:stdout => local_list_stdout)
+    allow(provider).to receive(:shell_out!).with("#{choco_exe} list -l -r", { :timeout => timeout }).and_return(local_list_obj)
+  end
+
+  def allow_remote_list(package_names, args = nil)
+    remote_list_stdout = <<-EOF
+chocolatey|0.9.9.11
+ConEmu|15.10.25.1
+Git|2.6.1
+Git|2.6.2
+munin-node|1.6.1.20130823
+    EOF
+    remote_list_obj = double(stdout: remote_list_stdout)
+    allow(provider).to receive(:shell_out!).with("#{choco_exe} list -ar #{package_names.join ' '}#{args}", { timeout: timeout }).and_return(remote_list_obj)
+  end
+
+  describe "#initialize" do
+    it "should return the correct class" do
+      expect(provider).to be_kind_of(Chef::Provider::Package::Chocolatey)
+    end
+
+    it "should support arrays" do
+      expect(provider.use_multipackage_api?).to be true
+    end
+  end
+
+  describe "#candidate_version" do
+    it "should set the candidate_version to the latest version when not pinning" do
+      allow_remote_list(["git"])
+      expect(provider.candidate_version).to eql(["2.6.2"])
+    end
+
+    it "should set the candidate_version to pinned version if available" do
+      allow_remote_list(["git"])
+      new_resource.version("2.6.1")
+      expect(provider.candidate_version).to eql(["2.6.1"])
+    end
+
+    it "should set the candidate_version to nill if pinning to bogus version" do
+      allow_remote_list(["git"])
+      new_resource.version("2.5.0")
+      expect(provider.candidate_version).to eql([nil])
+    end
+
+    it "should set the candidate_version to nil if there is no candidate" do
+      allow_remote_list(["vim"])
+      new_resource.package_name("vim")
+      expect(provider.candidate_version).to eql([nil])
+    end
+
+    it "should set the candidate_version correctly when there are two packages to install" do
+      allow_remote_list(["ConEmu", "chocolatey"])
+      new_resource.package_name(["ConEmu", "chocolatey"])
+      expect(provider.candidate_version).to eql(["15.10.25.1", "0.9.9.11"])
+    end
+
+    it "should set the candidate_version correctly when only the first is installable" do
+      allow_remote_list(["ConEmu", "vim"])
+      new_resource.package_name(["ConEmu", "vim"])
+      expect(provider.candidate_version).to eql(["15.10.25.1", nil])
+    end
+
+    it "should set the candidate_version correctly when only the last is installable" do
+      allow_remote_list(["vim", "chocolatey"])
+      new_resource.package_name(["vim", "chocolatey"])
+      expect(provider.candidate_version).to eql([nil, "0.9.9.11"])
+    end
+
+    it "should set the candidate_version correctly when neither are is installable" do
+      allow_remote_list(["vim", "ruby"])
+      new_resource.package_name(["vim", "ruby"])
+      expect(provider.candidate_version).to eql([nil, nil])
+    end
+  end
+
+  describe "#load_current_resource" do
+    it "should return a current_resource" do
+      expect(provider.load_current_resource).to be_kind_of(Chef::Resource::ChocolateyPackage)
+    end
+
+    it "should set the current_resource#package_name" do
+      provider.load_current_resource
+      expect(provider.current_resource.package_name).to eql(["git"])
+    end
+
+    it "should load and downcase names in the installed_packages hash" do
+      provider.load_current_resource
+      expect(provider.send(:installed_packages)).to eql(
+        { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.0" }
+      )
+    end
+
+    it "should load and downcase names in the available_packages hash" do
+      allow_remote_list(["git"])
+      provider.load_current_resource
+      expect(provider.send(:available_packages)).to eql(
+        { "chocolatey" => "0.9.9.11", "conemu" => "15.10.25.1", "git" => "2.6.2", "munin-node" => "1.6.1.20130823" }
+      )
+    end
+
+    it "should set the current_resource.version to nil when the package is not installed" do
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql([nil])
+    end
+
+    it "should set the current_resource.version to the installed version when the package is installed" do
+      new_resource.package_name("ConEmu")
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql(["15.10.25.0"])
+    end
+
+    it "should set the current_resource.version when there are two packages that are installed" do
+      new_resource.package_name(["ConEmu", "chocolatey"])
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql(["15.10.25.0", "0.9.9.11"])
+    end
+
+    it "should set the current_resource.version correctly when only the first is installed" do
+      new_resource.package_name(["ConEmu", "git"])
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql(["15.10.25.0", nil])
+    end
+
+    it "should set the current_resource.version correctly when only the last is installed" do
+      new_resource.package_name(["git", "chocolatey"])
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql([nil, "0.9.9.11"])
+    end
+
+    it "should set the current_resource.version correctly when none are installed" do
+      new_resource.package_name(["git", "vim"])
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eql([nil, nil])
+    end
+  end
+
+  describe "#action_install" do
+    it "should install a single package" do
+      allow_remote_list(["git"])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    context "when changing the timeout to 3600" do
+      let(:timeout) { 3600 }
+      it "sets the timeout on shell_out commands" do
+        allow_remote_list(["git"])
+        new_resource.timeout(timeout)
+        provider.load_current_resource
+        expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double)
+        provider.run_action(:install)
+        expect(new_resource).to be_updated_by_last_action
+      end
+    end
+
+    it "should not install packages that are up-to-date" do
+      allow_remote_list(["chocolatey"])
+      new_resource.package_name("chocolatey")
+      provider.load_current_resource
+      expect(provider).not_to receive(:install_package)
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "should not upgrade packages" do
+      allow_remote_list(["ConEmu"])
+      new_resource.package_name("ConEmu")
+      provider.load_current_resource
+      expect(provider).not_to receive(:install_package)
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "should upgrade packages when given a version pin" do
+      allow_remote_list(["ConEmu"])
+      new_resource.package_name("ConEmu")
+      new_resource.version("15.10.25.1")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should handle complicated cases when the name/version array is pruned" do
+      # chocolatey will be pruned by the superclass out of the args to install_package and we
+      # implicitly test that we correctly pick up new_resource.version[1] instead of
+      # new_version.resource[0]
+      allow_remote_list(["chocolatey", "ConEmu"])
+      new_resource.package_name(["chocolatey", "ConEmu"])
+      new_resource.version([nil, "15.10.25.1"])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should be case-insensitive" do
+      allow_remote_list(["conemu"])
+      new_resource.package_name("conemu")
+      new_resource.version("15.10.25.1")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should split up commands when given two packages, one with a version pin" do
+      allow_remote_list(["ConEmu", "git"])
+      new_resource.package_name(["ConEmu", "git"])
+      new_resource.version(["15.10.25.1", nil])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -version 15.10.25.1 conemu", { :timeout => timeout }).and_return(double)
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should do multipackage installs when given two packages without constraints" do
+      allow_remote_list(["git", "munin-node"])
+      new_resource.package_name(["git", "munin-node"])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y git munin-node", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    context "when passing a source argument" do
+      it "should pass options into the install command" do
+        allow_remote_list(["git"], " -source localpackages")
+        new_resource.source("localpackages")
+        provider.load_current_resource
+        expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -source localpackages git", { :timeout => timeout }).and_return(double)
+        provider.run_action(:install)
+        expect(new_resource).to be_updated_by_last_action
+      end
+    end
+
+    it "should pass options into the install command" do
+      allow_remote_list(["git"])
+      new_resource.options("-force")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} install -y -force git", { :timeout => timeout }).and_return(double)
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "installing a package that does not exist throws an error" do
+      allow_remote_list(["package-does-not-exist"])
+      new_resource.package_name("package-does-not-exist")
+      provider.load_current_resource
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "installing a package version that does not exist throws an error" do
+      allow_remote_list(["git"])
+      new_resource.package_name("git")
+      new_resource.version("2.7.0")
+      provider.load_current_resource
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "installing multiple packages with a package that does not exist throws an error" do
+      allow_remote_list(["git", "package-does-not-exist"])
+      new_resource.package_name(["git", "package-does-not-exist"])
+      provider.load_current_resource
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    context "alternate source" do
+      it "installing a package that does not exist throws an error" do
+        allow_remote_list(["package-does-not-exist"], " -source alternate_source")
+        new_resource.package_name("package-does-not-exist")
+        new_resource.source("alternate_source")
+        provider.load_current_resource
+        expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      end
+    end
+  end
+
+  describe "#action_upgrade" do
+    it "should install a package that is not installed" do
+      allow_remote_list(["git"])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y git", { :timeout => timeout }).and_return(double)
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should upgrade a package that is installed but upgradable" do
+      allow_remote_list(["ConEmu"])
+      new_resource.package_name("ConEmu")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should be case insensitive" do
+      allow_remote_list(["conemu"])
+      new_resource.package_name("conemu")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "should not install a package that is up-to-date" do
+      allow_remote_list(["chocolatey"])
+      new_resource.package_name("chocolatey")
+      provider.load_current_resource
+      expect(provider).not_to receive(:shell_out!).with("#{choco_exe} upgrade -y chocolatey", { :timeout => timeout })
+      provider.run_action(:upgrade)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "version pins work as well" do
+      allow_remote_list(["git"])
+      new_resource.version("2.6.2")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y -version 2.6.2 git", { :timeout => timeout })
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "upgrading multiple packages uses a single command" do
+      allow_remote_list(["conemu", "git"])
+      new_resource.package_name(["conemu", "git"])
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} upgrade -y conemu git", { :timeout => timeout }).and_return(double)
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "upgrading a package that does not exist throws an error" do
+      allow_remote_list(["package-does-not-exist"])
+      new_resource.package_name("package-does-not-exist")
+      provider.load_current_resource
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    it "upgrading multiple packages with a package that does not exist throws an error" do
+      allow_remote_list(["git", "package-does-not-exist"])
+      new_resource.package_name(["git", "package-does-not-exist"])
+      provider.load_current_resource
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    context "alternate source" do
+      it "installing a package that does not exist throws an error" do
+        allow_remote_list(["package-does-not-exist"], " -source alternate_source")
+        new_resource.package_name("package-does-not-exist")
+        new_resource.source("alternate_source")
+        provider.load_current_resource
+        expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+      end
+    end
+  end
+
+  describe "#action_remove" do
+    it "does nothing when the package is already removed" do
+      allow_remote_list(["git"])
+      provider.load_current_resource
+      expect(provider).not_to receive(:remove_package)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "does nothing when all the packages are already removed" do
+      allow_remote_list(["git", "package-does-not-exist"])
+      new_resource.package_name(["git", "package-does-not-exist"])
+      provider.load_current_resource
+      expect(provider).not_to receive(:remove_package)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+
+    it "removes a package" do
+      allow_remote_list(["ConEmu"])
+      new_resource.package_name("ConEmu")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y ConEmu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "is case-insensitive" do
+      allow_remote_list(["conemu"])
+      new_resource.package_name("conemu")
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
+    end
+
+    it "removes a single package when its the only one installed" do
+      pending "this is a bug in the superclass"
+      allow_remote_list(["git", "conemu"])
+      new_resource.package_name(["git", "conemu"])
+      provider.load_current_resource
+      expect(provider).to receive(:shell_out!).with("#{choco_exe} uninstall -y conemu", { :timeout => timeout }).and_return(double)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
+    end
+  end
+
+  describe "#action_uninstall" do
+    it "should call :remove with a deprecation warning" do
+      Chef::Config[:treat_deprecation_warnings_as_errors] = false
+      expect(Chef::Log).to receive(:deprecation).with(/please use :remove/)
+      allow_remote_list(["ConEmu"])
+      new_resource.package_name("ConEmu")
+      provider.load_current_resource
+      expect(provider).to receive(:remove_package)
+      provider.run_action(:uninstall)
+      expect(new_resource).to be_updated_by_last_action
+    end
+  end
+
+  describe "#choco_exe" do
+    it "calls #choco_install_path" do
+      # un-stub #choco_exe from the before{} block.
+      allow(provider).to receive(:choco_exe).and_call_original
+      expect(provider).to receive(:choco_install_path).and_return("spork")
+      provider.instance_variable_set("@choco_exe", nil)
+
+      expect(provider.send(:choco_exe)).to match(%r{spork[/\\]bin[/\\]choco.exe})
+    end
+  end
+end
+
+describe "behavior when Chocolatey is not installed" do
+  let(:new_resource) { Chef::Resource::ChocolateyPackage.new("git") }
+
+  let(:provider) do
+    node = Chef::Node.new
+    events = Chef::EventDispatch::Dispatcher.new
+    run_context = Chef::RunContext.new(node, {}, events)
+    Chef::Provider::Package::Chocolatey.new(new_resource, run_context)
+  end
+
+  before {
+    allow(provider).to receive(:choco_install_path).and_return("")
+    provider.instance_variable_set("@choco_install_path", nil)
+
+    # we don't care what this returns, but we have to let it be called.
+    allow(provider).to receive(:shell_out!).and_return(double(:stdout => ""))
+  }
+
+  context "#define_resource_requirements" do
+    it "triggers a MissingLibrary exception when Chocolatey is not installed" do
+      provider.action = :install
+      provider.load_current_resource
+      provider.define_resource_requirements
+      expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::MissingLibrary, /Could not locate.*install.*cookbook.*PowerShell.*GetEnvironmentVariable/m)
+    end
+  end
+end
diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb
index 3fd8621..613f7a3 100644
--- a/spec/unit/provider/package/dpkg_spec.rb
+++ b/spec/unit/provider/package/dpkg_spec.rb
@@ -1,6 +1,5 @@
-#
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,180 +15,273 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Dpkg do
+  let(:node) { Chef::Node.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:package) { "wget" }
+  let(:source) { "/tmp/wget_1.11.4-1ubuntu1_amd64.deb" }
+  let(:new_resource) do
+    new_resource = Chef::Resource::DpkgPackage.new(package)
+    new_resource.source source
+    new_resource
+  end
+  let(:provider) { Chef::Provider::Package::Dpkg.new(new_resource, run_context) }
+
+  let(:dpkg_deb_version) { "1.11.4" }
+  let(:dpkg_deb_status) { status = double(:stdout => "#{package}\t#{dpkg_deb_version}", :exitstatus => 0) }
+  let(:dpkg_s_version) { "1.11.4-1ubuntu1" }
+  let(:dpkg_s_status) do
+    stdout = <<-DPKG_S
+Package: #{package}
+Status: install ok installed
+Priority: important
+Section: web
+Installed-Size: 1944
+Maintainer: Ubuntu Core developers <ubuntu-devel-discuss at lists.ubuntu.com>
+Architecture: amd64
+Version: #{dpkg_s_version}
+Config-Version: #{dpkg_s_version}
+Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5)
+Conflicts: wget-ssl
+    DPKG_S
+    status = double(:stdout => stdout, :exitstatus => 1)
+  end
+
   before(:each) do
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new("wget")
-    @new_resource.source "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+    allow(provider).to receive(:shell_out!).with("dpkg-deb -W #{source}", timeout: 900).and_return(dpkg_deb_status)
+    allow(provider).to receive(:shell_out!).with("dpkg -s #{package}", timeout: 900, returns: [0, 1]).and_return(double(stdout: "", exitstatus: 1))
+    allow(::File).to receive(:exist?).with(source).and_return(true)
+  end
 
-    @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
+  describe "#define_resource_requirements" do
+    it "should raise an exception if a source is supplied but not found when :install" do
+      allow(::File).to receive(:exist?).with(source).and_return(false)
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+    end
 
-    @status = double(:stdout => "", :exitstatus => 0)
-    allow(@provider).to receive(:shell_out).and_return(@status)
+    it "should raise an exception if a source is supplied but not found when :upgrade" do
+      allow(::File).to receive(:exist?).with(source).and_return(false)
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    # FIXME?  we're saying we ignore source, but should supplying source on :remove or :purge be an actual error?
+    it "should not raise an exception if a source is supplied but not found when :remove" do
+      allow(::File).to receive(:exist?).with(source).and_return(false)
+      expect(provider).to receive(:action_remove)
+      expect { provider.run_action(:remove) }.not_to raise_error
+    end
+
+    it "should not raise an exception if a source is supplied but not found when :purge" do
+      allow(::File).to receive(:exist?).with(source).and_return(false)
+      expect(provider).to receive(:action_purge)
+      expect { provider.run_action(:purge) }.not_to raise_error
+    end
+
+    context "when source is nil" do
+      let(:source) { nil }
+
+      it "should raise an exception if a source is nil when :install" do
+        expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      end
+
+      it "should raise an exception if a source is nil when :upgrade" do
+        expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+      end
 
-    allow(::File).to receive(:exists?).and_return(true)
+      it "should not raise an exception if a source is nil when :remove" do
+        expect(provider).to receive(:action_remove)
+        expect { provider.run_action(:remove) }.not_to raise_error
+      end
+
+      it "should not raise an exception if a source is nil when :purge" do
+        expect(provider).to receive(:action_purge)
+        expect { provider.run_action(:purge) }.not_to raise_error
+      end
+    end
   end
 
   describe "when loading the current resource state" do
 
     it "should create a current resource with the name of the new_resource" do
-      @provider.load_current_resource
-      expect(@provider.current_resource.package_name).to eq("wget")
+      provider.load_current_resource
+      expect(provider.current_resource.package_name).to eq(["wget"])
     end
 
-    it "should raise an exception if a source is supplied but not found" do
-      @provider.load_current_resource
-      @provider.define_resource_requirements
-      allow(::File).to receive(:exists?).and_return(false)
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
-    end
-
-    describe 'gets the source package version from dpkg-deb' do
+    describe "gets the source package version from dpkg-deb" do
       def check_version(version)
-        @status = double(:stdout => "wget\t#{version}", :exitstatus => 0)
-        allow(@provider).to receive(:shell_out).with("dpkg-deb -W #{@new_resource.source}").and_return(@status)
-        @provider.load_current_resource
-        expect(@provider.current_resource.package_name).to eq("wget")
-        expect(@new_resource.version).to eq(version)
-        expect(@provider.candidate_version).to eq(version)
+        status = double(:stdout => "wget\t#{version}", :exitstatus => 0)
+        expect(provider).to receive(:shell_out!).with("dpkg-deb -W #{source}", timeout: 900).and_return(status)
+        provider.load_current_resource
+        expect(provider.current_resource.package_name).to eq(["wget"])
+        expect(provider.candidate_version).to eq([version])
       end
 
-      it 'if short version provided' do
-        check_version('1.11.4')
+      it "if short version provided" do
+        check_version("1.11.4")
       end
 
-      it 'if extended version provided' do
-        check_version('1.11.4-1ubuntu1')
+      it "if extended version provided" do
+        check_version("1.11.4-1ubuntu1")
       end
 
-      it 'if distro-specific version provided' do
-        check_version('1.11.4-1ubuntu1~lucid')
+      it "if distro-specific version provided" do
+        check_version("1.11.4-1ubuntu1~lucid")
       end
 
-      it 'returns the version if an epoch is used' do
-        check_version('1:1.8.3-2')
+      it "returns the version if an epoch is used" do
+        check_version("1:1.8.3-2")
       end
     end
 
-    it "gets the source package name from dpkg-deb correctly when the package name has `-', `+' or `.' characters" do
-      stdout = "f.o.o-pkg++2\t1.11.4-1ubuntu1"
-      status = double(:stdout => stdout, :exitstatus => 1)
-      allow(@provider).to receive(:shell_out).and_return(status)
-      @provider.load_current_resource
-      expect(@provider.current_resource.package_name).to eq("f.o.o-pkg++2")
+    describe "when the package name has `-', `+' or `.' characters" do
+      let(:package) { "f.o.o-pkg++2" }
+
+      it "gets the source package name from dpkg-deb correctly" do
+        provider.load_current_resource
+        expect(provider.current_resource.package_name).to eq(["f.o.o-pkg++2"])
+      end
+    end
+
+    describe "when the package version has `~', `-', `+' or `.' characters" do
+      let(:package) { "b.a.r-pkg++1" }
+      let(:dpkg_deb_version) { "1.2.3+3141592-1ubuntu1~lucid" }
+      let(:dpkg_s_version) { "1.2.3+3141592-1ubuntu1~lucid" }
+
+      it "gets the source package version from dpkg-deb correctly when the package version has `~', `-', `+' or `.' characters" do
+        provider.load_current_resource
+        expect(provider.candidate_version).to eq(["1.2.3+3141592-1ubuntu1~lucid"])
+      end
     end
 
-    it "should raise an exception if the source is not set but we are installing" do
-      @new_resource = Chef::Resource::Package.new("wget")
-      @provider.new_resource = @new_resource
-      @provider.load_current_resource
-      @provider.define_resource_requirements
-      expect { @provider.run_action(:install)}.to raise_error(Chef::Exceptions::Package)
+    describe "when the source is not set" do
+      let(:source) { nil }
+
+      it "should raise an exception if the source is not set but we are installing" do
+        expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      end
     end
 
     it "should return the current version installed if found by dpkg" do
-      stdout = <<-DPKG_S
-Package: wget
-Status: install ok installed
-Priority: important
-Section: web
-Installed-Size: 1944
-Maintainer: Ubuntu Core developers <ubuntu-devel-discuss at lists.ubuntu.com>
-Architecture: amd64
-Version: 1.11.4-1ubuntu1
-Config-Version: 1.11.4-1ubuntu1
-Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5)
-Conflicts: wget-ssl
-DPKG_S
-      status = double(:stdout => stdout, :exitstatus => 1)
-      allow(@provider).to receive(:shell_out).with("dpkg -s wget").and_return(status)
+      allow(provider).to receive(:shell_out!).with("dpkg -s #{package}", timeout: 900, returns: [0, 1]).and_return(dpkg_s_status)
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eq(["1.11.4-1ubuntu1"])
+    end
+
+    it "on new debian/ubuntu we get an exit(1) and no stdout from dpkg -s for uninstalled" do
+      dpkg_s_status = double(
+        exitstatus: 1, stdout: "", stderr: <<-EOF
+dpkg-query: package '#{package}' is not installed and no information is available
+Use dpkg --info (= dpkg-deb --info) to examine archive files,
+and dpkg --contents (= dpkg-deb --contents) to list their contents.
+        EOF
+      )
+      expect(provider).to receive(:shell_out!).with("dpkg -s #{package}", returns: [0, 1], timeout: 900).and_return(dpkg_s_status)
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eq([nil])
+    end
 
-      @provider.load_current_resource
-      expect(@provider.current_resource.version).to eq("1.11.4-1ubuntu1")
+    it "on old debian/ubuntu we get an exit(0) and we get info on stdout from dpkg -s for uninstalled" do
+      dpkg_s_status = double(
+        exitstatus: 0, stderr: "", stdout: <<-EOF
+Package: #{package}
+Status: unknown ok not-installed
+Priority: extra
+Section: ruby
+        EOF
+      )
+      expect(provider).to receive(:shell_out!).with("dpkg -s #{package}", returns: [0, 1], timeout: 900).and_return(dpkg_s_status)
+      provider.load_current_resource
+      expect(provider.current_resource.version).to eq([nil])
     end
 
-    it "should raise an exception if dpkg fails to run" do
+    it "and we should raise if we get any other exit codes from dpkg -s" do
+      dpkg_s_status = double(
+        exitstatus: 3, stderr: "i am very, very angry with you.  i'm very, very cross.  go to your room.", stdout: ""
+      )
+      expect(provider).to receive(:shell_out!).with("dpkg -s #{package}", returns: [0, 1], timeout: 900).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+      expect { provider.load_current_resource }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
+    end
+
+    it "should raise an exception if dpkg-deb -W fails to run" do
       status = double(:stdout => "", :exitstatus => -1)
-      allow(@provider).to receive(:shell_out).and_return(status)
-      expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
+      expect(provider).to receive(:shell_out_with_timeout!).with("dpkg-deb -W /tmp/wget_1.11.4-1ubuntu1_amd64.deb").and_raise(Mixlib::ShellOut::ShellCommandFailed)
+      expect { provider.load_current_resource }.to raise_error(Mixlib::ShellOut::ShellCommandFailed)
     end
   end
 
   describe Chef::Provider::Package::Dpkg, "install and upgrade" do
     it "should run dpkg -i with the package source" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -i", nil, "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
       )
-      @provider.install_package("wget", "1.11.4-1ubuntu1")
+      provider.load_current_resource
+      provider.run_action(:install)
     end
 
     it "should run dpkg -i if the package is a path and the source is nil" do
-      @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb")
-      @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      new_resource.name "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -i", nil, "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
       )
-      @provider.install_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1")
+      provider.run_action(:install)
     end
 
     it "should run dpkg -i if the package is a path and the source is nil for an upgrade" do
-      @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb")
-      @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context)
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      new_resource.name "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -i", nil, "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
       )
-      @provider.upgrade_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1")
+      provider.run_action(:upgrade)
     end
 
     it "should run dpkg -i with the package source and options if specified" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -i --force-yes /tmp/wget_1.11.4-1ubuntu1_amd64.deb"
+      new_resource.options "--force-yes"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -i", "--force-yes", "/tmp/wget_1.11.4-1ubuntu1_amd64.deb"
       )
-      allow(@new_resource).to receive(:options).and_return("--force-yes")
-
-      @provider.install_package("wget", "1.11.4-1ubuntu1")
+      provider.run_action(:install)
     end
+
     it "should upgrade by running install_package" do
-      expect(@provider).to receive(:install_package).with("wget", "1.11.4-1ubuntu1")
-      @provider.upgrade_package("wget", "1.11.4-1ubuntu1")
+      expect(provider).to receive(:install_package).with(["wget"], ["1.11.4-1ubuntu1"])
+      provider.upgrade_package(["wget"], ["1.11.4-1ubuntu1"])
     end
   end
 
   describe Chef::Provider::Package::Dpkg, "remove and purge" do
     it "should run dpkg -r to remove the package" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -r wget"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -r", nil, "wget"
       )
-      @provider.remove_package("wget", "1.11.4-1ubuntu1")
+      provider.remove_package(["wget"], ["1.11.4-1ubuntu1"])
     end
 
     it "should run dpkg -r to remove the package with options if specified" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -r --force-yes wget"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -r", "--force-yes", "wget"
       )
-      allow(@new_resource).to receive(:options).and_return("--force-yes")
+      allow(new_resource).to receive(:options).and_return("--force-yes")
 
-      @provider.remove_package("wget", "1.11.4-1ubuntu1")
+      provider.remove_package(["wget"], ["1.11.4-1ubuntu1"])
     end
 
     it "should run dpkg -P to purge the package" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -P wget"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -P", nil, "wget"
       )
-      @provider.purge_package("wget", "1.11.4-1ubuntu1")
+      provider.purge_package(["wget"], ["1.11.4-1ubuntu1"])
     end
 
     it "should run dpkg -P to purge the package with options if specified" do
-      expect(@provider).to receive(:run_noninteractive).with(
-        "dpkg -P --force-yes wget"
+      expect(provider).to receive(:run_noninteractive).with(
+        "dpkg -P", "--force-yes", "wget"
       )
-      allow(@new_resource).to receive(:options).and_return("--force-yes")
+      allow(new_resource).to receive(:options).and_return("--force-yes")
 
-      @provider.purge_package("wget", "1.11.4-1ubuntu1")
+      provider.purge_package(["wget"], ["1.11.4-1ubuntu1"])
     end
   end
 end
diff --git a/spec/unit/provider/package/easy_install_spec.rb b/spec/unit/provider/package/easy_install_spec.rb
index 221ec8f..8ce4856 100644
--- a/spec/unit/provider/package/easy_install_spec.rb
+++ b/spec/unit/provider/package/easy_install_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::EasyInstall do
   before(:each) do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::EasyInstallPackage.new('boto')
-    @new_resource.version('1.8d')
-
-    @current_resource = Chef::Resource::EasyInstallPackage.new('boto')
-    @current_resource.version('1.8d')
+    @new_resource = Chef::Resource::EasyInstallPackage.new("boto")
+    @new_resource.version("1.8d")
 
     @provider = Chef::Provider::Package::EasyInstall.new(@new_resource, @run_context)
-    allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
 
     @stdin = StringIO.new
     @stdout = StringIO.new
@@ -48,8 +44,8 @@ describe Chef::Provider::Package::EasyInstall do
 
     it "should set the current resources package name to the new resources package name" do
       allow($stdout).to receive(:write)
-      expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
       @provider.load_current_resource
+      expect(@provider.current_resource.package_name).to eq(@new_resource.package_name)
     end
 
     it "should return a relative path to easy_install if no easy_install_binary is given" do
@@ -67,14 +63,14 @@ describe Chef::Provider::Package::EasyInstall do
     it "should run easy_install with the package name and version" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install \"boto==1.8d\""
-      })
+      },)
       @provider.install_package("boto", "1.8d")
     end
 
     it "should run easy_install with the package name and version and specified options" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install --always-unzip \"boto==1.8d\""
-      })
+      },)
       allow(@new_resource).to receive(:options).and_return("--always-unzip")
       @provider.install_package("boto", "1.8d")
     end
@@ -82,21 +78,21 @@ describe Chef::Provider::Package::EasyInstall do
     it "should run easy_install with the package name and version" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install \"boto==1.8d\""
-      })
+      },)
       @provider.upgrade_package("boto", "1.8d")
     end
 
     it "should run easy_install -m with the package name and version" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install -m boto"
-      })
+      },)
       @provider.remove_package("boto", "1.8d")
     end
 
     it "should run easy_install -m with the package name and version and specified options" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install -x -m boto"
-      })
+      },)
       allow(@new_resource).to receive(:options).and_return("-x")
       @provider.remove_package("boto", "1.8d")
     end
@@ -104,7 +100,7 @@ describe Chef::Provider::Package::EasyInstall do
     it "should run easy_install -m with the package name and version" do
       expect(@provider).to receive(:run_command).with({
         :command => "easy_install -m boto"
-      })
+      },)
       @provider.purge_package("boto", "1.8d")
     end
 
diff --git a/spec/unit/provider/package/freebsd/pkg_spec.rb b/spec/unit/provider/package/freebsd/pkg_spec.rb
index f671619..8890f62 100644
--- a/spec/unit/provider/package/freebsd/pkg_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkg_spec.rb
@@ -1,7 +1,7 @@
 #
 # Authors:: Bryan McLellan (btm at loftninjas.org)
 #           Matthew Landauer (matthew at openaustralia.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer
+# Copyright:: Copyright 2009-2016, Bryan McLellan, Matthew Landauer
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
   before(:each) do
@@ -30,7 +30,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
 
     @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context)
     @provider.current_resource = @current_resource
-    allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(false)
+    allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(false)
   end
 
   describe "when determining the current package state" do
@@ -77,7 +77,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
 
     it "should return the version number when it is installed" do
       pkg_info = OpenStruct.new(:stdout => "zsh-4.3.6_7")
-      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
       #@provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, ["zsh-4.3.6_7"], @stderr).and_return(@status)
       allow(@provider).to receive(:package_name).and_return("zsh")
       expect(@provider.current_installed_version).to eq("4.3.6_7")
@@ -85,14 +85,14 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
 
     it "does not set the current version number when the package is not installed" do
       pkg_info = OpenStruct.new(:stdout => "")
-      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
       allow(@provider).to receive(:package_name).and_return("zsh")
       expect(@provider.current_installed_version).to be_nil
     end
 
     it "should return the port path for a valid port name" do
       whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
-      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
       #@provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status)
       allow(@provider).to receive(:port_name).and_return("zsh")
       expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
@@ -102,15 +102,15 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
     it "should return the ports candidate version when given a valid port path" do
       allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
       make_v = OpenStruct.new(:stdout => "4.3.6\n", :exitstatus => 0)
-      expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", {:cwd=>"/usr/ports/shells/zsh", :returns=>[0, 1], :env=>nil}).and_return(make_v)
+      expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", { cwd: "/usr/ports/shells/zsh", returns: [0, 1], env: nil, timeout: 900 }).and_return(make_v)
       expect(@provider.ports_candidate_version).to eq("4.3.6")
     end
 
     it "should figure out the package name when we have ports" do
-      allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
+      allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(true)
       allow(@provider).to receive(:port_path).and_return("/usr/ports/shells/zsh")
       make_v = OpenStruct.new(:stdout => "zsh-4.3.6_7\n", :exitstatus => 0)
-      expect(@provider).to receive(:shell_out!).with("make -V PKGNAME", {:cwd=>"/usr/ports/shells/zsh", :env=>nil, :returns=>[0, 1]}).and_return(make_v)
+      expect(@provider).to receive(:shell_out!).with("make -V PKGNAME", { cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900 }).and_return(make_v)
       #@provider.should_receive(:ports_makefile_variable_value).with("PKGNAME").and_return("zsh-4.3.6_7")
       expect(@provider.package_name).to eq("zsh")
     end
@@ -127,7 +127,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
     end
 
     it "should run pkg_add -r with the package name" do
-      expect(@provider).to receive(:shell_out!).with("pkg_add -r zsh", :env => nil).and_return(@cmd_result)
+      expect(@provider).to receive(:shell_out!).with("pkg_add -r zsh", env: nil, timeout: 900).and_return(@cmd_result)
       @provider.install_package("zsh", "4.3.6_7")
     end
   end
@@ -142,7 +142,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
 
     it "should figure out the port path from the package_name using whereis" do
       whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh")
-      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env=>nil).and_return(whereis)
+      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
       expect(@provider.port_path).to eq("/usr/ports/shells/zsh")
     end
 
@@ -178,7 +178,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
     end
 
     it "should run pkg_add -r with the package name" do
-      expect(@provider).to receive(:shell_out!).with("pkg_add -r ruby18-iconv", :env => nil).and_return(@install_result)
+      expect(@provider).to receive(:shell_out!).with("pkg_add -r ruby18-iconv", env: nil, timeout: 900).and_return(@install_result)
       @provider.install_package("ruby-iconv", "1.0")
     end
   end
@@ -193,7 +193,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
     end
 
     it "should run pkg_delete with the package name and version" do
-      expect(@provider).to receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", :env => nil).and_return(@pkg_delete)
+      expect(@provider).to receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", env: nil, timeout: 900).and_return(@pkg_delete)
       @provider.remove_package("zsh", "4.3.6_7")
     end
   end
@@ -213,14 +213,14 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
 
     it "should return the port path for a valid port name" do
       whereis = OpenStruct.new(:stdout => "bonnie++: /usr/ports/benchmarks/bonnie++")
-      expect(@provider).to receive(:shell_out!).with("whereis -s bonnie++", :env => nil).and_return(whereis)
+      expect(@provider).to receive(:shell_out!).with("whereis -s bonnie++", env: nil, timeout: 900).and_return(whereis)
       allow(@provider).to receive(:port_name).and_return("bonnie++")
       expect(@provider.port_path).to eq("/usr/ports/benchmarks/bonnie++")
     end
 
     it "should return the version number when it is installed" do
       pkg_info = OpenStruct.new(:stdout => "bonnie++-1.96")
-      expect(@provider).to receive(:shell_out!).with('pkg_info -E "bonnie++*"', :env => nil, :returns => [0,1]).and_return(pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg_info -E "bonnie++*"', env: nil, returns: [0, 1], timeout: 900).and_return(pkg_info)
       allow(@provider).to receive(:package_name).and_return("bonnie++")
       expect(@provider.current_installed_version).to eq("1.96")
     end
@@ -253,7 +253,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
       allow(@provider).to receive(:latest_link_name).and_return("perl")
 
       cmd = OpenStruct.new(:status => true)
-      expect(@provider).to receive(:shell_out!).with("pkg_add -r perl", :env => nil).and_return(cmd)
+      expect(@provider).to receive(:shell_out!).with("pkg_add -r perl", env: nil, timeout: 900).and_return(cmd)
       @provider.install_package("perl5.8", "5.8.8_1")
     end
 
@@ -267,7 +267,7 @@ describe Chef::Provider::Package::Freebsd::Pkg, "load_current_resource" do
       allow(@provider).to receive(:latest_link_name).and_return("mysql50-server")
 
       cmd = OpenStruct.new(:status => true)
-      expect(@provider).to receive(:shell_out!).with("pkg_add -r mysql50-server", :env=>nil).and_return(cmd)
+      expect(@provider).to receive(:shell_out!).with("pkg_add -r mysql50-server", env: nil, timeout: 900).and_return(cmd)
       @provider.install_package("mysql50-server", "5.0.45_1")
     end
   end
diff --git a/spec/unit/provider/package/freebsd/pkgng_spec.rb b/spec/unit/provider/package/freebsd/pkgng_spec.rb
index 0c1e89c..a2bd833 100644
--- a/spec/unit/provider/package/freebsd/pkgng_spec.rb
+++ b/spec/unit/provider/package/freebsd/pkgng_spec.rb
@@ -1,6 +1,6 @@
 #
 # Authors:: Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Freebsd::Port do
   before(:each) do
@@ -30,15 +29,13 @@ describe Chef::Provider::Package::Freebsd::Port do
     @provider = Chef::Provider::Package::Freebsd::Pkgng.new(@new_resource, @run_context)
   end
 
-
   describe "initialization" do
     it "should create a current resource with the name of the new resource" do
       expect(@provider.current_resource.is_a?(Chef::Resource::Package)).to be_truthy
-      expect(@provider.current_resource.name).to eq('zsh')
+      expect(@provider.current_resource.name).to eq("zsh")
     end
   end
 
-
   describe "loading current resource" do
     before(:each) do
       allow(@provider).to receive(:current_installed_version)
@@ -63,7 +60,6 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
   end
 
-
   describe "determining current installed version" do
     before(:each) do
       allow(@provider).to receive(:supports_pkgng?)
@@ -71,23 +67,22 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
 
     it "should query pkg database" do
-      expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
       expect(@provider.current_installed_version).to eq("3.1.7")
     end
   end
 
-
   describe "determining candidate version" do
     it "should query repository" do
       pkg_query = OpenStruct.new(:stdout => "5.0.5\n", :exitstatus => 0)
-      expect(@provider).to receive(:shell_out!).with("pkg rquery '%v' zsh", :env => nil).and_return(pkg_query)
+      expect(@provider).to receive(:shell_out!).with("pkg rquery '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
       expect(@provider.candidate_version).to eq("5.0.5")
     end
 
     it "should query specified repository when given option" do
-      @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+      @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
       pkg_query = OpenStruct.new(:stdout => "5.0.3\n", :exitstatus => 0)
-      expect(@provider).to receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", :env => nil).and_return(pkg_query)
+      expect(@provider).to receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", env: nil, timeout: 900).and_return(pkg_query)
       expect(@provider.candidate_version).to eq("5.0.3")
     end
 
@@ -97,7 +92,6 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
   end
 
-
   describe "installing a binary package" do
     before(:each) do
       @install_result = OpenStruct.new(:status => true)
@@ -106,7 +100,7 @@ describe Chef::Provider::Package::Freebsd::Port do
     it "should handle package source from file" do
       @provider.new_resource.source("/nas/pkg/repo/zsh-5.0.1.txz")
       expect(@provider).to receive(:shell_out!).
-        with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }).
+        with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", env: { "LC_ALL" => nil }, timeout: 900).
         and_return(@install_result)
       @provider.install_package("zsh", "5.0.1")
     end
@@ -114,26 +108,25 @@ describe Chef::Provider::Package::Freebsd::Port do
     it "should handle package source over ftp or http" do
       @provider.new_resource.source("http://repo.example.com/zsh-5.0.1.txz")
       expect(@provider).to receive(:shell_out!).
-        with("pkg add http://repo.example.com/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }).
+        with("pkg add http://repo.example.com/zsh-5.0.1.txz", env: { "LC_ALL" => nil }, timeout: 900).
         and_return(@install_result)
       @provider.install_package("zsh", "5.0.1")
     end
 
     it "should handle a package name" do
       expect(@provider).to receive(:shell_out!).
-        with("pkg install -y zsh", :env => { 'LC_ALL' => nil }).and_return(@install_result)
+        with("pkg install -y zsh", env: { "LC_ALL" => nil }, timeout: 900).and_return(@install_result)
       @provider.install_package("zsh", "5.0.1")
     end
 
     it "should handle a package name with a specified repo" do
-      @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+      @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
       expect(@provider).to receive(:shell_out!).
-        with("pkg install -y -r LocalMirror zsh", :env => { 'LC_ALL' => nil }).and_return(@install_result)
+        with("pkg install -y -r LocalMirror zsh", env: { "LC_ALL" => nil }, timeout: 900).and_return(@install_result)
       @provider.install_package("zsh", "5.0.1")
     end
   end
 
-
   describe "removing a binary package" do
     before(:each) do
       @install_result = OpenStruct.new(:status => true)
@@ -141,14 +134,14 @@ describe Chef::Provider::Package::Freebsd::Port do
 
     it "should call pkg delete" do
       expect(@provider).to receive(:shell_out!).
-        with("pkg delete -y zsh-5.0.1", :env => nil).and_return(@install_result)
+        with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
       @provider.remove_package("zsh", "5.0.1")
     end
 
     it "should not include repo option in pkg delete" do
-      @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration.
+      @provider.new_resource.options("-r LocalMirror") # This requires LocalMirror repo configuration.
       expect(@provider).to receive(:shell_out!).
-        with("pkg delete -y zsh-5.0.1", :env => nil).and_return(@install_result)
+        with("pkg delete -y zsh-5.0.1", env: nil, timeout: 900).and_return(@install_result)
       @provider.remove_package("zsh", "5.0.1")
     end
   end
diff --git a/spec/unit/provider/package/freebsd/port_spec.rb b/spec/unit/provider/package/freebsd/port_spec.rb
index 2e32e88..b593da4 100644
--- a/spec/unit/provider/package/freebsd/port_spec.rb
+++ b/spec/unit/provider/package/freebsd/port_spec.rb
@@ -1,6 +1,6 @@
 #
 # Authors:: Richard Manyanza (liseki at nyikacraftsmen.com)
-# Copyright:: Copyright (c) 2014 Richard Manyanza
+# Copyright:: Copyright 2014-2016, Richard Manyanza
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Freebsd::Port do
   before(:each) do
@@ -30,15 +29,13 @@ describe Chef::Provider::Package::Freebsd::Port do
     @provider = Chef::Provider::Package::Freebsd::Port.new(@new_resource, @run_context)
   end
 
-
   describe "initialization" do
     it "should create a current resource with the name of the new resource" do
       expect(@provider.current_resource.is_a?(Chef::Resource::Package)).to be_truthy
-      expect(@provider.current_resource.name).to eq('zsh')
+      expect(@provider.current_resource.name).to eq("zsh")
     end
   end
 
-
   describe "loading current resource" do
     before(:each) do
       allow(@provider).to receive(:current_installed_version)
@@ -63,7 +60,6 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
   end
 
-
   describe "determining current installed version" do
     before(:each) do
       @pkg_info = OpenStruct.new(:stdout => "zsh-3.1.7\n")
@@ -72,7 +68,7 @@ describe Chef::Provider::Package::Freebsd::Port do
     it "should check 'pkg_info' if system uses pkg_* tools" do
       allow(@new_resource).to receive(:supports_pkgng?)
       expect(@new_resource).to receive(:supports_pkgng?).and_return(false)
-      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(@pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg_info -E "zsh*"', env: nil, returns: [0, 1], timeout: 900).and_return(@pkg_info)
       expect(@provider.current_installed_version).to eq("3.1.7")
     end
 
@@ -80,8 +76,8 @@ describe Chef::Provider::Package::Freebsd::Port do
       pkg_enabled = OpenStruct.new(:stdout => "yes\n")
       [1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version|
         @node.automatic_attrs[:os_version] = __freebsd_version
-        expect(@new_resource).to receive(:shell_out!).with('make -V WITH_PKGNG', :env => nil).and_return(pkg_enabled)
-        expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+        expect(@new_resource).to receive(:shell_out!).with("make -V WITH_PKGNG", env: nil).and_return(pkg_enabled)
+        expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
         expect(@provider.current_installed_version).to eq("3.1.7")
       end
     end
@@ -89,7 +85,7 @@ describe Chef::Provider::Package::Freebsd::Port do
     it "should check 'pkg info' if the freebsd version is greater than or equal to 1000017" do
       __freebsd_version = 1000017
       @node.automatic_attrs[:os_version] = __freebsd_version
-      expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info)
+      expect(@provider).to receive(:shell_out!).with('pkg info "zsh"', env: nil, returns: [0, 70], timeout: 900).and_return(@pkg_info)
       expect(@provider.current_installed_version).to eq("3.1.7")
     end
   end
@@ -100,20 +96,19 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
 
     it "should return candidate version if port exists" do
-      allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(true)
-      allow(@provider).to receive(:port_dir).and_return('/usr/ports/shells/zsh')
-      expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", :cwd => "/usr/ports/shells/zsh", :env => nil, :returns => [0,1]).
+      allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(true)
+      allow(@provider).to receive(:port_dir).and_return("/usr/ports/shells/zsh")
+      expect(@provider).to receive(:shell_out!).with("make -V PORTVERSION", cwd: "/usr/ports/shells/zsh", env: nil, returns: [0, 1], timeout: 900).
         and_return(@port_version)
       expect(@provider.candidate_version).to eq("5.0.5")
     end
 
     it "should raise exception if ports tree not found" do
-      allow(::File).to receive(:exist?).with('/usr/ports/Makefile').and_return(false)
+      allow(::File).to receive(:exist?).with("/usr/ports/Makefile").and_return(false)
       expect { @provider.candidate_version }.to raise_error(Chef::Exceptions::Package, "Ports collection could not be found")
     end
   end
 
-
   describe "determining port directory" do
     it "should return name if package name is absolute path" do
       allow(@provider.new_resource).to receive(:package_name).and_return("/var/ports/shells/zsh")
@@ -127,18 +122,17 @@ describe Chef::Provider::Package::Freebsd::Port do
 
     it "should query system for path given just a name" do
       whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh\n")
-      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
       expect(@provider.port_dir).to eq("/usr/ports/shells/zsh")
     end
 
     it "should raise exception if not found" do
       whereis = OpenStruct.new(:stdout => "zsh:\n")
-      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis)
+      expect(@provider).to receive(:shell_out!).with("whereis -s zsh", env: nil, timeout: 900).and_return(whereis)
       expect { @provider.port_dir }.to raise_error(Chef::Exceptions::Package, "Could not find port with the name zsh")
     end
   end
 
-
   describe "building a binary package" do
     before(:each) do
       @install_result = OpenStruct.new(:status => true)
@@ -153,7 +147,6 @@ describe Chef::Provider::Package::Freebsd::Port do
     end
   end
 
-
   describe "removing a binary package" do
     before(:each) do
       @install_result = OpenStruct.new(:status => true)
diff --git a/spec/unit/provider/package/homebrew_spec.rb b/spec/unit/provider/package/homebrew_spec.rb
index d01d455..17ed5cc 100644
--- a/spec/unit/provider/package/homebrew_spec.rb
+++ b/spec/unit/provider/package/homebrew_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
-# Copyright (c) 2014, Chef Software, Inc. <legal at getchef.com>
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright 2014-2016, Chef Software, Inc. <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,14 +15,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Homebrew do
   let(:node) { Chef::Node.new }
-  let(:events) { double('Chef::Events').as_null_object }
-  let(:run_context) { double('Chef::RunContext', node: node, events: events) }
-  let(:new_resource) { Chef::Resource::HomebrewPackage.new('emacs') }
-  let(:current_resource) { Chef::Resource::HomebrewPackage.new('emacs')}
+  let(:events) { double("Chef::Events").as_null_object }
+  let(:run_context) { double("Chef::RunContext", node: node, events: events) }
+  let(:new_resource) { Chef::Resource::HomebrewPackage.new("emacs") }
+  let(:current_resource) { Chef::Resource::HomebrewPackage.new("emacs") }
 
   let(:provider) do
     Chef::Provider::Package::Homebrew.new(new_resource, run_context)
@@ -32,85 +32,85 @@ describe Chef::Provider::Package::Homebrew do
 
   let(:uninstalled_brew_info) do
     {
-      'name' => 'emacs',
-      'homepage' => 'http://www.gnu.org/software/emacs',
-      'versions' => {
-        'stable' => '24.3',
-        'bottle' => false,
-        'devel' => nil,
-        'head' => nil
+      "name" => "emacs",
+      "homepage" => "http://www.gnu.org/software/emacs",
+      "versions" => {
+        "stable" => "24.3",
+        "bottle" => false,
+        "devel" => nil,
+        "head" => nil,
       },
-      'revision' => 0,
-      'installed' => [],
-      'linked_keg' => nil,
-      'keg_only' => nil,
-      'dependencies' => [],
-      'conflicts_with' => [],
-      'caveats' => nil,
-      'options' => []
+      "revision" => 0,
+      "installed" => [],
+      "linked_keg" => nil,
+      "keg_only" => nil,
+      "dependencies" => [],
+      "conflicts_with" => [],
+      "caveats" => nil,
+      "options" => [],
     }
   end
 
   let(:installed_brew_info) do
     {
-      'name' => 'emacs',
-      'homepage' => 'http://www.gnu.org/software/emacs/',
-      'versions' => {
-        'stable' => '24.3',
-        'bottle' => false,
-        'devel' => nil,
-        'head' => 'HEAD'
+      "name" => "emacs",
+      "homepage" => "http://www.gnu.org/software/emacs/",
+      "versions" => {
+        "stable" => "24.3",
+        "bottle" => false,
+        "devel" => nil,
+        "head" => "HEAD",
       },
-      'revision' => 0,
-      'installed' => [{ 'version' => '24.3' }],
-      'linked_keg' => '24.3',
-      'keg_only' => nil,
-      'dependencies' => [],
-      'conflicts_with' => [],
-      'caveats' => '',
-      'options' => []
+      "revision" => 0,
+      "installed" => [{ "version" => "24.3" }],
+      "linked_keg" => "24.3",
+      "keg_only" => nil,
+      "dependencies" => [],
+      "conflicts_with" => [],
+      "caveats" => "",
+      "options" => [],
     }
   end
 
   let(:keg_only_brew_info) do
     {
-      'name' => 'emacs-kegger',
-      'homepage' => 'http://www.gnu.org/software/emacs/',
-      'versions' => {
-        'stable' => '24.3-keggy',
-        'bottle' => false,
-        'devel' => nil,
-        'head' => 'HEAD'
+      "name" => "emacs-kegger",
+      "homepage" => "http://www.gnu.org/software/emacs/",
+      "versions" => {
+        "stable" => "24.3-keggy",
+        "bottle" => false,
+        "devel" => nil,
+        "head" => "HEAD",
       },
-      'revision' => 0,
-      'installed' => [{ 'version' => '24.3-keggy' }],
-      'linked_keg' => nil,
-      'keg_only' => true,
-      'dependencies' => [],
-      'conflicts_with' => [],
-      'caveats' => '',
-      'options' => []
+      "revision" => 0,
+      "installed" => [{ "version" => "24.3-keggy" }],
+      "linked_keg" => nil,
+      "keg_only" => true,
+      "dependencies" => [],
+      "conflicts_with" => [],
+      "caveats" => "",
+      "options" => [],
     }
   end
 
   let(:keg_only_uninstalled_brew_info) do
     {
-      'name' => 'emacs-kegger',
-      'homepage' => 'http://www.gnu.org/software/emacs/',
-      'versions' => {
-        'stable' => '24.3-keggy',
-        'bottle' => false,
-        'devel' => nil,
-        'head' => 'HEAD'
+      "name" => "emacs-kegger",
+      "homepage" => "http://www.gnu.org/software/emacs/",
+      "versions" => {
+        "stable" => "24.3-keggy",
+        "bottle" => false,
+        "devel" => nil,
+        "head" => "HEAD",
       },
-      'revision' => 0,
-      'installed' => [],
-      'linked_keg' => nil,
-      'keg_only' => true,
-      'dependencies' => [],
-      'conflicts_with' => [],
-      'caveats' => '',
-      'options' => []
+      "revision" => 0,
+      "installed" => [],
+      "linked_keg" => nil,
+      "keg_only" => true,
+      "dependencies" => [],
+      "conflicts_with" => [],
+      "caveats" => "",
+      "options" => [],
     }
   end
 
@@ -118,174 +118,174 @@ describe Chef::Provider::Package::Homebrew do
 
   end
 
-  describe 'load_current_resource' do
+  describe "load_current_resource" do
     before(:each) do
       allow(provider).to receive(:current_installed_version).and_return(nil)
-      allow(provider).to receive(:candidate_version).and_return('24.3')
+      allow(provider).to receive(:candidate_version).and_return("24.3")
     end
 
-    it 'creates a current resource with the name of the new resource' do
+    it "creates a current resource with the name of the new resource" do
       provider.load_current_resource
       expect(provider.current_resource).to be_a(Chef::Resource::Package)
-      expect(provider.current_resource.name).to eql('emacs')
+      expect(provider.current_resource.name).to eql("emacs")
     end
 
-    it 'creates a current resource with the version if the package is installed' do
-      expect(provider).to receive(:current_installed_version).and_return('24.3')
+    it "creates a current resource with the version if the package is installed" do
+      expect(provider).to receive(:current_installed_version).and_return("24.3")
       provider.load_current_resource
-      expect(provider.current_resource.version).to eql('24.3')
+      expect(provider.current_resource.version).to eql("24.3")
     end
 
-    it 'creates a current resource with a nil version if the package is not installed' do
+    it "creates a current resource with a nil version if the package is not installed" do
       provider.load_current_resource
       expect(provider.current_resource.version).to be_nil
     end
 
-    it 'sets a candidate version if one exists' do
+    it "sets a candidate version if one exists" do
       provider.load_current_resource
-      expect(provider.candidate_version).to eql('24.3')
+      expect(provider.candidate_version).to eql("24.3")
     end
   end
 
-  describe 'current_installed_version' do
-    it 'returns the latest version from brew info if the package is keg only' do
+  describe "current_installed_version" do
+    it "returns the latest version from brew info if the package is keg only" do
       allow(provider).to receive(:brew_info).and_return(keg_only_brew_info)
-      expect(provider.current_installed_version).to eql('24.3-keggy')
+      expect(provider.current_installed_version).to eql("24.3-keggy")
     end
 
-    it 'returns the linked keg version if the package is not keg only' do
+    it "returns the linked keg version if the package is not keg only" do
       allow(provider).to receive(:brew_info).and_return(installed_brew_info)
-      expect(provider.current_installed_version).to eql('24.3')
+      expect(provider.current_installed_version).to eql("24.3")
     end
 
-    it 'returns nil if the package is not installed' do
+    it "returns nil if the package is not installed" do
       allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
       expect(provider.current_installed_version).to be_nil
     end
 
-    it 'returns nil if the package is keg only and not installed' do
+    it "returns nil if the package is keg only and not installed" do
       allow(provider).to receive(:brew_info).and_return(keg_only_uninstalled_brew_info)
       expect(provider.current_installed_version).to be_nil
     end
   end
 
-  describe 'brew' do
+  describe "brew" do
     before do
       expect(provider).to receive(:find_homebrew_uid).and_return(homebrew_uid)
       expect(Etc).to receive(:getpwuid).with(homebrew_uid).and_return(OpenStruct.new(:name => "name", :dir => "/"))
     end
 
-    it 'passes a single to the brew command and return stdout' do
-      allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'zombo'))
-      expect(provider.brew).to eql('zombo')
+    it "passes a single to the brew command and return stdout" do
+      allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "zombo"))
+      expect(provider.brew).to eql("zombo")
     end
 
-    it 'takes multiple arguments as an array' do
-      allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'homestarrunner'))
-      expect(provider.brew('info', 'opts', 'bananas')).to eql('homestarrunner')
+    it "takes multiple arguments as an array" do
+      allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "homestarrunner"))
+      expect(provider.brew("info", "opts", "bananas")).to eql("homestarrunner")
     end
 
     context "when new_resource is Package" do
-      let(:new_resource) { Chef::Resource::Package.new('emacs') }
+      let(:new_resource) { Chef::Resource::Package.new("emacs") }
 
       it "does not try to read homebrew_user from Package, which does not have it" do
-        allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => 'zombo'))
-        expect(provider.brew).to eql('zombo')
+        allow(provider).to receive(:shell_out!).and_return(OpenStruct.new(:stdout => "zombo"))
+        expect(provider.brew).to eql("zombo")
       end
     end
   end
 
-  context 'when testing actions' do
+  context "when testing actions" do
     before(:each) do
       provider.current_resource = current_resource
     end
 
-    describe 'install_package' do
+    describe "install_package" do
       before(:each) do
-        allow(provider).to receive(:candidate_version).and_return('24.3')
+        allow(provider).to receive(:candidate_version).and_return("24.3")
       end
 
-      it 'installs the named package with brew install' do
-        allow(provider.new_resource).to receive(:version).and_return('24.3')
+      it "installs the named package with brew install" do
+        allow(provider.new_resource).to receive(:version).and_return("24.3")
         allow(provider.current_resource).to receive(:version).and_return(nil)
         allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
-        expect(provider).to receive(:get_response_from_command).with('brew install  emacs')
-        provider.install_package('emacs', '24.3')
+        expect(provider).to receive(:get_response_from_command).with("brew install  emacs")
+        provider.install_package("emacs", "24.3")
       end
 
-      it 'does not do anything if the package is installed' do
-        allow(provider.current_resource).to receive(:version).and_return('24.3')
+      it "does not do anything if the package is installed" do
+        allow(provider.current_resource).to receive(:version).and_return("24.3")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
         expect(provider).not_to receive(:get_response_from_command)
-        provider.install_package('emacs', '24.3')
+        provider.install_package("emacs", "24.3")
       end
 
-      it 'uses options to the brew command if specified' do
-        allow(provider.new_resource).to receive(:options).and_return('--cocoa')
-        allow(provider.current_resource).to receive(:version).and_return('24.3')
-        allow(provider).to receive(:get_response_from_command).with('brew install --cocoa emacs')
-        provider.install_package('emacs', '24.3')
+      it "uses options to the brew command if specified" do
+        allow(provider.new_resource).to receive(:options).and_return("--cocoa")
+        allow(provider.current_resource).to receive(:version).and_return("24.3")
+        allow(provider).to receive(:get_response_from_command).with("brew install --cocoa emacs")
+        provider.install_package("emacs", "24.3")
       end
     end
 
-    describe 'upgrade_package' do
-      it 'uses brew upgrade to upgrade the package if it is installed' do
-        allow(provider.current_resource).to receive(:version).and_return('24')
+    describe "upgrade_package" do
+      it "uses brew upgrade to upgrade the package if it is installed" do
+        allow(provider.current_resource).to receive(:version).and_return("24")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
-        expect(provider).to receive(:get_response_from_command).with('brew upgrade  emacs')
-        provider.upgrade_package('emacs', '24.3')
+        expect(provider).to receive(:get_response_from_command).with("brew upgrade  emacs")
+        provider.upgrade_package("emacs", "24.3")
       end
 
-      it 'does not do anything if the package version is already installed' do
-        allow(provider.current_resource).to receive(:version).and_return('24.3')
+      it "does not do anything if the package version is already installed" do
+        allow(provider.current_resource).to receive(:version).and_return("24.3")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
         expect(provider).not_to receive(:get_response_from_command)
-        provider.install_package('emacs', '24.3')
+        provider.install_package("emacs", "24.3")
       end
 
-      it 'uses brew install to install the package if it is not installed' do
+      it "uses brew install to install the package if it is not installed" do
         allow(provider.current_resource).to receive(:version).and_return(nil)
         allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
-        expect(provider).to receive(:get_response_from_command).with('brew install  emacs')
-        provider.upgrade_package('emacs', '24.3')
+        expect(provider).to receive(:get_response_from_command).with("brew install  emacs")
+        provider.upgrade_package("emacs", "24.3")
       end
 
-      it 'uses options to the brew command if specified' do
-        allow(provider.current_resource).to receive(:version).and_return('24')
+      it "uses options to the brew command if specified" do
+        allow(provider.current_resource).to receive(:version).and_return("24")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
-        allow(provider.new_resource).to receive(:options).and_return('--cocoa')
-        expect(provider).to receive(:get_response_from_command).with('brew upgrade --cocoa emacs')
-        provider.upgrade_package('emacs', '24.3')
+        allow(provider.new_resource).to receive(:options).and_return("--cocoa")
+        expect(provider).to receive(:get_response_from_command).with("brew upgrade --cocoa emacs")
+        provider.upgrade_package("emacs", "24.3")
       end
     end
 
-    describe 'remove_package' do
-      it 'uninstalls the package with brew uninstall' do
-        allow(provider.current_resource).to receive(:version).and_return('24.3')
+    describe "remove_package" do
+      it "uninstalls the package with brew uninstall" do
+        allow(provider.current_resource).to receive(:version).and_return("24.3")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
-        expect(provider).to receive(:get_response_from_command).with('brew uninstall  emacs')
-        provider.remove_package('emacs', '24.3')
+        expect(provider).to receive(:get_response_from_command).with("brew uninstall  emacs")
+        provider.remove_package("emacs", "24.3")
       end
 
-      it 'does not do anything if the package is not installed' do
+      it "does not do anything if the package is not installed" do
         allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
         expect(provider).not_to receive(:get_response_from_command)
-        provider.remove_package('emacs', '24.3')
+        provider.remove_package("emacs", "24.3")
       end
     end
 
-    describe 'purge_package' do
-      it 'uninstalls the package with brew uninstall --force' do
-        allow(provider.current_resource).to receive(:version).and_return('24.3')
+    describe "purge_package" do
+      it "uninstalls the package with brew uninstall --force" do
+        allow(provider.current_resource).to receive(:version).and_return("24.3")
         allow(provider).to receive(:brew_info).and_return(installed_brew_info)
-        expect(provider).to receive(:get_response_from_command).with('brew uninstall  --force emacs')
-        provider.purge_package('emacs', '24.3')
+        expect(provider).to receive(:get_response_from_command).with("brew uninstall  --force emacs")
+        provider.purge_package("emacs", "24.3")
       end
 
-      it 'does not do anything if the package is not installed' do
+      it "does not do anything if the package is not installed" do
         allow(provider).to receive(:brew_info).and_return(uninstalled_brew_info)
         expect(provider).not_to receive(:get_response_from_command)
-        provider.purge_package('emacs', '24.3')
+        provider.purge_package("emacs", "24.3")
       end
     end
   end
diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb
index 342ac4c..f47385d 100644
--- a/spec/unit/provider/package/ips_spec.rb
+++ b/spec/unit/provider/package/ips_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Bryan McLellan <btm at opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm at chef.io>
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 # based on the apt specs
 
@@ -34,18 +34,17 @@ describe Chef::Provider::Package::Ips do
 
   def local_output
     stdin  = StringIO.new
-    stdout = ''
-    stderr =<<-PKG_STATUS
+    stdout = ""
+    stderr = <<-PKG_STATUS
 pkg: info: no packages matching the following patterns you specified are
 installed on the system.  Try specifying -r to query remotely:
 
    crypto/gnupg
 PKG_STATUS
-    return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 1)
+    return OpenStruct.new(:stdout => stdout, :stdin => stdin, :stderr => stderr, :status => @status, :exitstatus => 1)
   end
 
   def remote_output
-
     stdout = <<-PKG_STATUS
           Name: security/sudo
        Summary: sudo - authority delegation tool
@@ -58,35 +57,35 @@ Packaging Date: April  1, 2012 05:55:52 PM
           Size: 2.57 MB
           FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
 PKG_STATUS
-  stdin = StringIO.new
-  stderr = ''
-  return OpenStruct.new(:stdout => stdout,:stdin => stdin,:stderr => stderr,:status => @status,:exitstatus => 0)
+    stdin = StringIO.new
+    stderr = ""
+    return OpenStruct.new(:stdout => stdout, :stdin => stdin, :stderr => stderr, :status => @status, :exitstatus => 0)
   end
 
   context "when loading current resource" do
     it "should create a current resource with the name of the new_resource" do
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
       @provider.load_current_resource
     end
 
     it "should set the current resources package name to the new resources package name" do
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       @provider.load_current_resource
       expect(@current_resource.package_name).to eq(@new_resource.package_name)
     end
 
     it "should run pkg info with the package name" do
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       @provider.load_current_resource
     end
 
     it "should set the installed version to nil on the current resource if package state is not installed" do
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       @provider.load_current_resource
       expect(@current_resource.version).to be_nil
     end
@@ -108,27 +107,27 @@ Packaging Date: October 19, 2011 09:14:50 AM
           Size: 8.07 MB
           FMRI: pkg://solaris/crypto/gnupg@2.0.17,5.11-0.175.0.0.0.2.537:20111019T091450Z
 INSTALLED
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       @provider.load_current_resource
       expect(@current_resource.version).to eq("2.0.17")
     end
 
     it "should return the current resource" do
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote_output)
       expect(@provider.load_current_resource).to eql(@current_resource)
     end
   end
 
   context "when installing a package" do
     it "should run pkg install with the package name and version" do
-      expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg at 2.0.17")
+      expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg at 2.0.17", timeout: 900)
       @provider.install_package("crypto/gnupg", "2.0.17")
     end
 
     it "should run pkg install with the package name and version and options if specified" do
-      expect(@provider).to receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg at 2.0.17")
+      expect(@provider).to receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg at 2.0.17", timeout: 900)
       allow(@new_resource).to receive(:options).and_return("--no-refresh")
       @provider.install_package("crypto/gnupg", "2.0.17")
     end
@@ -147,8 +146,8 @@ Packaging Date: April  1, 2012 05:55:52 PM
           Size: 2.57 MB
           FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z
 PKG_STATUS
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local_output)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
       @provider.load_current_resource
       expect(@current_resource.version).to be_nil
       expect(@provider.candidate_version).to eql("1.8.4.1")
@@ -188,8 +187,8 @@ Packaging Date: October 19, 2011 09:14:50 AM
           FMRI: pkg://solaris/crypto/gnupg@2.0.18,5.11-0.175.0.0.0.2.537:20111019T091450Z
 REMOTE
 
-      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local)
-      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote)
+      expect(@provider).to receive(:shell_out).with("pkg info #{@new_resource.package_name}", timeout: 900).and_return(local)
+      expect(@provider).to receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}", timeout: 900).and_return(remote)
       expect(@provider).to receive(:install_package).exactly(0).times
       @provider.run_action(:install)
     end
@@ -200,7 +199,7 @@ REMOTE
       end
 
       it "should run pkg install with the --accept flag" do
-        expect(@provider).to receive(:shell_out).with("pkg install -q --accept crypto/gnupg at 2.0.17")
+        expect(@provider).to receive(:shell_out).with("pkg install -q --accept crypto/gnupg at 2.0.17", timeout: 900)
         @provider.install_package("crypto/gnupg", "2.0.17")
       end
     end
@@ -208,19 +207,19 @@ REMOTE
 
   context "when upgrading a package" do
     it "should run pkg install with the package name and version" do
-      expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg at 2.0.17")
+      expect(@provider).to receive(:shell_out).with("pkg install -q crypto/gnupg at 2.0.17", timeout: 900)
       @provider.upgrade_package("crypto/gnupg", "2.0.17")
     end
   end
 
   context "when uninstalling a package" do
     it "should run pkg uninstall with the package name and version" do
-      expect(@provider).to receive(:shell_out!).with("pkg uninstall -q crypto/gnupg at 2.0.17")
+      expect(@provider).to receive(:shell_out!).with("pkg uninstall -q crypto/gnupg at 2.0.17", timeout: 900)
       @provider.remove_package("crypto/gnupg", "2.0.17")
     end
 
     it "should run pkg uninstall with the package name and version and options if specified" do
-      expect(@provider).to receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg at 2.0.17")
+      expect(@provider).to receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg at 2.0.17", timeout: 900)
       allow(@new_resource).to receive(:options).and_return("--no-refresh")
       @provider.remove_package("crypto/gnupg", "2.0.17")
     end
diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb
index 9822fb3..b90cf89 100644
--- a/spec/unit/provider/package/macports_spec.rb
+++ b/spec/unit/provider/package/macports_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: David Balatero (<dbalatero at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Macports do
   before(:each) do
@@ -70,7 +70,7 @@ describe Chef::Provider::Package::Macports do
 
   describe "current_installed_version" do
     it "should return the current version if the package is installed" do
-      stdout =  <<EOF
+      stdout = <<EOF
 The following ports are currently installed:
   openssl @0.9.8k_0 (active)
 EOF
@@ -105,7 +105,7 @@ EOF
     it "should run the port install command with the correct version" do
       expect(@current_resource).to receive(:version).and_return("4.1.6")
       @provider.current_resource = @current_resource
-      expect(@provider).to receive(:shell_out!).with("port install zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port install zsh @4.2.7", timeout: 900)
 
       @provider.install_package("zsh", "4.2.7")
     end
@@ -122,7 +122,7 @@ EOF
       expect(@current_resource).to receive(:version).and_return("4.1.6")
       @provider.current_resource = @current_resource
       allow(@new_resource).to receive(:options).and_return("-f")
-      expect(@provider).to receive(:shell_out!).with("port -f install zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port -f install zsh @4.2.7", timeout: 900)
 
       @provider.install_package("zsh", "4.2.7")
     end
@@ -130,36 +130,36 @@ EOF
 
   describe "purge_package" do
     it "should run the port uninstall command with the correct version" do
-      expect(@provider).to receive(:shell_out!).with("port uninstall zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port uninstall zsh @4.2.7", timeout: 900)
       @provider.purge_package("zsh", "4.2.7")
     end
 
     it "should purge the currently active version if no explicit version is passed in" do
-      expect(@provider).to receive(:shell_out!).with("port uninstall zsh")
+      expect(@provider).to receive(:shell_out!).with("port uninstall zsh", timeout: 900)
       @provider.purge_package("zsh", nil)
     end
 
     it "should add options to the port command when specified" do
       allow(@new_resource).to receive(:options).and_return("-f")
-      expect(@provider).to receive(:shell_out!).with("port -f uninstall zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port -f uninstall zsh @4.2.7", timeout: 900)
       @provider.purge_package("zsh", "4.2.7")
     end
   end
 
   describe "remove_package" do
     it "should run the port deactivate command with the correct version" do
-      expect(@provider).to receive(:shell_out!).with("port deactivate zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port deactivate zsh @4.2.7", timeout: 900)
       @provider.remove_package("zsh", "4.2.7")
     end
 
     it "should remove the currently active version if no explicit version is passed in" do
-      expect(@provider).to receive(:shell_out!).with("port deactivate zsh")
+      expect(@provider).to receive(:shell_out!).with("port deactivate zsh", timeout: 900)
       @provider.remove_package("zsh", nil)
     end
 
     it "should add options to the port command when specified" do
       allow(@new_resource).to receive(:options).and_return("-f")
-      expect(@provider).to receive(:shell_out!).with("port -f deactivate zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port -f deactivate zsh @4.2.7", timeout: 900)
       @provider.remove_package("zsh", "4.2.7")
     end
   end
@@ -169,7 +169,7 @@ EOF
       expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
       @provider.current_resource = @current_resource
 
-      expect(@provider).to receive(:shell_out!).with("port upgrade zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port upgrade zsh @4.2.7", timeout: 900)
 
       @provider.upgrade_package("zsh", "4.2.7")
     end
@@ -195,7 +195,7 @@ EOF
       expect(@current_resource).to receive(:version).at_least(:once).and_return("4.1.6")
       @provider.current_resource = @current_resource
 
-      expect(@provider).to receive(:shell_out!).with("port -f upgrade zsh @4.2.7")
+      expect(@provider).to receive(:shell_out!).with("port -f upgrade zsh @4.2.7", timeout: 900)
 
       @provider.upgrade_package("zsh", "4.2.7")
     end
diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb
index b0cdb99..3e1c1c9 100644
--- a/spec/unit/provider/package/openbsd_spec.rb
+++ b/spec/unit/provider/package/openbsd_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Scott Bonds (scott at ggr.com)
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2014-2016, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Openbsd do
 
   let(:node) do
     node = Chef::Node.new
-    node.default['kernel'] = {'name' => 'OpenBSD', 'release' => '5.5', 'machine' => 'amd64'}
+    node.default["kernel"] = { "name" => "OpenBSD", "release" => "5.5", "machine" => "amd64" }
     node
   end
 
@@ -33,100 +33,79 @@ describe Chef::Provider::Package::Openbsd do
     Chef::Provider::Package::Openbsd.new(new_resource, run_context)
   end
 
-  let(:new_resource) { Chef::Resource::Package.new(name)}
+  let(:new_resource) { Chef::Resource::Package.new(name) }
 
   before(:each) do
-    ENV['PKG_PATH'] = nil
+    ENV["PKG_PATH"] = nil
   end
 
   describe "install a package" do
-    let(:name) { 'ihavetoes' }
-    let(:version) {'0.0'}
+    let(:name) { "ihavetoes" }
+    let(:version) { "0.0" }
 
-    context 'when not already installed' do
+    context "when not already installed" do
       before do
-        allow(provider).to receive(:shell_out!).with("pkg_info -e \"#{name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
+        allow(provider).to receive(:shell_out!).with("pkg_info -e \"#{name}->0\"", anything()).and_return(instance_double("shellout", :stdout => ""))
       end
 
-      context 'when there is a single candidate' do
+      context "when there is a single candidate" do
 
-        context 'when installing from source' do
-          it 'should run the installation command' do
-            pending('Installing from source is not supported yet')
-            # This is a consequence of load_current_resource being called before define_resource_requirements
-            # It can be deleted once an implementation is provided
-            allow(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
-              instance_double('shellout', :stdout => "#{name}-#{version}\n"))
-            new_resource.source('/some/path/on/disk.tgz')
-            provider.run_action(:install)
-          end
-        end
-
-        context 'when source is not provided' do
-          it 'should run the installation command' do
+        context "when source is not provided" do
+          it "should run the installation command" do
             expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
-              instance_double('shellout', :stdout => "#{name}-#{version}\n"))
+              instance_double("shellout", :stdout => "#{name}-#{version}\n"))
             expect(provider).to receive(:shell_out!).with(
               "pkg_add -r #{name}-#{version}",
-              {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
-            ) {OpenStruct.new :status => true}
+              { :env => { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+            ) { OpenStruct.new :status => true }
             provider.run_action(:install)
           end
         end
       end
 
-      context 'when there are multiple candidates' do
-        let(:flavor_a) { 'flavora' }
-        let(:flavor_b) { 'flavorb' }
+      context "when there are multiple candidates" do
+        let(:flavor_a) { "flavora" }
+        let(:flavor_b) { "flavorb" }
 
-        context 'if no version is specified' do
-          it 'should raise an exception' do
+        context "if no version is specified" do
+          it "should raise an exception" do
             expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
-              instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n#{name}-#{version}-#{flavor_b}\n"))
+              instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor_a}\n#{name}-#{version}-#{flavor_b}\n"))
             expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package, /multiple matching candidates/)
           end
         end
 
-        context 'if a flavor is specified' do
+        context "if a flavor is specified" do
 
-          let(:flavor) { 'flavora' }
-          let(:package_name) {'ihavetoes' }
+          let(:flavor) { "flavora" }
+          let(:package_name) { "ihavetoes" }
           let(:name) { "#{package_name}--#{flavor}" }
 
-          context 'if no version is specified' do
-            it 'should run the installation command' do
-              expect(provider).to receive(:shell_out!).with("pkg_info -e \"#{package_name}->0\"", anything()).and_return(instance_double('shellout', :stdout => ''))
+          context "if no version is specified" do
+            it "should run the installation command" do
+              expect(provider).to receive(:shell_out!).with("pkg_info -e \"#{package_name}->0\"", anything()).and_return(instance_double("shellout", :stdout => ""))
               expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}\"", anything()).and_return(
-                instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor}\n"))
+                instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor}\n"))
               expect(provider).to receive(:shell_out!).with(
                 "pkg_add -r #{name}-#{version}-#{flavor}",
-                {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
-              ) {OpenStruct.new :status => true}
+                { env: { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+              ) { OpenStruct.new :status => true }
               provider.run_action(:install)
             end
           end
 
-          context 'if a version is specified' do
-            it 'runs the installation command' do
-              pending('Specifying both a version and flavor is not supported')
-              new_resource.version(version)
-              allow(provider).to receive(:shell_out!).with(/pkg_info -e/, anything()).and_return(instance_double('shellout', :stdout => ''))
-              allow(provider).to receive(:candidate_version).and_return("#{package_name}-#{version}-#{flavor}")
-              provider.run_action(:install)
-            end
-          end
         end
 
-        context 'if a version is specified' do
-          it 'should use the flavor from the version' do
+        context "if a version is specified" do
+          it "should use the flavor from the version" do
             expect(provider).to receive(:shell_out!).with("pkg_info -I \"#{name}-#{version}-#{flavor_b}\"", anything()).and_return(
-              instance_double('shellout', :stdout => "#{name}-#{version}-#{flavor_a}\n"))
+              instance_double("shellout", :stdout => "#{name}-#{version}-#{flavor_a}\n"))
 
             new_resource.version("#{version}-#{flavor_b}")
             expect(provider).to receive(:shell_out!).with(
               "pkg_add -r #{name}-#{version}-#{flavor_b}",
-              {:env => {"PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/"}}
-            ) {OpenStruct.new :status => true}
+              { env: { "PKG_PATH" => "http://ftp.OpenBSD.org/pub/OpenBSD/5.5/packages/amd64/" }, timeout: 900 }
+            ) { OpenStruct.new :status => true }
             provider.run_action(:install)
           end
         end
@@ -136,7 +115,7 @@ describe Chef::Provider::Package::Openbsd do
 
   describe "delete a package" do
     before do
-      @name = 'ihavetoes'
+      @name = "ihavetoes"
       @new_resource     = Chef::Resource::Package.new(@name)
       @current_resource = Chef::Resource::Package.new(@name)
       @provider = Chef::Provider::Package::Openbsd.new(@new_resource, @run_context)
@@ -144,11 +123,10 @@ describe Chef::Provider::Package::Openbsd do
     end
     it "should run the command to delete the installed package" do
       expect(@provider).to receive(:shell_out!).with(
-        "pkg_delete #{@name}", :env=>nil
-      ) {OpenStruct.new :status => true}
+        "pkg_delete #{@name}", env: nil, timeout: 900
+      ) { OpenStruct.new :status => true }
       @provider.remove_package(@name, nil)
     end
   end
 
 end
-
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index 3b8848c..ce9107f 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Pacman do
   before(:each) do
@@ -51,7 +51,7 @@ ERR
     end
 
     it "should run pacman query with the package name" do
-      expect(@provider).to receive(:shell_out).with("pacman -Qi #{@new_resource.package_name}").and_return(@status)
+      expect(@provider).to receive(:shell_out).with("pacman -Qi #{@new_resource.package_name}", { timeout: 900 }).and_return(@status)
       @provider.load_current_resource
     end
 
@@ -62,7 +62,6 @@ ERR
 
     it "should set the installed version to nil on the current resource if pacman installed version not exists" do
       allow(@provider).to receive(:shell_out).and_return(@status)
-      expect(@current_resource).to receive(:version).with(nil).and_return(true)
       @provider.load_current_resource
     end
 
@@ -103,7 +102,7 @@ PACMAN
     end
 
     it "should use pacman.conf to determine valid repo names for package versions" do
-     @pacman_conf = <<-PACMAN_CONF
+      @pacman_conf = <<-PACMAN_CONF
 [options]
 HoldPkg      = pacman glibc
 Architecture = auto
@@ -152,12 +151,12 @@ PACMAN_CONF
 
   describe Chef::Provider::Package::Pacman, "install_package" do
     it "should run pacman install with the package name and version" do
-      expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano")
+      expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano", { timeout: 900 })
       @provider.install_package("nano", "1.0")
     end
 
     it "should run pacman install with the package name and version and options if specified" do
-      expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano")
+      expect(@provider).to receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano", { timeout: 900 })
       allow(@new_resource).to receive(:options).and_return("--debug")
 
       @provider.install_package("nano", "1.0")
@@ -173,12 +172,12 @@ PACMAN_CONF
 
   describe Chef::Provider::Package::Pacman, "remove_package" do
     it "should run pacman remove with the package name" do
-      expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano")
+      expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano", { timeout: 900 })
       @provider.remove_package("nano", "1.0")
     end
 
     it "should run pacman remove with the package name and options if specified" do
-      expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano")
+      expect(@provider).to receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano", { timeout: 900 })
       allow(@new_resource).to receive(:options).and_return("--debug")
 
       @provider.remove_package("nano", "1.0")
diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb
index 4ed5dfc..b984aeb 100644
--- a/spec/unit/provider/package/paludis_spec.rb
+++ b/spec/unit/provider/package/paludis_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Vasiliy Tolstov <v.tolstov at selfip.ru>
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 # based on the ips specs
 
@@ -33,7 +33,7 @@ describe Chef::Provider::Package::Paludis do
 
     @stdin = StringIO.new
     @stderr = StringIO.new
-    @stdout =<<-PKG_STATUS
+    @stdout = <<-PKG_STATUS
 group/ntp 0 accounts
 group/ntp 0 installed-accounts
 net/ntp 4.2.6_p5-r2 arbor
@@ -42,7 +42,7 @@ user/ntp 0 installed-accounts
 net/ntp 4.2.6_p5-r1 installed
 PKG_STATUS
     @pid = 12345
-    @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0)
+    @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
   end
 
   context "when loading current resource" do
@@ -86,13 +86,12 @@ INSTALLED
 
   context "when installing a package" do
     it "should run pkg install with the package name and version" do
-      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
+      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", { :timeout => @new_resource.timeout })
       @provider.install_package("net/ntp", "4.2.6_p5-r2")
     end
 
-
     it "should run pkg install with the package name and version and options if specified" do
-      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
+      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"", { :timeout => @new_resource.timeout })
       allow(@new_resource).to receive(:options).and_return("--preserve-world")
       @provider.install_package("net/ntp", "4.2.6_p5-r2")
     end
@@ -102,7 +101,7 @@ INSTALLED
 sys-process/lsof 4.87 arbor
 sys-process/lsof 4.87 x86_64
 PKG_STATUS
-      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=sys-process/lsof-4.87\"", {:timeout=>@new_resource.timeout})
+      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=sys-process/lsof-4.87\"", { :timeout => @new_resource.timeout })
       @provider.install_package("sys-process/lsof", "4.87")
     end
 
@@ -120,7 +119,7 @@ PKG_STATUS
 
   context "when upgrading a package" do
     it "should run pkg install with the package name and version" do
-      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout})
+      expect(@provider).to receive(:shell_out!).with("cave -L warning resolve -x \"=net/ntp-4.2.6_p5-r2\"", { :timeout => @new_resource.timeout })
       @provider.upgrade_package("net/ntp", "4.2.6_p5-r2")
     end
   end
diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb
index 55743db..c2ff1cc 100644
--- a/spec/unit/provider/package/portage_spec.rb
+++ b/spec/unit/provider/package/portage_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Caleb Tennis (<caleb.tennis at gmail.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Portage, "load_current_resource" do
   before(:each) do
diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb
index 411afd3..1d179ed 100644
--- a/spec/unit/provider/package/rpm_spec.rb
+++ b/spec/unit/provider/package/rpm_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,190 +16,414 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Rpm do
   let(:provider) { Chef::Provider::Package::Rpm.new(new_resource, run_context) }
   let(:node) { Chef::Node.new }
   let(:events) { Chef::EventDispatch::Dispatcher.new }
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
+
+  let(:package_source) { "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+  let(:package_name) { "ImageMagick-c++" }
+
   let(:new_resource) do
-    Chef::Resource::Package.new("ImageMagick-c++").tap do |resource|
-      resource.source "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
+    Chef::Resource::Package.new(package_name).tap do |resource|
+      resource.source(package_source)
     end
   end
-  let(:exitstatus) { 0 }
-  let(:stdout) { String.new('') }
-  let(:status) { double('Process::Status', exitstatus: exitstatus, stdout: stdout) }
+
+  # `rpm -qp [stuff] $source`
+  let(:rpm_qp_status) { instance_double("Mixlib::ShellOut", exitstatus: rpm_qp_exitstatus, stdout: rpm_qp_stdout) }
+
+  # `rpm -q [stuff] $package_name`
+  let(:rpm_q_status) { instance_double("Mixlib::ShellOut", exitstatus: rpm_q_exitstatus, stdout: rpm_q_stdout) }
 
   before(:each) do
-    allow(::File).to receive(:exists?).and_return(true)
-    allow(provider).to receive(:shell_out!).and_return(status)
+    allow(::File).to receive(:exists?).with("PLEASE STUB File.exists? EXACTLY").and_return(true)
+
+    # Ensure all shell out usage is stubbed with exact arguments
+    allow(provider).to receive(:shell_out!).with("PLEASE STUB YOUR SHELLOUT CALLS").and_return(nil)
+    allow(provider).to receive(:shell_out).with("PLEASE STUB YOUR SHELLOUT CALLS").and_return(nil)
   end
 
-  describe "when determining the current state of the package" do
-    it "should create a current resource with the name of new_resource" do
-      provider.load_current_resource
-      expect(provider.current_resource.name).to eq("ImageMagick-c++")
-    end
+  describe "when the package source is not valid" do
 
-    it "should set the current reource package name to the new resource package name" do
-      provider.load_current_resource
-      expect(provider.current_resource.package_name).to eq('ImageMagick-c++')
-    end
+    context "when source is not defiend" do
+      let(:new_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
 
-    it "should raise an exception if a source is supplied but not found" do
-      allow(::File).to receive(:exists?).and_return(false)
-      expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+      it "should raise an exception when attempting any action" do
+        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+      end
     end
 
-    context "installation exists" do
-      let(:stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+    context "when the source is a file that doesn't exist" do
 
-      it "should get the source package version from rpm if provided" do
-        expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status)
-        expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status)
-        provider.load_current_resource
-        expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
-        expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+      it "should raise an exception when attempting any action" do
+        allow(::File).to receive(:exists?).with(package_source).and_return(false)
+        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
       end
+    end
 
-      it "should return the current version installed if found by rpm" do
-        expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(status)
-        expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(status)
-        provider.load_current_resource
-        expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+    context "when the source is an unsupported URI scheme" do
+
+      let(:package_source) { "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+      it "should raise an exception if an uri formed source is non-supported scheme" do
+        allow(::File).to receive(:exists?).with(package_source).and_return(false)
+
+        # verify let bindings are as we expect
+        expect(new_resource.source).to eq("foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+        expect(provider.load_current_resource).to be_nil
+        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
       end
     end
 
-    context "source is uri formed" do
-      before(:each) do
-        allow(::File).to receive(:exists?).and_return(false)
+  end
+
+  describe "when the package source is valid" do
+
+    before do
+      expect(provider).to receive(:shell_out!).
+        with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_source}", timeout: 900).
+        and_return(rpm_qp_status)
+
+      expect(provider).to receive(:shell_out).
+        with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{package_name}", timeout: 900).
+        and_return(rpm_q_status)
+    end
+
+    context "when rpm fails when querying package installed state" do
+
+      before do
+        allow(::File).to receive(:exists?).with(package_source).and_return(true)
       end
 
-      %w(http HTTP https HTTPS ftp FTP).each do |scheme|
-        it "should accept uri formed source (#{scheme})" do
-          new_resource.source "#{scheme}://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
-          expect(provider.load_current_resource).not_to be_nil
+      let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+      let(:rpm_q_stdout) { "" }
+
+      let(:rpm_qp_exitstatus) { 0 }
+      let(:rpm_q_exitstatus) { -1 }
+
+      it "raises an exception when attempting any action" do
+        expected_message = "Unable to determine current version due to RPM failure."
+
+        expect { provider.run_action(:install) }.to raise_error do |error|
+          expect(error).to be_a_kind_of(Chef::Exceptions::Package)
+          expect(error.to_s).to include(expected_message)
         end
       end
+    end
+
+    context "when the package is installed" do
+
+      let(:rpm_qp_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+      let(:rpm_q_stdout) { "ImageMagick-c++ 6.5.4.7-7.el6_5" }
+
+      let(:rpm_qp_exitstatus) { 0 }
+      let(:rpm_q_exitstatus) { 0 }
+
+      let(:action) { :install }
+
+      context "when the source is a file system path" do
 
-      %w(file FILE).each do |scheme|
-        it "should accept uri formed source (#{scheme})" do
-          new_resource.source "#{scheme}:///ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
-          expect(provider.load_current_resource).not_to be_nil
+        before do
+          allow(::File).to receive(:exists?).with(package_source).and_return(true)
+
+          provider.action = action
+
+          provider.load_current_resource
+          provider.define_resource_requirements
+          provider.process_resource_requirements
         end
-      end
 
-      it "should raise an exception if an uri formed source is non-supported scheme" do
-        new_resource.source "foobar://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm"
-        expect(provider.load_current_resource).to be_nil
-        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
-      end
-    end
+        it "should get the source package version from rpm if provided" do
+          expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
+          expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+        end
 
-    context "source is not defiend" do
-      let(:new_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+        it "should return the current version installed if found by rpm" do
+          expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+        end
+
+        describe "action install" do
+
+          context "when at the desired version already" do
+            it "does nothing when the correct version is installed" do
+              expect(provider).to_not receive(:shell_out!).with("rpm  -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+
+              provider.action_install
+            end
+          end
+
+          context "when a newer version is desired" do
+
+            let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
+
+            it "runs rpm -u with the package source to upgrade" do
+              expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+              provider.action_install
+            end
+          end
+
+          context "when an older version is desired" do
+            let(:new_resource) do
+              Chef::Resource::RpmPackage.new(package_name).tap do |r|
+                r.source(package_source)
+                r.allow_downgrade(true)
+              end
+            end
+
+            let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
+
+            it "should run rpm -u --oldpackage with the package source to downgrade" do
+              expect(provider).to receive(:shell_out!).with("rpm  -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+              provider.action_install
+            end
+
+          end
+
+        end
+
+        describe "action upgrade" do
+
+          let(:action) { :upgrade }
+
+          context "when at the desired version already" do
+            it "does nothing when the correct version is installed" do
+              expect(provider).to_not receive(:shell_out!).with("rpm  -i /tmp/imagemagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+
+              provider.action_upgrade
+            end
+          end
+
+          context "when a newer version is desired" do
+
+            let(:rpm_q_stdout) { "imagemagick-c++ 0.5.4.7-7.el6_5" }
+
+            it "runs rpm -u with the package source to upgrade" do
+              expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+              provider.action_upgrade
+            end
+          end
+
+          context "when an older version is desired" do
+            let(:new_resource) do
+              Chef::Resource::RpmPackage.new(package_name).tap do |r|
+                r.source(package_source)
+                r.allow_downgrade(true)
+              end
+            end
+
+            let(:rpm_q_stdout) { "imagemagick-c++ 21.4-19.el6_5" }
+
+            it "should run rpm -u --oldpackage with the package source to downgrade" do
+              expect(provider).to receive(:shell_out!).with("rpm  -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+              provider.action_upgrade
+            end
+
+          end
+        end
+
+        describe "action :remove" do
+
+          let(:action) { :remove }
+
+          it "should remove the package" do
+            expect(provider).to receive(:shell_out!).with("rpm  -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+            provider.action_remove
+          end
+        end
+
+        context "when the package name contains a tilde (chef#3503)" do
+
+          let(:package_name) { "supermarket" }
+
+          let(:package_source) { "/tmp/supermarket-1.10.1~alpha.0-1.el5.x86_64.rpm" }
+
+          let(:rpm_qp_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+          let(:rpm_q_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+
+          let(:rpm_qp_exitstatus) { 0 }
+          let(:rpm_q_exitstatus) { 0 }
+
+          it "should correctly determine the candidate version and installed version" do
+            expect(provider.current_resource.package_name).to eq("supermarket")
+            expect(provider.new_resource.version).to eq("1.10.1~alpha.0-1.el5")
+          end
+        end
+
+        context "when the package name contains a plus symbol (chef#3671)" do
+
+          let(:package_name) { "chef-server-core" }
+
+          let(:package_source) { "/tmp/chef-server-core-12.2.0+20150713220422-1.el6.x86_64.rpm" }
+
+          let(:rpm_qp_stdout) { "chef-server-core 12.2.0+20150713220422-1.el6" }
+          let(:rpm_q_stdout) { "chef-server-core 12.2.0+20150713220422-1.el6" }
+
+          let(:rpm_qp_exitstatus) { 0 }
+          let(:rpm_q_exitstatus) { 0 }
+
+          it "should correctly determine the candidate version and installed version" do
+            expect(provider.current_resource.package_name).to eq("chef-server-core")
+            expect(provider.new_resource.version).to eq("12.2.0+20150713220422-1.el6")
+          end
+        end
 
-      it "should raise an exception if the source is not set but we are installing" do
-        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
       end
-    end
 
-    context "installation does not exist" do
-      let(:stdout) { String.new("package openssh-askpass is not installed") }
-      let(:exitstatus) { -1 }
-      let(:new_resource) do
-        Chef::Resource::Package.new("openssh-askpass").tap do |resource|
-          resource.source "openssh-askpass"
+      context "when the source is given as an URI" do
+        before(:each) do
+          allow(::File).to receive(:exists?).with(package_source).and_return(false)
+
+          provider.action = action
+
+          provider.load_current_resource
+          provider.define_resource_requirements
+          provider.process_resource_requirements
+        end
+
+        %w{http HTTP https HTTPS ftp FTP file FILE}.each do |scheme|
+
+          context "when the source URI uses protocol scheme '#{scheme}'" do
+
+            let(:package_source) { "#{scheme}://example.com/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" }
+
+            it "should get the source package version from rpm if provided" do
+              expect(provider.current_resource.package_name).to eq("ImageMagick-c++")
+              expect(provider.new_resource.version).to eq("6.5.4.7-7.el6_5")
+            end
+
+            it "should return the current version installed if found by rpm" do
+              expect(provider.current_resource.version).to eq("6.5.4.7-7.el6_5")
+            end
+
+          end
         end
+
       end
 
-      it "should raise an exception if rpm fails to run" do
-        allow(provider).to receive(:shell_out).and_return(status)
-        expect { provider.run_action(:any) }.to raise_error(Chef::Exceptions::Package)
+    end
+
+    context "when the package is not installed" do
+
+      let(:package_name) { "openssh-askpass" }
+
+      let(:package_source) { "/tmp/openssh-askpass-1.2.3-4.el6_5.x86_64.rpm" }
+
+      let(:rpm_qp_stdout) { "openssh-askpass 1.2.3-4.el6_5" }
+      let(:rpm_q_stdout) { "package openssh-askpass is not installed" }
+
+      let(:rpm_qp_exitstatus) { 0 }
+      let(:rpm_q_exitstatus) { 0 }
+
+      let(:action) { :install }
+
+      before do
+        allow(File).to receive(:exists?).with(package_source).and_return(true)
+
+        provider.action = action
+
+        provider.load_current_resource
+        provider.define_resource_requirements
+        provider.process_resource_requirements
       end
 
       it "should not detect the package name as version when not installed" do
-        expect(provider).to receive(:shell_out!).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status)
-        expect(provider).to receive(:shell_out).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(status)
-        provider.load_current_resource
         expect(provider.current_resource.version).to be_nil
       end
-    end
-  end
 
-  describe "after the current resource is loaded" do
-    let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
-    let(:provider) do
-      Chef::Provider::Package::Rpm.new(new_resource, run_context).tap do |provider|
-        provider.current_resource = current_resource
-      end
-    end
+      context "when the package name contains a tilde (chef#3503)" do
 
-    describe "when installing or upgrading" do
-      it "should run rpm -i with the package source to install" do
-        expect(provider).to receive(:shell_out!).with("rpm  -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-        provider.install_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
-      end
+        let(:package_name) { "supermarket" }
 
-      it "should run rpm -U with the package source to upgrade" do
-        current_resource.version("21.4-19.el5")
-        expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-        provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
-      end
+        let(:package_source) { "/tmp/supermarket-1.10.1~alpha.0-1.el5.x86_64.rpm" }
 
-      it "should install package if missing and set to upgrade" do
-        current_resource.version("ImageMagick-c++")
-        expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-        provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
-      end
+        let(:rpm_qp_stdout) { "supermarket 1.10.1~alpha.0-1.el5" }
+        let(:rpm_q_stdout) { "package supermarket is not installed" }
 
-      context "allowing downgrade" do
-        let(:new_resource) { Chef::Resource::RpmPackage.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") }
-        let(:current_resource) { Chef::Resource::RpmPackage.new("ImageMagick-c++") }
+        let(:rpm_qp_exitstatus) { 0 }
+        let(:rpm_q_exitstatus) { 0 }
 
-        it "should run rpm -U --oldpackage with the package source to downgrade" do
-          new_resource.allow_downgrade(true)
-          current_resource.version("21.4-19.el5")
-          expect(provider).to receive(:shell_out!).with("rpm  -U --oldpackage /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-          provider.upgrade_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
+        it "should correctly determine the candidate version" do
+          expect(provider.new_resource.version).to eq("1.10.1~alpha.0-1.el5")
         end
       end
 
-      context "installing when the name is a path" do
-        let(:new_resource) { Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") }
-        let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+      describe "managing the package" do
+
+        describe "action install" do
+
+          it "installs the package" do
+            expect(provider).to receive(:shell_out!).with("rpm  -i #{package_source}", timeout: 900)
+
+            provider.action_install
+          end
+
+          context "when custom resource options are given" do
+            it "installs with custom options specified in the resource" do
+              new_resource.options("--dbpath /var/lib/rpm")
+              expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i #{package_source}", timeout: 900)
+              provider.action_install
+            end
+          end
+        end
+
+        describe "action upgrade" do
+
+          let(:action) { :upgrade }
 
-        it "should install from a path when the package is a path and the source is nil" do
-          expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-          provider.current_resource = current_resource
-          expect(provider).to receive(:shell_out!).with("rpm  -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-          provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+          it "installs the package" do
+            expect(provider).to receive(:shell_out!).with("rpm  -i #{package_source}", timeout: 900)
+
+            provider.action_upgrade
+          end
         end
 
-        it "should uprgrade from a path when the package is a path and the source is nil" do
-          expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-          current_resource.version("21.4-19.el5")
-          provider.current_resource = current_resource
-          expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-          provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+        describe "when removing the package" do
+
+          let(:action) { :remove }
+
+          it "should do nothing" do
+            expect(provider).to_not receive(:shell_out!).with("rpm  -e ImageMagick-c++-6.5.4.7-7.el6_5", timeout: 900)
+            provider.action_remove
+          end
         end
-      end
 
-      it "installs with custom options specified in the resource" do
-        provider.candidate_version = '11'
-        new_resource.options("--dbpath /var/lib/rpm")
-        expect(provider).to receive(:shell_out!).with("rpm --dbpath /var/lib/rpm -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
-        provider.install_package(new_resource.name, provider.candidate_version)
       end
+
+    end
+  end
+
+  context "when the resource name is the path to the package" do
+
+    let(:new_resource) do
+      # When we pass a source in as the name, then #initialize in the
+      # provider will call File.exists?. Because of the ordering in our
+      # let() bindings and such, we have to set the stub here and not in a
+      # before block.
+      allow(::File).to receive(:exists?).with(package_source).and_return(true)
+      Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
     end
 
-    describe "when removing the package" do
-      it "should run rpm -e to remove the package" do
-        expect(provider).to receive(:shell_out!).with("rpm  -e ImageMagick-c++-6.5.4.7-7.el6_5")
-        provider.remove_package("ImageMagick-c++", "6.5.4.7-7.el6_5")
-      end
+    let(:current_resource) { Chef::Resource::Package.new("ImageMagick-c++") }
+
+    it "should install from a path when the package is a path and the source is nil" do
+      expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+      provider.current_resource = current_resource
+      expect(provider).to receive(:shell_out!).with("rpm  -i /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+      provider.install_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
+    end
+
+    it "should uprgrade from a path when the package is a path and the source is nil" do
+      expect(new_resource.source).to eq("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm")
+      current_resource.version("21.4-19.el5")
+      provider.current_resource = current_resource
+      expect(provider).to receive(:shell_out!).with("rpm  -U /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", timeout: 900)
+      provider.upgrade_package("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm", "6.5.4.7-7.el6_5")
     end
   end
+
 end
diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb
index 3805724..141e2bd 100644
--- a/spec/unit/provider/package/rubygems_spec.rb
+++ b/spec/unit/provider/package/rubygems_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: David Balatero (dbalatero at gmail.com)
 #
-# Copyright:: Copyright (c) 2009 David Balatero
+# Copyright:: Copyright 2009-2016, David Balatero
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'pp'
+require "pp"
 
 module GemspecBackcompatCreator
   def gemspec(name, version)
@@ -28,8 +28,8 @@ module GemspecBackcompatCreator
   end
 end
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
   include GemspecBackcompatCreator
@@ -43,18 +43,18 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
   end
 
   it "determines the installed versions of gems from Gem.source_index" do
-    gems = [gemspec('rspec-core', Gem::Version.new('1.2.9')), gemspec('rspec-core', Gem::Version.new('1.3.0'))]
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
-      expect(Gem::Specification).to receive(:find_all_by_name).with('rspec-core', Gem::Dependency.new('rspec-core').requirement).and_return(gems)
+    gems = [gemspec("rspec-core", Gem::Version.new("1.2.9")), gemspec("rspec-core", Gem::Version.new("1.3.0"))]
+    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
+      expect(Gem::Specification).to receive(:find_all_by_name).with("rspec-core", Gem::Dependency.new("rspec-core").requirement).and_return(gems)
     else
-      expect(Gem.source_index).to receive(:search).with(Gem::Dependency.new('rspec-core', nil)).and_return(gems)
+      expect(Gem.source_index).to receive(:search).with(Gem::Dependency.new("rspec-core", nil)).and_return(gems)
     end
-    expect(@gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil))).to eq(gems)
+    expect(@gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil))).to eq(gems)
   end
 
   it "determines the installed versions of gems from the source index (part2: the unmockening)" do
-    expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)]
-    actual = @gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |spec| [spec.name, spec.version] }
+    expected = ["rspec-core", Gem::Version.new(RSpec::Core::Version::STRING)]
+    actual = @gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil)).map { |spec| [spec.name, spec.version] }
     expect(actual).to include(expected)
   end
 
@@ -87,16 +87,16 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
   end
 
   it "finds a matching gem candidate version" do
-    dep = Gem::Dependency.new('rspec', '>= 0')
+    dep = Gem::Dependency.new("rspec", ">= 0")
     dep_installer = Gem::DependencyInstaller.new
     allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
     latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "https://rubygems.org/"]]
     expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
-    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
+    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new("rspec", ">= 0"))).to eq(Gem::Version.new("1.3.0"))
   end
 
   it "finds a matching gem candidate version on rubygems 2.0.0+" do
-    dep = Gem::Dependency.new('rspec', '>= 0')
+    dep = Gem::Dependency.new("rspec", ">= 0")
     dep_installer = Gem::DependencyInstaller.new
     allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
     best_gem = double("best gem match", :spec => gemspec("rspec", Gem::Version.new("1.3.0")), :source => "https://rubygems.org")
@@ -104,94 +104,62 @@ describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do
     expect(available_set).to receive(:pick_best!)
     expect(available_set).to receive(:set).and_return([best_gem])
     expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(available_set)
-    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to eq(Gem::Version.new('1.3.0'))
-  end
-
-  context "when rubygems was upgraded from 1.8->2.0" do
-    # https://github.com/rubygems/rubygems/issues/404
-    # tl;dr rubygems 1.8 and 2.0 can both be in the load path, which means that
-    # require "rubygems/format" will load even though rubygems 2.0 doesn't have
-    # that file.
-
-    before do
-      if defined?(Gem::Format)
-        # tests are running under rubygems 1.8, or 2.0 upgraded from 1.8
-        @remove_gem_format = false
-      else
-        Gem.const_set(:Format, Object.new)
-        @remove_gem_format = true
-      end
-      allow(Gem::Package).to receive(:respond_to?).and_call_original
-      allow(Gem::Package).to receive(:respond_to?).with(:open).and_return(false)
-    end
-
-    after do
-      if @remove_gem_format
-        Gem.send(:remove_const, :Format)
-      end
-    end
-
-    it "finds a matching gem candidate version on rubygems 2.0+ with some rubygems 1.8 code loaded" do
-      package = double("Gem::Package", :spec => "a gemspec from package")
-      expect(Gem::Package).to receive(:new).with("/path/to/package.gem").and_return(package)
-      expect(@gem_env.spec_from_file("/path/to/package.gem")).to eq("a gemspec from package")
-    end
-
+    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new("rspec", ">= 0"))).to eq(Gem::Version.new("1.3.0"))
   end
 
   it "gives the candidate version as nil if none is found" do
-    dep = Gem::Dependency.new('rspec', '>= 0')
+    dep = Gem::Dependency.new("rspec", ">= 0")
     latest = []
     dep_installer = Gem::DependencyInstaller.new
     allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
     expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
-    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0'))).to be_nil
+    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new("rspec", ">= 0"))).to be_nil
   end
 
   it "finds a matching candidate version from a .gem file when the path to the gem is supplied" do
-    location = CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem'
-    expect(@gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0'), location)).to eq(Gem::Version.new('0.1.0'))
-    expect(@gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0.2.0'), location)).to be_nil
+    location = CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem"
+    expect(@gem_env.candidate_version_from_file(Gem::Dependency.new("chef-integration-test", ">= 0"), location)).to eq(Gem::Version.new("0.1.0"))
+    expect(@gem_env.candidate_version_from_file(Gem::Dependency.new("chef-integration-test", ">= 0.2.0"), location)).to be_nil
   end
 
   it "finds a matching gem from a specific gemserver when explicit sources are given" do
-    dep = Gem::Dependency.new('rspec', '>= 0')
+    dep = Gem::Dependency.new("rspec", ">= 0")
     latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "https://rubygems.org/"]]
 
-    expect(@gem_env).to receive(:with_gem_sources).with('http://gems.example.com').and_yield
+    expect(@gem_env).to receive(:with_gem_sources).with("http://gems.example.com").and_yield
     dep_installer = Gem::DependencyInstaller.new
     allow(@gem_env).to receive(:dependency_installer).and_return(dep_installer)
     expect(dep_installer).to receive(:find_gems_with_sources).with(dep).and_return(latest)
-    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>=0'), 'http://gems.example.com')).to eq(Gem::Version.new('1.3.0'))
+    expect(@gem_env.candidate_version_from_remote(Gem::Dependency.new("rspec", ">=0"), "http://gems.example.com")).to eq(Gem::Version.new("1.3.0"))
   end
 
   it "installs a gem with a hash of options for the dependency installer" do
     dep_installer = Gem::DependencyInstaller.new
-    expect(@gem_env).to receive(:dependency_installer).with(:install_dir => '/foo/bar').and_return(dep_installer)
-    expect(@gem_env).to receive(:with_gem_sources).with('http://gems.example.com').and_yield
-    expect(dep_installer).to receive(:install).with(Gem::Dependency.new('rspec', '>= 0'))
-    @gem_env.install(Gem::Dependency.new('rspec', '>= 0'), :install_dir => '/foo/bar', :sources => ['http://gems.example.com'])
+    expect(@gem_env).to receive(:dependency_installer).with(:install_dir => "/foo/bar").and_return(dep_installer)
+    expect(@gem_env).to receive(:with_gem_sources).with("http://gems.example.com").and_yield
+    expect(dep_installer).to receive(:install).with(Gem::Dependency.new("rspec", ">= 0"))
+    @gem_env.install(Gem::Dependency.new("rspec", ">= 0"), :install_dir => "/foo/bar", :sources => ["http://gems.example.com"])
   end
 
   it "builds an uninstaller for a gem with options set to avoid requiring user input" do
     # default options for uninstaller should be:
     # :ignore => true, :executables => true
-    expect(Gem::Uninstaller).to receive(:new).with('rspec', :ignore => true, :executables => true)
-    @gem_env.uninstaller('rspec')
+    expect(Gem::Uninstaller).to receive(:new).with("rspec", :ignore => true, :executables => true)
+    @gem_env.uninstaller("rspec")
   end
 
   it "uninstalls all versions of a gem" do
-    uninstaller = double('gem uninstaller')
+    uninstaller = double("gem uninstaller")
     expect(uninstaller).to receive(:uninstall)
-    expect(@gem_env).to receive(:uninstaller).with('rspec', :all => true).and_return(uninstaller)
-    @gem_env.uninstall('rspec')
+    expect(@gem_env).to receive(:uninstaller).with("rspec", :all => true).and_return(uninstaller)
+    @gem_env.uninstall("rspec")
   end
 
   it "uninstalls a specific version of a gem" do
-    uninstaller = double('gem uninstaller')
+    uninstaller = double("gem uninstaller")
     expect(uninstaller).to receive(:uninstall)
-    expect(@gem_env).to receive(:uninstaller).with('rspec', :version => '1.2.3').and_return(uninstaller)
-    @gem_env.uninstall('rspec', '1.2.3')
+    expect(@gem_env).to receive(:uninstaller).with("rspec", :version => "1.2.3").and_return(uninstaller)
+    @gem_env.uninstall("rspec", "1.2.3")
   end
 
 end
@@ -202,74 +170,72 @@ describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do
   before do
     Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache.clear
     Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache.clear
-    @gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new('/usr/weird/bin/gem')
+    @gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new("/usr/weird/bin/gem")
   end
 
   it "determines the gem paths from shelling out to gem env" do
-    gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
+    gem_env_output = ["/path/to/gems", "/another/path/to/gems"].join(File::PATH_SEPARATOR)
     shell_out_result = OpenStruct.new(:stdout => gem_env_output)
-    expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result)
-    expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
+    expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env gempath").and_return(shell_out_result)
+    expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
   end
 
   it "caches the gempaths by gem_binary" do
-    gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
+    gem_env_output = ["/path/to/gems", "/another/path/to/gems"].join(File::PATH_SEPARATOR)
     shell_out_result = OpenStruct.new(:stdout => gem_env_output)
-    expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result)
-    expected = ['/path/to/gems', '/another/path/to/gems']
-    expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
-    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']).to eq(expected)
+    expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env gempath").and_return(shell_out_result)
+    expected = ["/path/to/gems", "/another/path/to/gems"]
+    expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
+    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache["/usr/weird/bin/gem"]).to eq(expected)
   end
 
   it "uses the cached result for gem paths when available" do
-    gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR)
-    shell_out_result = OpenStruct.new(:stdout => gem_env_output)
     expect(@gem_env).not_to receive(:shell_out!)
-    expected = ['/path/to/gems', '/another/path/to/gems']
-    Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']= expected
-    expect(@gem_env.gem_paths).to eq(['/path/to/gems', '/another/path/to/gems'])
+    expected = ["/path/to/gems", "/another/path/to/gems"]
+    Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache["/usr/weird/bin/gem"] = expected
+    expect(@gem_env.gem_paths).to eq(["/path/to/gems", "/another/path/to/gems"])
   end
 
   it "builds the gems source index from the gem paths" do
-    allow(@gem_env).to receive(:gem_paths).and_return(['/path/to/gems', '/another/path/to/gems'])
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+    allow(@gem_env).to receive(:gem_paths).and_return(["/path/to/gems", "/another/path/to/gems"])
+    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
       @gem_env.gem_specification
-      expect(Gem::Specification.dirs).to eq([ '/path/to/gems/specifications', '/another/path/to/gems/specifications' ])
+      expect(Gem::Specification.dirs).to eq([ "/path/to/gems/specifications", "/another/path/to/gems/specifications" ])
     else
-      expect(Gem::SourceIndex).to receive(:from_gems_in).with('/path/to/gems/specifications', '/another/path/to/gems/specifications')
+      expect(Gem::SourceIndex).to receive(:from_gems_in).with("/path/to/gems/specifications", "/another/path/to/gems/specifications")
       @gem_env.gem_source_index
     end
   end
 
   it "determines the installed versions of gems from the source index" do
-    gems = [gemspec('rspec', Gem::Version.new('1.2.9')), gemspec('rspec', Gem::Version.new('1.3.0'))]
-    rspec_dep = Gem::Dependency.new('rspec', nil)
-    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
+    gems = [gemspec("rspec", Gem::Version.new("1.2.9")), gemspec("rspec", Gem::Version.new("1.3.0"))]
+    rspec_dep = Gem::Dependency.new("rspec", nil)
+    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.0")
       allow(@gem_env).to receive(:gem_specification).and_return(Gem::Specification)
       expect(@gem_env.gem_specification).to receive(:find_all_by_name).with(rspec_dep.name, rspec_dep.requirement).and_return(gems)
     else
       allow(@gem_env).to receive(:gem_source_index).and_return(Gem.source_index)
       expect(@gem_env.gem_source_index).to receive(:search).with(rspec_dep).and_return(gems)
     end
-    expect(@gem_env.installed_versions(Gem::Dependency.new('rspec', nil))).to eq(gems)
+    expect(@gem_env.installed_versions(Gem::Dependency.new("rspec", nil))).to eq(gems)
   end
 
   it "determines the installed versions of gems from the source index (part2: the unmockening)" do
     allow($stdout).to receive(:write)
     path_to_gem = if windows?
-      `where gem`.split[1]
-    else
-      `which gem`.strip
-    end
-    pending("cant find your gem executable") if path_to_gem.empty?
+                    `where gem`.split[1]
+                  else
+                    `which gem`.strip
+                  end
+    skip("cant find your gem executable") if path_to_gem.empty?
     gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new(path_to_gem)
-    expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)]
-    actual = gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |s| [s.name, s.version] }
+    expected = ["rspec-core", Gem::Version.new(RSpec::Core::Version::STRING)]
+    actual = gem_env.installed_versions(Gem::Dependency.new("rspec-core", nil)).map { |s| [s.name, s.version] }
     expect(actual).to include(expected)
   end
 
   it "detects when the target gem environment is the jruby platform" do
-    gem_env_out=<<-JRUBY_GEM_ENV
+    gem_env_out = <<-JRUBY_GEM_ENV
 RubyGems Environment:
   - RUBYGEMS VERSION: 1.3.6
   - RUBY VERSION: 1.8.7 (2010-05-12 patchlevel 249) [java]
@@ -295,23 +261,23 @@ RubyGems Environment:
   - REMOTE SOURCES:
      - https://rubygems.org/
      - http://gems.github.com/
-JRUBY_GEM_ENV
-    expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(double('jruby_gem_env', :stdout => gem_env_out))
-    expected = ['ruby', Gem::Platform.new('universal-java-1.6')]
+    JRUBY_GEM_ENV
+    expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env").and_return(double("jruby_gem_env", :stdout => gem_env_out))
+    expected = ["ruby", Gem::Platform.new("universal-java-1.6")]
     expect(@gem_env.gem_platforms).to eq(expected)
     # it should also cache the result
-    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']).to eq(expected)
+    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"]).to eq(expected)
   end
 
   it "uses the cached result for gem platforms if available" do
     expect(@gem_env).not_to receive(:shell_out!)
-    expected = ['ruby', Gem::Platform.new('universal-java-1.6')]
-    Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']= expected
+    expected = ["ruby", Gem::Platform.new("universal-java-1.6")]
+    Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"] = expected
     expect(@gem_env.gem_platforms).to eq(expected)
   end
 
   it "uses the current gem platforms when the target env is not jruby" do
-    gem_env_out=<<-RBX_GEM_ENV
+    gem_env_out = <<-RBX_GEM_ENV
 RubyGems Environment:
   - RUBYGEMS VERSION: 1.3.6
   - RUBY VERSION: 1.8.7 (2010-05-14 patchlevel 174) [x86_64-apple-darwin10.3.0]
@@ -337,23 +303,23 @@ RubyGems Environment:
   - REMOTE SOURCES:
      - https://rubygems.org/
      - http://gems.github.com/
-RBX_GEM_ENV
-    expect(@gem_env).to receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(double('rbx_gem_env', :stdout => gem_env_out))
+    RBX_GEM_ENV
+    expect(@gem_env).to receive(:shell_out!).with("/usr/weird/bin/gem env").and_return(double("rbx_gem_env", :stdout => gem_env_out))
     expect(@gem_env.gem_platforms).to eq(Gem.platforms)
-    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']).to eq(Gem.platforms)
+    expect(Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache["/usr/weird/bin/gem"]).to eq(Gem.platforms)
   end
 
   it "yields to a block while masquerading as a different gems platform" do
     original_platforms = Gem.platforms
     platforms_in_block = nil
     begin
-      @gem_env.with_gem_platforms(['ruby', Gem::Platform.new('sparc64-java-1.7')]) do
+      @gem_env.with_gem_platforms(["ruby", Gem::Platform.new("sparc64-java-1.7")]) do
         platforms_in_block = Gem.platforms
         raise "gem platforms should get set to the correct value even when an error occurs"
       end
     rescue RuntimeError
     end
-    expect(platforms_in_block).to eq(['ruby', Gem::Platform.new('sparc64-java-1.7')])
+    expect(platforms_in_block).to eq(["ruby", Gem::Platform.new("sparc64-java-1.7")])
     expect(Gem.platforms).to eq(original_platforms)
   end
 
@@ -361,339 +327,454 @@ end
 
 describe Chef::Provider::Package::Rubygems do
   let(:target_version) { nil }
+  let(:gem_name) { "rspec-core" }
+  let(:gem_binary) { nil }
+  let(:bindir) { "/usr/bin/ruby" }
+  let(:options) { nil }
+  let(:source) { nil }
+
+  let(:new_resource) do
+    new_resource = Chef::Resource::GemPackage.new(gem_name)
+    new_resource.version(target_version)
+    new_resource.gem_binary(gem_binary) if gem_binary
+    new_resource.options(options) if options
+    new_resource.source(source) if source
+    new_resource
+  end
 
-  before(:each) do
-    @node = Chef::Node.new
-    @new_resource = Chef::Resource::GemPackage.new("rspec-core")
-    @spec_version = @new_resource.version(target_version)
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
+  let (:current_resource) { nil }
+
+  let(:provider) do
+    run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
+    provider = Chef::Provider::Package::Rubygems.new(new_resource, run_context)
+    if current_resource
+      allow(provider).to receive(:load_current_resource)
+      provider.current_resource = current_resource
+    end
+    provider
+  end
+
+  let(:gem_dep) { Gem::Dependency.new(gem_name, target_version) }
 
+  before(:each) do
     # We choose detect omnibus via RbConfig::CONFIG['bindir'] in Chef::Provider::Package::Rubygems.new
-    allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/usr/bin/ruby")
+    allow(RbConfig::CONFIG).to receive(:[]).with("bindir").and_return(bindir)
     # Rubygems uses this interally
-    allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_call_original
-    @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
+    allow(RbConfig::CONFIG).to receive(:[]).with("arch").and_call_original
   end
 
   describe "when new_resource version is nil" do
     let(:target_version) { nil }
 
     it "target_version_already_installed? should return false so that we can search for candidates" do
-      @provider.load_current_resource
-      expect(@provider.target_version_already_installed?(@provider.current_resource.version, @new_resource.version)).to be_falsey
+      provider.load_current_resource
+      expect(provider.target_version_already_installed?(provider.current_resource.version, new_resource.version)).to be_falsey
     end
   end
 
-  describe "when new_resource version is current rspec version" do
-    let(:target_version) { RSpec::Core::Version::STRING }
+  describe "when new_resource version is an rspec version" do
+    let(:current_version) { RSpec::Core::Version::STRING }
+    let(:target_version) { current_version }
 
     it "triggers a gem configuration load so a later one will not stomp its config values" do
+      _ = provider
       # ugly, is there a better way?
       expect(Gem.instance_variable_get(:@configuration)).not_to be_nil
     end
 
     it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do
-      expect(@provider.gem_env).to be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
+      expect(provider.gem_env).to be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment)
     end
 
-    it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
-      @new_resource.gem_binary('/usr/weird/bin/gem')
-      provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
-      expect(provider.gem_env.gem_binary_location).to eq('/usr/weird/bin/gem')
+    context "when a gem_binary_path is provided" do
+      let(:gem_binary) { "/usr/weird/bin/gem" }
+
+      it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do
+        expect(provider.gem_env.gem_binary_location).to eq(gem_binary)
+      end
+
+      context "when you try to use a hash of install options" do
+        let(:options) { { :fail => :burger } }
+
+        it "smites you" do
+          expect { provider }.to raise_error(ArgumentError)
+        end
+      end
     end
 
-    it "searches for a gem binary when running on Omnibus on Unix" do
-      platform_mock :unix do
-        allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
-        allow(ENV).to receive(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
-        allow(File).to receive(:exists?).with('/usr/bin/gem').and_return(false)
-        allow(File).to receive(:exists?).with('/usr/sbin/gem').and_return(true)
-        allow(File).to receive(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here
-        provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
-        expect(provider.gem_env.gem_binary_location).to eq('/usr/sbin/gem')
+    context "when in omnibus opscode" do
+      let(:bindir) { "/opt/opscode/embedded/bin" }
+
+      it "recognizes opscode as omnibus" do
+        expect(provider.is_omnibus?).to be true
       end
     end
 
-    it "searches for a gem binary when running on Omnibus on Windows" do
-      platform_mock :windows do
-        allow(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin")
-        allow(ENV).to receive(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
-        allow(File).to receive(:exists?).with('C:\\windows\\system32\\gem').and_return(false)
-        allow(File).to receive(:exists?).with('C:\\windows\\gem').and_return(false)
-        allow(File).to receive(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true)
-        allow(File).to receive(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
-        allow(File).to receive(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
-        provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
-        expect(provider.gem_env.gem_binary_location).to eq('C:\Ruby186\bin\gem')
+    context "when in omnibus chefdk" do
+      let(:bindir) { "/opt/chefdk/embedded/bin" }
+
+      it "recognizes chefdk as omnibus" do
+        expect(provider.is_omnibus?).to be true
       end
     end
 
-    it "smites you when you try to use a hash of install options with an explicit gem binary" do
-      @new_resource.gem_binary('/foo/bar')
-      @new_resource.options(:fail => :burger)
-      expect {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.to raise_error(ArgumentError)
+    context "when in omnibus chef" do
+      let(:bindir) { "/opt/chef/embedded/bin" }
+
+      it "recognizes chef as omnibus" do
+        expect(provider.is_omnibus?).to be true
+      end
+
+      it "searches for a gem binary when running on Omnibus on Unix" do
+        platform_mock :unix do
+          allow(ENV).to receive(:[]).with("PATH").and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin")
+          allow(File).to receive(:exists?).with("/usr/bin/gem").and_return(false)
+          allow(File).to receive(:exists?).with("/usr/sbin/gem").and_return(true)
+          allow(File).to receive(:exists?).with("/opt/chef/embedded/bin/gem").and_return(true) # should not get here
+          expect(provider.gem_env.gem_binary_location).to eq("/usr/sbin/gem")
+        end
+      end
+
+      context "when on Windows" do
+        let(:bindir) { "d:/opscode/chef/embedded/bin" }
+
+        it "searches for a gem binary when running on Omnibus on Windows" do
+          platform_mock :windows do
+            allow(ENV).to receive(:[]).with("PATH").and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin')
+            allow(File).to receive(:exists?).with('C:\\windows\\system32\\gem').and_return(false)
+            allow(File).to receive(:exists?).with('C:\\windows\\gem').and_return(false)
+            allow(File).to receive(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true)
+            allow(File).to receive(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here
+            allow(File).to receive(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here
+            expect(provider.gem_env.gem_binary_location).to eq('C:\Ruby186\bin\gem')
+          end
+        end
+      end
     end
 
     it "converts the new resource into a gem dependency" do
-      expect(@provider.gem_dependency).to eq(Gem::Dependency.new('rspec-core', @spec_version))
-      @new_resource.version('~> 1.2.0')
-      expect(@provider.gem_dependency).to eq(Gem::Dependency.new('rspec-core', '~> 1.2.0'))
+      expect(provider.gem_dependency).to eq(gem_dep)
+    end
+
+    context "when the new resource is not the current version" do
+      let(:target_version) { "~> 9000.0.2" }
+
+      it "converts the new resource into a gem dependency" do
+        expect(provider.gem_dependency).to eq(gem_dep)
+      end
     end
 
     describe "when determining the currently installed version" do
+      before do
+        provider.load_current_resource
+      end
 
       it "sets the current version to the version specified by the new resource if that version is installed" do
-        @provider.load_current_resource
-        expect(@provider.current_resource.version).to eq(@spec_version)
+        expect(provider.current_resource.version).to eq(current_version)
       end
 
-      it "sets the current version to the highest installed version if the requested version is not installed" do
-        @new_resource.version('9000.0.2')
-        @provider.load_current_resource
-        expect(@provider.current_resource.version).to eq(@spec_version)
+      context "if the requested version is not installed" do
+        let(:target_version) { "9000.0.2" }
+
+        it "sets the current version to the highest installed version if the requested version is not installed" do
+          expect(provider.current_resource.version).to eq(current_version)
+        end
       end
 
-      it "leaves the current version at nil if the package is not installed" do
-        @new_resource.package_name("no-such-gem-should-exist-with-this-name")
-        @provider.load_current_resource
-        expect(@provider.current_resource.version).to be_nil
+      context "if the package is not currently installed" do
+        let(:gem_name) { "no-such-gem-should-exist-with-this-name" }
+
+        it "leaves the current version at nil" do
+          expect(provider.current_resource.version).to be_nil
+        end
       end
 
     end
 
     describe "when determining the candidate version to install" do
+      before do
+        provider.load_current_resource
+      end
 
       it "does not query for available versions when the current version is the target version" do
-        @provider.current_resource = @new_resource.dup
-        expect(@provider.candidate_version).to be_nil
+        expect(provider.candidate_version).to be_nil
       end
 
-      it "determines the candidate version by querying the remote gem servers" do
-        @new_resource.source('http://mygems.example.com')
-        @provider.load_current_resource
-        @provider.current_resource.version('0.0.1')
-        version = Gem::Version.new(@spec_version)
-        expect(@provider.gem_env).to receive(:candidate_version_from_remote).
-                          with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com").
-                          and_return(version)
-        expect(@provider.candidate_version).to eq(@spec_version)
+      context "when the current version is not the target version" do
+        let(:target_version) { "9000.0.2" }
+        let(:source) { "http://mygems.example.com" }
+
+        it "determines the candidate version by querying the remote gem servers" do
+          expect(provider.gem_env).to receive(:candidate_version_from_remote).
+            with(gem_dep, source).
+            and_return(Gem::Version.new(target_version))
+          expect(provider.candidate_version).to eq(target_version)
+        end
       end
 
-      it "parses the gem's specification if the requested source is a file" do
-        @new_resource.package_name('chef-integration-test')
-        @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-        @new_resource.version('>= 0')
-        @provider.load_current_resource
-        expect(@provider.candidate_version).to eq('0.1.0')
+      context "when the requested source is a file" do
+        let (:gem_name) { "chef-integration-test" }
+        let (:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+        let (:target_version) { ">= 0" }
+
+        it "parses the gem's specification" do
+          expect(provider.candidate_version).to eq("0.1.0")
+        end
       end
 
     end
 
     describe "when installing a gem" do
+      let(:target_version) { "9000.0.2" }
+      let(:current_version) { nil }
+      let(:candidate_version) { "9000.0.2" }
+      let(:current_resource) do
+        current_resource = Chef::Resource::GemPackage.new(gem_name)
+        current_resource.version(current_version)
+        current_resource
+      end
+
       before do
-        @current_resource = Chef::Resource::GemPackage.new('rspec-core')
-        @provider.current_resource = @current_resource
-        @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
-        allow(@provider).to receive(:load_current_resource)
+        version = Gem::Version.new(candidate_version)
+        args = [gem_dep]
+        args << source if source
+        allow(provider.gem_env).to receive(:candidate_version_from_remote).
+          with(*args).
+          and_return(version)
       end
 
       describe "in the current gem environment" do
         it "installs the gem via the gems api when no explicit options are used" do
-          expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+          expect(provider.gem_env).to receive(:install).with(gem_dep, :sources => nil)
+          provider.run_action(:install)
+          expect(new_resource).to be_updated_by_last_action
         end
 
-        it "installs the gem via the gems api when a remote source is provided" do
-          @new_resource.source('http://gems.example.org')
-          sources = ['http://gems.example.org']
-          expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => sources)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when a remote source is provided" do
+          let(:source) { "http://gems.example.org" }
+
+          it "installs the gem via the gems api" do
+            expect(provider.gem_env).to receive(:install).with(gem_dep, :sources => [source])
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
-        it "installs the gem from file via the gems api when no explicit options are used" do
-          @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when source is a path" do
+          let(:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+
+          it "installs the gem from file via the gems api" do
+            expect(provider.gem_env).to receive(:install).with(source)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
-        it "installs the gem from file via the gems api when the package is a path and the source is nil" do
-          @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
-          @provider.current_resource = @current_resource
-          expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          expect(@provider.gem_env).to receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when the gem name is a file path and source is nil" do
+          let(:gem_name) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+
+          it "installs the gem from file via the gems api" do
+            expect(new_resource.source).to eq(gem_name)
+            expect(provider.gem_env).to receive(:install).with(gem_name)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
         # this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem
         it "installs the gem via the gems api, when the package has no file separator characters in it, but a matching file exists in cwd" do
           allow(::File).to receive(:exists?).and_return(true)
-          @new_resource.package_name('rspec-core')
-          expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+          new_resource.package_name("rspec-core")
+          expect(provider.gem_env).to receive(:install).with(gem_dep, :sources => nil)
+          provider.run_action(:install)
+          expect(new_resource).to be_updated_by_last_action
         end
 
-        it "installs the gem by shelling out when options are provided as a String" do
-          @new_resource.options('-i /alt/install/location')
-          expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location"
-          expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when options are provided as a String" do
+          let(:options) { "-i /alt/install/location" }
+
+          it "installs the gem by shelling out when options are provided as a String" do
+            expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" #{options}"
+            expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
-        it "installs the gem with rubygems.org as an added source" do
-          @new_resource.gem_binary('/foo/bar')
-          @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
-          expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --source=#{@new_resource.source} --source=https://rubygems.org"
-          expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when another source and binary are provided" do
+          let(:source) { "http://mirror.ops.rhcloud.com/mirror/ruby" }
+          let(:gem_binary) { "/foo/bar" }
+
+          it "installs the gem with rubygems.org as an added source" do
+            expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --source=#{source} --source=https://rubygems.org"
+            expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
-        it "installs the gem with cleared sources and explict source when specified" do
-          @new_resource.gem_binary('/foo/bar')
-          @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
-          @new_resource.clear_sources(true)
-          expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --clear-sources --source=#{@new_resource.source}"
-          expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when we have cleared sources and an explict source is specified" do
+          let(:gem_binary) { "/foo/bar" }
+          let(:source) { "http://mirror.ops.rhcloud.com/mirror/ruby" }
+
+          it "installs the gem" do
+            new_resource.clear_sources(true)
+            expected = "#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\" --clear-sources --source=#{source}"
+            expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
         context "when no version is given" do
           let(:target_version) { nil }
+          let(:options) { "-i /alt/install/location" }
 
           it "installs the gem by shelling out when options are provided but no version is given" do
-            @new_resource.options('-i /alt/install/location')
-            expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@provider.candidate_version}\" -i /alt/install/location"
-            expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
-            @provider.run_action(:install)
-            expect(@new_resource).to be_updated_by_last_action
+            expected = "gem install rspec-core -q --no-rdoc --no-ri -v \"#{candidate_version}\" #{options}"
+            expect(provider).to receive(:shell_out!).with(expected, env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
           end
         end
 
-        it "installs the gem via the gems api when options are given as a Hash" do
-          @new_resource.options(:install_dir => '/alt/install/location')
-          expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location')
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when options are given as a Hash" do
+          let(:options) { { :install_dir => "/alt/install/location" } }
+
+          it "installs the gem via the gems api when options are given as a Hash" do
+            expect(provider.gem_env).to receive(:install).with(gem_dep, { :sources => nil }.merge(options))
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
         describe "at a specific version" do
-          before do
-            @gem_dep = Gem::Dependency.new('rspec-core', @spec_version)
-          end
+          let(:target_version) { "9000.0.2" }
 
           it "installs the gem via the gems api" do
-            expect(@provider.gem_env).to receive(:install).with(@gem_dep, :sources => nil)
-            @provider.run_action(:install)
-            expect(@new_resource).to be_updated_by_last_action
+            expect(provider.gem_env).to receive(:install).with(gem_dep, :sources => nil)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
           end
         end
-        describe "at version specified with comparison operator" do
-          it "skips install if current version satisifies requested version" do
-            @current_resource.version("2.3.3")
-            @new_resource.version(">=2.3.0")
 
-            expect(@provider.gem_env).not_to receive(:install)
-            @provider.run_action(:install)
+        describe "at version specified with comparison operator" do
+          context "if current version satisifies requested version" do
+            let(:target_version) { ">=2.3.0" }
+            let(:current_version) { "2.3.3" }
+
+            it "skips the install" do
+              expect(provider.gem_env).not_to receive(:install)
+              provider.run_action(:install)
+            end
           end
 
-          it "allows user to specify gem version with fuzzy operator" do
-            @current_resource.version("2.3.3")
-            @new_resource.version("~>2.3.0")
+          context "if the fuzzy operator is used" do
+            let(:target_version) { "~>2.3.0" }
+            let(:current_version) { "2.3.3" }
 
-            expect(@provider.gem_env).not_to receive(:install)
-            @provider.run_action(:install)
+            it "it matches an existing gem" do
+              expect(provider.gem_env).not_to receive(:install)
+              provider.run_action(:install)
+            end
           end
         end
       end
 
       describe "in an alternate gem environment" do
+        let(:gem_binary) { "/usr/weird/bin/gem" }
+
         it "installs the gem by shelling out to gem install" do
-          @new_resource.gem_binary('/usr/weird/bin/gem')
-          expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+          expect(provider).to receive(:shell_out!).with("#{gem_binary} install rspec-core -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+          provider.run_action(:install)
+          expect(new_resource).to be_updated_by_last_action
         end
 
-        it "installs the gem from file by shelling out to gem install" do
-          @new_resource.gem_binary('/usr/weird/bin/gem')
-          @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          @new_resource.version('>= 0')
-          expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when source is a path" do
+          let(:source) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+          let(:target_version) { ">= 0" }
+
+          it "installs the gem by shelling out to gem install" do
+            expect(provider).to receive(:shell_out!).with("#{gem_binary} install #{source} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
 
-        it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
-          @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)
-          @provider.current_resource = @current_resource
-          @new_resource.gem_binary('/usr/weird/bin/gem')
-          @new_resource.version('>= 0')
-          expect(@new_resource.source).to eq(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem')
-          expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil)
-          @provider.run_action(:install)
-          expect(@new_resource).to be_updated_by_last_action
+        context "when the package is a path and source is nil" do
+          let(:gem_name) { CHEF_SPEC_DATA + "/gems/chef-integration-test-0.1.0.gem" }
+          let(:target_version) { ">= 0" }
+
+          it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do
+            expect(new_resource.source).to eq(gem_name)
+            expect(provider).to receive(:shell_out!).with("#{gem_binary} install #{gem_name} -q --no-rdoc --no-ri -v \"#{target_version}\"", env: nil, timeout: 900)
+            provider.run_action(:install)
+            expect(new_resource).to be_updated_by_last_action
+          end
         end
       end
 
     end
 
     describe "when uninstalling a gem" do
-      before do
-        @new_resource = Chef::Resource::GemPackage.new("rspec")
-        @current_resource = @new_resource.dup
-        @current_resource.version('1.2.3')
-        @provider.new_resource = @new_resource
-        @provider.current_resource = @current_resource
+      let(:gem_name) { "rspec" }
+      let(:current_version) { "1.2.3" }
+      let(:target_version) { nil }
+
+      let(:current_resource) do
+        current_resource = Chef::Resource::GemPackage.new(gem_name)
+        current_resource.version(current_version)
+        current_resource
       end
 
       describe "in the current gem environment" do
         it "uninstalls via the api when no explicit options are used" do
           # pre-reqs for action_remove to actually remove the package:
-          expect(@provider.new_resource.version).to be_nil
-          expect(@provider.current_resource.version).not_to be_nil
+          expect(provider.new_resource.version).to be_nil
+          expect(provider.current_resource.version).not_to be_nil
           # the behavior we're testing:
-          expect(@provider.gem_env).to receive(:uninstall).with('rspec', nil)
-          @provider.action_remove
+          expect(provider.gem_env).to receive(:uninstall).with("rspec", nil)
+          provider.action_remove
         end
 
-        it "uninstalls via the api when options are given as a Hash" do
-          # pre-reqs for action_remove to actually remove the package:
-          expect(@provider.new_resource.version).to be_nil
-          expect(@provider.current_resource.version).not_to be_nil
-          # the behavior we're testing:
-          @new_resource.options(:install_dir => '/alt/install/location')
-          expect(@provider.gem_env).to receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location')
-          @provider.action_remove
+        context "when options are given as a Hash" do
+          let(:options) { { :install_dir => "/alt/install/location" } }
+
+          it "uninstalls via the api" do
+            # pre-reqs for action_remove to actually remove the package:
+            expect(provider.new_resource.version).to be_nil
+            expect(provider.current_resource.version).not_to be_nil
+            # the behavior we're testing:
+            expect(provider.gem_env).to receive(:uninstall).with("rspec", nil, options)
+            provider.action_remove
+          end
         end
 
-        it "uninstalls via the gem command when options are given as a String" do
-          @new_resource.options('-i /alt/install/location')
-          expect(@provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil)
-          @provider.action_remove
+        context "when options are given as a String" do
+          let(:options) { "-i /alt/install/location" }
+
+          it "uninstalls via the gem command" do
+            expect(provider).to receive(:shell_out!).with("gem uninstall rspec -q -x -I -a #{options}", env: nil, timeout: 900)
+            provider.action_remove
+          end
         end
 
-        it "uninstalls a specific version of a gem when a version is provided" do
-          @new_resource.version('1.2.3')
-          expect(@provider.gem_env).to receive(:uninstall).with('rspec', '1.2.3')
-          @provider.action_remove
+        context "when a version is provided" do
+          let(:target_version) { "1.2.3" }
+
+          it "uninstalls a specific version of a gem" do
+            expect(provider.gem_env).to receive(:uninstall).with("rspec", "1.2.3")
+            provider.action_remove
+          end
         end
       end
 
       describe "in an alternate gem environment" do
+        let(:gem_binary) { "/usr/weird/bin/gem" }
+
         it "uninstalls via the gem command" do
-          @new_resource.gem_binary('/usr/weird/bin/gem')
-          expect(@provider).to receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil)
-          @provider.action_remove
+          expect(provider).to receive(:shell_out!).with("#{gem_binary} uninstall rspec -q -x -I -a", env: nil, timeout: 900)
+          provider.action_remove
         end
       end
     end
diff --git a/spec/unit/provider/package/smartos_spec.rb b/spec/unit/provider/package/smartos_spec.rb
index db39589..51bffa1 100644
--- a/spec/unit/provider/package/smartos_spec.rb
+++ b/spec/unit/provider/package/smartos_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Trevor O (trevoro at joyent.com)
 # Author:: Yukihiko Sawanobori (sawanoboriyu at higanworks.com)
-# Copyright:: Copyright (c) 2012 Opscode
+# Copyright:: Copyright 2012-2016, Opscode
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 #
 
 require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
-require 'ostruct'
+require "ostruct"
 
 describe Chef::Provider::Package::SmartOS, "load_current_resource" do
   before(:each) do
@@ -28,46 +28,44 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
     @new_resource     = Chef::Resource::Package.new("varnish")
     @current_resource = Chef::Resource::Package.new("varnish")
 
-
-	  @status = double("Status", :exitstatus => 0)
-		@provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context)
-		allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
-		@stdin = StringIO.new
-		@stdout = "varnish-2.1.5nb2\n"
-		@stderr = StringIO.new
-		@pid = 10
-		@shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
+    @status = double("Status", :exitstatus => 0)
+    @provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context)
+    allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+    @stdin = StringIO.new
+    @stdout = "varnish-2.1.5nb2\n"
+    @stderr = StringIO.new
+    @pid = 10
+    @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0)
   end
 
-	describe "when loading current resource" do
+  describe "when loading current resource" do
 
     it "should create a current resource with the name of the new_resource" do
-			expect(@provider).to receive(:shell_out!).and_return(@shell_out)
-			expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
-			@provider.load_current_resource
+      expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+      expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
+      @provider.load_current_resource
     end
 
-		it "should set the current resource package name" do
-			expect(@provider).to receive(:shell_out!).and_return(@shell_out)
-			expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
-			@provider.load_current_resource
-		end
-
-		it "should set the installed version if it is installed" do
-		  expect(@provider).to receive(:shell_out!).and_return(@shell_out)
-			@provider.load_current_resource
-			expect(@current_resource.version).to eq("2.1.5nb2")
-	  end
+    it "should set the current resource package name" do
+      expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+      expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
+      @provider.load_current_resource
+    end
 
-		it "should set the installed version to nil if it's not installed" do
-			out = OpenStruct.new(:stdout => nil)
-			expect(@provider).to receive(:shell_out!).and_return(out)
-			@provider.load_current_resource
-			expect(@current_resource.version).to eq(nil)
-		end
+    it "should set the installed version if it is installed" do
+      expect(@provider).to receive(:shell_out!).and_return(@shell_out)
+      @provider.load_current_resource
+      expect(@current_resource.version).to eq("2.1.5nb2")
+    end
 
+    it "should set the installed version to nil if it's not installed" do
+      out = OpenStruct.new(:stdout => nil)
+      expect(@provider).to receive(:shell_out!).and_return(out)
+      @provider.load_current_resource
+      expect(@current_resource.version).to eq(nil)
+    end
 
-	end
+  end
 
   describe "candidate_version" do
     it "should return the candidate_version variable if already setup" do
@@ -76,27 +74,37 @@ describe Chef::Provider::Package::SmartOS, "load_current_resource" do
       @provider.candidate_version
     end
 
-    it "should lookup the candidate_version if the variable is not already set" do
+    it "should lookup the candidate_version if the variable is not already set (pkgin separated by spaces)" do
+      search = double()
+      expect(search).to receive(:each_line).
+        and_yield("something-varnish-1.1.1   something varnish like\n").
+        and_yield("varnish-2.3.4             actual varnish\n")
+      @shell_out = double("shell_out!", :stdout => search)
+      expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "se", "varnish", :env => nil, :returns => [0, 1], :timeout => 900).and_return(@shell_out)
+      expect(@provider.candidate_version).to eq("2.3.4")
+    end
+
+    it "should lookup the candidate_version if the variable is not already set (pkgin separated by semicolons)" do
       search = double()
       expect(search).to receive(:each_line).
-        and_yield("something-varnish-1.1.1  something varnish like\n").
-        and_yield("varnish-2.3.4 actual varnish\n")
-      @shell_out = double('shell_out!', :stdout => search)
-      expect(@provider).to receive(:shell_out!).with('/opt/local/bin/pkgin se varnish', :env => nil, :returns => [0,1]).and_return(@shell_out)
+        and_yield("something-varnish-1.1.1;;something varnish like\n").
+        and_yield("varnish-2.3.4;;actual varnish\n")
+      @shell_out = double("shell_out!", :stdout => search)
+      expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "se", "varnish", :env => nil, :returns => [0, 1], :timeout => 900).and_return(@shell_out)
       expect(@provider.candidate_version).to eq("2.3.4")
     end
   end
 
-	describe "when manipulating a resource" do
+  describe "when manipulating a resource" do
 
-		it "run pkgin and install the package" do
-			out = OpenStruct.new(:stdout => nil)
-      expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info -E \"varnish*\"", {:env => nil, :returns=>[0,1]}).and_return(@shell_out)
-      expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin -y install varnish-2.1.5nb2", {:env=>nil}).and_return(out)
+    it "run pkgin and install the package" do
+      out = OpenStruct.new(:stdout => nil)
+      expect(@provider).to receive(:shell_out!).with("/opt/local/sbin/pkg_info", "-E", "varnish*", { :env => nil, :returns => [0, 1], :timeout => 900 }).and_return(@shell_out)
+      expect(@provider).to receive(:shell_out!).with("/opt/local/bin/pkgin", "-y", "install", "varnish-2.1.5nb2", { :env => nil, :timeout => 900 }).and_return(out)
       @provider.load_current_resource
       @provider.install_package("varnish", "2.1.5nb2")
-		end
+    end
 
-	end
+  end
 
 end
diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb
index c348d66..9cc8dee 100644
--- a/spec/unit/provider/package/solaris_spec.rb
+++ b/spec/unit/provider/package/solaris_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Solaris do
   before(:each) do
@@ -32,7 +32,7 @@ describe Chef::Provider::Package::Solaris do
 
   describe "assessing the current package status" do
     before do
-      @pkginfo =<<-PKGINFO
+      @pkginfo = <<-PKGINFO
 PKGINST:  SUNWbash
 NAME:  GNU Bourne-Again shell (bash)
 CATEGORY:  system
@@ -46,7 +46,7 @@ INSTDATE:  Nov 04 2009 01:02
 HOTLINE:  Please contact your local service provider
 PKGINFO
 
-      @status = double("Status",:stdout => "", :exitstatus => 0)
+      @status = double("Status", :stdout => "", :exitstatus => 0)
     end
 
     it "should create a current resource with the name of new_resource" do
@@ -71,8 +71,8 @@ PKGINFO
 
     it "should get the source package version from pkginfo if provided" do
       status = double(:stdout => @pkginfo, :exitstatus => 0)
-      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(status)
-      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(@status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
       @provider.load_current_resource
 
       expect(@provider.current_resource.package_name).to eq("SUNWbash")
@@ -81,8 +81,8 @@ PKGINFO
 
     it "should return the current version installed if found by pkginfo" do
       status = double(:stdout => @pkginfo, :exitstatus => 0)
-      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status)
-      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(status)
       @provider.load_current_resource
       expect(@provider.current_resource.version).to eq("11.10.0,REV=2005.01.08.05.16")
     end
@@ -101,8 +101,8 @@ PKGINFO
     end
 
     it "should return a current resource with a nil version if the package is not found" do
-      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status)
-      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash").and_return(@status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l -d /tmp/bash.pkg SUNWbash", { timeout: 900 }).and_return(@status)
+      expect(@provider).to receive(:shell_out).with("pkginfo -l SUNWbash", { timeout: 900 }).and_return(@status)
       @provider.load_current_resource
       expect(@provider.current_resource.version).to be_nil
     end
@@ -132,7 +132,7 @@ PKGINFO
 
   describe "install and upgrade" do
     it "should run pkgadd -n -d with the package source to install" do
-      expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
+      expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
       @provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
     end
 
@@ -140,26 +140,26 @@ PKGINFO
       @new_resource = Chef::Resource::Package.new("/tmp/bash.pkg")
       @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context)
       expect(@new_resource.source).to eq("/tmp/bash.pkg")
-      expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all")
+      expect(@provider).to receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all", { timeout: 900 })
       @provider.install_package("/tmp/bash.pkg", "11.10.0,REV=2005.01.08.05.16")
     end
 
     it "should run pkgadd -n -a /tmp/myadmin -d with the package options -a /tmp/myadmin" do
       allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
-      expect(@provider).to receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all")
+      expect(@provider).to receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all", { timeout: 900 })
       @provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
     end
   end
 
   describe "remove" do
     it "should run pkgrm -n to remove the package" do
-      expect(@provider).to receive(:shell_out!).with("pkgrm -n SUNWbash")
+      expect(@provider).to receive(:shell_out!).with("pkgrm -n SUNWbash", { timeout: 900 })
       @provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
     end
 
     it "should run pkgrm -n -a /tmp/myadmin with options -a /tmp/myadmin" do
       allow(@new_resource).to receive(:options).and_return("-a /tmp/myadmin")
-      expect(@provider).to receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash")
+      expect(@provider).to receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash", { timeout: 900 })
       @provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16")
     end
 
diff --git a/spec/unit/provider/package/windows/exe_spec.rb b/spec/unit/provider/package/windows/exe_spec.rb
new file mode 100644
index 0000000..23a5460
--- /dev/null
+++ b/spec/unit/provider/package/windows/exe_spec.rb
@@ -0,0 +1,187 @@
+#
+# Author:: Matt Wrock <matt at mattwrock.com>
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/provider/package/windows/exe"
+
+unless Chef::Platform.windows?
+  class Chef
+    module ReservedNames::Win32
+      class File
+        def version_info
+          nil
+        end
+      end
+    end
+  end
+end
+
+describe Chef::Provider::Package::Windows::Exe do
+  let(:package_name) { "calculator" }
+  let(:resource_source) { "calculator.exe" }
+  let(:new_resource) do
+    new_resource = Chef::Resource::WindowsPackage.new(package_name)
+    new_resource.source(resource_source)
+    new_resource
+  end
+  let(:uninstall_hash) do
+    [{
+      "DisplayVersion" => "outdated",
+      "UninstallString" => File.join("uninst_dir", "uninst_file"),
+    }]
+  end
+  let(:uninstall_entry) do
+    entries = []
+    uninstall_hash.each do |entry|
+      entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", "key", entry))
+    end
+    entries
+  end
+  let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
+
+  before(:each) do
+    allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
+  end
+
+  it "responds to shell_out!" do
+    expect(provider).to respond_to(:shell_out!)
+  end
+
+  describe "expand_options" do
+    it "returns an empty string if passed no options" do
+      expect(provider.expand_options(nil)).to eql ""
+    end
+
+    it "returns a string with a leading space if passed options" do
+      expect(provider.expand_options("--train nope --town no_way")).to eql(" --train nope --town no_way")
+    end
+  end
+
+  describe "installed_version" do
+    it "returns the installed version" do
+      expect(provider.installed_version).to eql(["outdated"])
+    end
+
+    context "no versions installed" do
+      let(:uninstall_hash) { [] }
+
+      it "returns the installed version" do
+        expect(provider.installed_version).to eql(nil)
+      end
+    end
+  end
+
+  describe "package_version" do
+    before { new_resource.version(nil) }
+
+    context "source file does not exist" do
+      before do
+        allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+      end
+
+      it "returns nil" do
+        expect(provider.package_version).to eql(nil)
+      end
+    end
+
+    it "returns the version attribute if given" do
+      new_resource.version("v55555")
+      expect(provider.package_version).to eql("v55555")
+    end
+
+    it "returns nil if no version given" do
+      expect(provider.package_version).to eql(nil)
+    end
+  end
+
+  describe "remove_package" do
+    context "no version given and one package installed" do
+      it "removes installed package" do
+        expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir\" uninst_file \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+        provider.remove_package
+      end
+    end
+
+    context "several packages installed" do
+      let(:uninstall_hash) do
+        [
+          {
+          "DisplayVersion" => "v1",
+          "UninstallString" => File.join("uninst_dir1", "uninst_file1"),
+          },
+          {
+          "DisplayVersion" => "v2",
+          "UninstallString" => File.join("uninst_dir2", "uninst_file2"),
+          },
+        ]
+      end
+
+      context "version given and installed" do
+        it "removes given version" do
+          new_resource.version("v2")
+          expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+          provider.remove_package
+        end
+      end
+
+      context "no version given" do
+        it "removes both versions" do
+          expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir1\" uninst_file1 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+          expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \/d\"uninst_dir2\" uninst_file2 \/S \/NCRC & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+          provider.remove_package
+        end
+      end
+    end
+  end
+
+  context "installs nsis installer" do
+    let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :nsis, uninstall_entry) }
+
+    it "calls installer with the correct flags" do
+      expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/S \/NCRC  & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+      provider.install_package
+    end
+  end
+
+  context "installs installshield installer" do
+    let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :installshield, uninstall_entry) }
+
+    it "calls installer with the correct flags" do
+      expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s \/sms  & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+      provider.install_package
+    end
+  end
+
+  context "installs inno installer" do
+    let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :inno, uninstall_entry) }
+
+    it "calls installer with the correct flags" do
+      expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/VERYSILENT \/SUPPRESSMSGBOXES \/NORESTART  & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+      provider.install_package
+    end
+  end
+
+  context "installs wise installer" do
+    let(:provider) { Chef::Provider::Package::Windows::Exe.new(new_resource, :wise, uninstall_entry) }
+
+    it "calls installer with the correct flags" do
+      expect(provider).to receive(:shell_out!).with(/start \"\" \/wait \"#{Regexp.quote(new_resource.source)}\" \/s  & exit %%%%ERRORLEVEL%%%%/, kind_of(Hash))
+      provider.install_package
+    end
+  end
+end
diff --git a/spec/unit/provider/package/windows/msi_spec.rb b/spec/unit/provider/package/windows/msi_spec.rb
index bef2028..e29508c 100644
--- a/spec/unit/provider/package/windows/msi_spec.rb
+++ b/spec/unit/provider/package/windows/msi_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,38 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "chef/provider/package/windows/msi"
 
 describe Chef::Provider::Package::Windows::MSI do
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
-  let(:new_resource) { Chef::Resource::WindowsPackage.new("calculator.msi") }
-  let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource) }
-
-  before(:each) do
-    stub_const("File::ALT_SEPARATOR", "\\")
-    allow(::File).to receive(:absolute_path).with("calculator.msi").and_return("calculator.msi")
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+  let(:package_name) { "calculator" }
+  let(:resource_source) { "calculator.msi" }
+  let(:resource_version) { nil }
+  let(:new_resource) do
+    new_resource = Chef::Resource::WindowsPackage.new(package_name)
+    new_resource.source(resource_source)
+    new_resource.version(resource_version)
+    new_resource
+  end
+  let(:uninstall_hash) do
+    [{
+      "DisplayVersion" => "outdated",
+      "UninstallString" => "MsiExec.exe /X{guid}",
+    }]
+  end
+  let(:uninstall_entry) do
+    entries = []
+    uninstall_hash.each do |entry|
+      entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", "key", entry))
+    end
+    entries
+  end
+  let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource, uninstall_entry) }
+  before do
+    allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(true)
   end
 
   it "responds to shell_out!" do
@@ -50,6 +70,11 @@ describe Chef::Provider::Package::Windows::MSI do
       allow(provider).to receive(:get_installed_version).with("{23170F69-40C1-2702-0920-000001000000}").and_return("3.14159.1337.42")
       expect(provider.installed_version).to eql("3.14159.1337.42")
     end
+
+    it "returns the installed version in the registry when install file not present" do
+      allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+      expect(provider.installed_version).to eql(["outdated"])
+    end
   end
 
   describe "package_version" do
@@ -57,19 +82,78 @@ describe Chef::Provider::Package::Windows::MSI do
       allow(provider).to receive(:get_product_property).with(/calculator.msi$/, "ProductVersion").and_return(42)
       expect(provider.package_version).to eql(42)
     end
+
+    context "version is explicitly provided" do
+      let(:resource_version) { "given_version" }
+
+      it "returns the given version" do
+        expect(provider.package_version).to eql("given_version")
+      end
+    end
+
+    context "no source or version is given" do
+      before do
+        allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+      end
+
+      it "returns nil" do
+        expect(provider.package_version).to eql(nil)
+      end
+    end
   end
 
   describe "install_package" do
     it "calls msiexec /qn /i" do
-      expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"calculator.msi\"/, kind_of(Hash))
-      provider.install_package("unused", "unused")
+      expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/i \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
+      provider.install_package
     end
   end
 
   describe "remove_package" do
     it "calls msiexec /qn /x" do
-      expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"calculator.msi\"/, kind_of(Hash))
-      provider.remove_package("unused", "unused")
+      expect(provider).to receive(:shell_out!).with(/msiexec \/qn \/x \"#{Regexp.quote(new_resource.source)}\"/, kind_of(Hash))
+      provider.remove_package
+    end
+
+    context "no source is provided" do
+      before do
+        allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+      end
+
+      it "removes installed package" do
+        expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
+        provider.remove_package
+      end
+
+      context "there are multiple installs" do
+        let(:uninstall_hash) do
+          [
+            {
+              "DisplayVersion" => "outdated",
+              "UninstallString" => "MsiExec.exe /X{guid}",
+            },
+            {
+              "DisplayVersion" => "really_outdated",
+              "UninstallString" => "MsiExec.exe /X{guid2}",
+            },
+          ]
+        end
+
+        it "removes both installed package" do
+          expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
+          expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid2} \/Q/, kind_of(Hash))
+          provider.remove_package
+        end
+      end
+
+      context "custom options includes /Q" do
+        before { new_resource.options("/Q") }
+
+        it "does not duplicate quiet switch" do
+          expect(provider).to receive(:shell_out!).with(/MsiExec.exe \/X{guid} \/Q/, kind_of(Hash))
+          provider.remove_package
+        end
+      end
     end
   end
 end
diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb
index d402113..62e40e7 100644
--- a/spec/unit/provider/package/windows_spec.rb
+++ b/spec/unit/provider/package/windows_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,71 +16,361 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "chef/provider/package/windows/exe"
+require "chef/provider/package/windows/msi"
 
 describe Chef::Provider::Package::Windows, :windows_only do
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
-  let(:new_resource) { Chef::Resource::WindowsPackage.new("calculator.msi") }
+  before(:each) do
+    allow(Chef::Util::PathHelper).to receive(:windows?).and_return(true)
+    allow(Chef::FileCache).to receive(:create_cache_path).with("package/").and_return(cache_path)
+  end
+
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
+  let(:resource_source) { "calculator.msi" }
+  let(:resource_name) { "calculator" }
+  let(:new_resource) do
+    new_resource = Chef::Resource::WindowsPackage.new(resource_name)
+    new_resource.source(resource_source) if resource_source
+    new_resource
+  end
   let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) }
+  let(:cache_path) { 'c:\\cache\\' }
+
+  before(:each) do
+    allow(::File).to receive(:exist?).with(provider.new_resource.source).and_return(true)
+  end
 
   describe "load_current_resource" do
-    before(:each) do
-      allow(Chef::Util::PathHelper).to receive(:validate_path)
-      allow(provider).to receive(:package_provider).and_return(double('package_provider',
+    shared_examples "a local file" do
+      before(:each) do
+        allow(Chef::Util::PathHelper).to receive(:validate_path)
+        allow(provider).to receive(:package_provider).and_return(double("package_provider",
           :installed_version => "1.0", :package_version => "2.0"))
-    end
+      end
 
-    it "creates a current resource with the name of the new resource" do
-      provider.load_current_resource
-      expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
-      expect(provider.current_resource.name).to eql("calculator.msi")
-    end
+      it "creates a current resource with the name of the new resource" do
+        provider.load_current_resource
+        expect(provider.current_resource).to be_a(Chef::Resource::WindowsPackage)
+        expect(provider.current_resource.name).to eql(resource_name)
+      end
 
-    it "sets the current version if the package is installed" do
-      provider.load_current_resource
-      expect(provider.current_resource.version).to eql("1.0")
+      it "sets the current version if the package is installed" do
+        provider.load_current_resource
+        expect(provider.current_resource.version).to eql("1.0")
+      end
+
+      it "sets the version to be installed" do
+        provider.load_current_resource
+        expect(provider.new_resource.version).to eql("2.0")
+      end
     end
 
-    it "sets the version to be installed" do
-      provider.load_current_resource
-      expect(provider.new_resource.version).to eql("2.0")
+    context "when the source is a uri" do
+      let(:resource_source) { "https://foo.bar/calculator.msi" }
+
+      context "when the source has not been downloaded" do
+        before(:each) do
+          allow(provider).to receive(:downloadable_file_missing?).and_return(true)
+        end
+        it "sets the current version to unknown" do
+          provider.load_current_resource
+          expect(provider.current_resource.version).to eql("unknown")
+        end
+      end
+
+      context "when the source has been downloaded" do
+        before(:each) do
+          allow(provider).to receive(:downloadable_file_missing?).and_return(false)
+        end
+        it_behaves_like "a local file"
+      end
     end
 
-    it "checks that the source path is valid" do
-      expect(Chef::Util::PathHelper).to receive(:validate_path)
-      provider.load_current_resource
+    context "when source is a local file" do
+      it_behaves_like "a local file"
     end
   end
 
   describe "package_provider" do
-    it "sets the package provider to MSI if the the installer type is :msi" do
-      allow(provider).to receive(:installer_type).and_return(:msi)
-      expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
+    shared_examples "a local file" do
+
+      it "checks that the source path is valid" do
+        expect(Chef::Util::PathHelper).to receive(:validate_path).and_call_original
+        provider.package_provider
+      end
+
+      it "sets the package provider to MSI if the the installer type is :msi" do
+        allow(provider).to receive(:installer_type).and_return(:msi)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI)
+      end
+
+      it "sets the package provider to Exe if the the installer type is :inno" do
+        allow(provider).to receive(:installer_type).and_return(:inno)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+      end
+
+      it "sets the package provider to Exe if the the installer type is :nsis" do
+        allow(provider).to receive(:installer_type).and_return(:nsis)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+      end
+
+      it "sets the package provider to Exe if the the installer type is :wise" do
+        allow(provider).to receive(:installer_type).and_return(:wise)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+      end
+
+      it "sets the package provider to Exe if the the installer type is :installshield" do
+        allow(provider).to receive(:installer_type).and_return(:installshield)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+      end
+
+      it "defaults to exe if the installer_type is unknown" do
+        allow(provider).to receive(:installer_type).and_return(nil)
+        expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::Exe)
+      end
+    end
+
+    context "when the source is a uri" do
+      let(:resource_source) { "https://foo.bar/calculator.msi" }
+
+      context "when the source has not been downloaded" do
+        before(:each) do
+          allow(provider).to receive(:should_download?).and_return(true)
+        end
+
+        it "should create a package provider with source pointing at the local file" do
+          expect(Chef::Provider::Package::Windows::MSI).to receive(:new) do |r|
+            expect(r.source).to eq("#{cache_path}#{::File.basename(resource_source)}")
+          end
+          provider.package_provider
+        end
+
+        it_behaves_like "a local file"
+      end
+
+      context "when the source has been downloaded" do
+        before(:each) do
+          allow(provider).to receive(:should_download?).and_return(false)
+        end
+        it_behaves_like "a local file"
+      end
     end
 
-    it "raises an error if the installer_type is unknown" do
-      allow(provider).to receive(:installer_type).and_return(:apt_for_windows)
-      expect { provider.package_provider }.to raise_error
+    context "when source is a local file" do
+      it_behaves_like "a local file"
     end
   end
 
   describe "installer_type" do
-    it "it returns @installer_type if it is set" do
+    let(:resource_source) { "microsoft_installer.exe" }
+
+    context "there is no source" do
+      let(:uninstall_hash) do
+        [{
+          "DisplayVersion" => "outdated",
+          "UninstallString" => "blah blah",
+        }]
+      end
+      let(:uninstall_key) { "blah" }
+      let(:uninstall_entry) do
+        entries = []
+        uninstall_hash.each do |entry|
+          entries.push(Chef::Provider::Package::Windows::RegistryUninstallEntry.new("hive", uninstall_key, entry))
+        end
+        entries
+      end
+
+      before do
+        allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return(uninstall_entry)
+        allow(::File).to receive(:exist?).with(Chef::Util::PathHelper.canonical_path(resource_source, false)).and_return(false)
+      end
+
+      context "uninstall string contains MsiExec.exe" do
+        let(:uninstall_hash) do
+          [{
+            "DisplayVersion" => "outdated",
+            "UninstallString" => "MsiExec.exe /X{guid}",
+          }]
+        end
+
+        it "sets installer_type to MSI" do
+          expect(provider.installer_type).to eql(:msi)
+        end
+      end
+
+      context "uninstall string ends with uninst.exe" do
+        let(:uninstall_hash) do
+          [{
+            "DisplayVersion" => "outdated",
+            "UninstallString" => %q{"c:/hfhfheru/uninst.exe"},
+          }]
+        end
+
+        it "sets installer_type to NSIS" do
+          expect(provider.installer_type).to eql(:nsis)
+        end
+      end
+
+      context "uninstall key ends in _is1" do
+        let(:uninstall_key) { "blah_is1" }
+
+        it "sets installer_type to inno" do
+          expect(provider.installer_type).to eql(:inno)
+        end
+      end
+
+      context "eninstall entries is empty" do
+        before { allow(Chef::Provider::Package::Windows::RegistryUninstallEntry).to receive(:find_entries).and_return([]) }
+
+        it "returns nil" do
+          expect(provider.installer_type).to eql(nil)
+        end
+      end
+    end
+
+    it "returns @installer_type if it is set" do
       provider.new_resource.installer_type(:downeaster)
       expect(provider.installer_type).to eql(:downeaster)
     end
 
-    it "sets installer_type to msi if the source ends in .msi" do
-      provider.new_resource.source("microsoft_installer.msi")
-      expect(provider.installer_type).to eql(:msi)
+    it "sets installer_type to inno if the source contains inno" do
+      allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah inno blah"))
+      expect(provider.installer_type).to eql(:inno)
     end
 
-    it "raises an error if it cannot determine the installer type" do
-      provider.new_resource.installer_type(nil)
-      provider.new_resource.source("tomfoolery.now")
-      expect { provider.installer_type }.to raise_error(ArgumentError)
+    it "sets installer_type to wise if the source contains wise" do
+      allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah wise blah"))
+      expect(provider.installer_type).to eql(:wise)
+    end
+
+    it "sets installer_type to nsis if the source contains nsis" do
+      allow(::Kernel).to receive(:open).and_yield(StringIO.new("blah blah nullsoft blah"))
+      expect(provider.installer_type).to eql(:nsis)
+    end
+
+    context "source ends in .msi" do
+      let(:resource_source) { "microsoft_installer.msi" }
+
+      it "sets installer_type to msi" do
+        expect(provider.installer_type).to eql(:msi)
+      end
+    end
+
+    context "the source is setup.exe" do
+      let(:resource_source) { "setup.exe" }
+
+      it "sets installer_type to installshield" do
+        allow(::Kernel).to receive(:open).and_yield(StringIO.new(""))
+        expect(provider.installer_type).to eql(:installshield)
+      end
+    end
+
+    context "cannot determine the installer type" do
+      let(:resource_source) { "tomfoolery.now" }
+
+      it "raises an error" do
+        allow(::Kernel).to receive(:open).and_yield(StringIO.new(""))
+        provider.new_resource.installer_type(nil)
+        expect { provider.installer_type }.to raise_error(Chef::Exceptions::CannotDetermineWindowsInstallerType)
+      end
+    end
+  end
+
+  describe "action_install" do
+    let(:resource_name) { "blah" }
+    let(:resource_source) { "blah.exe" }
+
+    before do
+      new_resource.installer_type(:inno)
+      allow_any_instance_of(Chef::Provider::Package::Windows::Exe).to receive(:package_version).and_return(new_resource.version)
+    end
+
+    context "no source given" do
+      let(:resource_source) { nil }
+
+      it "raises a NoWindowsPackageSource error" do
+        expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::NoWindowsPackageSource)
+      end
+    end
+
+    context "no version given, discovered or installed" do
+      it "installs latest" do
+        expect(provider).to receive(:install_package).with("blah", "latest")
+        provider.run_action(:install)
+      end
+    end
+
+    context "no version given or discovered but package is installed" do
+      before { allow(provider).to receive(:current_version_array).and_return(["5.5.5"]) }
+
+      it "does not install" do
+        expect(provider).not_to receive(:install_package)
+        provider.run_action(:install)
+      end
+    end
+
+    context "a version is given and none is installed" do
+      before { new_resource.version("5.5.5") }
+
+      it "installs given version" do
+        expect(provider).to receive(:install_package).with("blah", "5.5.5")
+        provider.run_action(:install)
+      end
+    end
+
+    context "a version is given and several are installed" do
+      context "given version matches an installed version" do
+        before do
+          new_resource.version("5.5.5")
+          allow(provider).to receive(:current_version_array).and_return([ ["5.5.5", "4.3.0", "1.1.1"] ])
+        end
+
+        it "does not install" do
+          expect(provider).not_to receive(:install_package)
+          provider.run_action(:install)
+        end
+      end
+
+      context "given version does not match an installed version" do
+        before do
+          new_resource.version("5.5.5")
+          allow(provider).to receive(:current_version_array).and_return([ ["5.5.0", "4.3.0", "1.1.1"] ])
+        end
+
+        it "installs given version" do
+          expect(provider).to receive(:install_package).with("blah", "5.5.5")
+          provider.run_action(:install)
+        end
+      end
+    end
+
+    context "a version is given and one is installed" do
+      context "given version matches installed version" do
+        before do
+          new_resource.version("5.5.5")
+          allow(provider).to receive(:current_version_array).and_return(["5.5.5"])
+        end
+
+        it "does not install" do
+          expect(provider).not_to receive(:install_package)
+          provider.run_action(:install)
+        end
+      end
+
+      context "given version does not match installed version" do
+        before do
+          new_resource.version("5.5.5")
+          allow(provider).to receive(:current_version_array).and_return(["5.5.0"])
+        end
+
+        it "installs given version" do
+          expect(provider).to receive(:install_package).with("blah", "5.5.5")
+          provider.run_action(:install)
+        end
+      end
     end
   end
 end
diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb
index 865dce2..98fe955 100644
--- a/spec/unit/provider/package/yum_spec.rb
+++ b/spec/unit/provider/package/yum_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,18 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
+require "securerandom"
 
 describe Chef::Provider::Package::Yum do
   before(:each) do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new('cups')
+    @new_resource = Chef::Resource::YumPackage.new("cups")
     @status = double("Status", :exitstatus => 0)
     @yum_cache = double(
-      'Chef::Provider::Yum::YumCache',
+      "Chef::Provider::Yum::YumCache",
       :reload_installed => true,
       :reset => true,
       :installed_version => "1.2.4-11.18.el5",
@@ -35,9 +36,10 @@ describe Chef::Provider::Package::Yum do
       :version_available? => true,
       :allow_multi_install => [ "kernel" ],
       :package_repository => "base",
-      :disable_extra_repo_control => true
+      :disable_extra_repo_control => true,
     )
     allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+    allow(@yum_cache).to receive(:yum_binary=).with("yum")
     @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
     @pid = double("PID")
   end
@@ -75,23 +77,63 @@ describe Chef::Provider::Package::Yum do
 
     describe "when source is provided" do
       it "should set the candidate version" do
-        @new_resource = Chef::Resource::YumPackage.new('testing.source')
+        @new_resource = Chef::Resource::YumPackage.new("testing.source")
         @new_resource.source "chef-server-core-12.0.5-1.rpm"
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         allow(File).to receive(:exists?).with(@new_resource.source).and_return(true)
         allow(@yum_cache).to receive(:installed_version).and_return(nil)
-        shellout_double = double(:stdout => 'chef-server-core 12.0.5-1')
+        shellout_double = double(:stdout => "chef-server-core 12.0.5-1")
         allow(@provider).to receive(:shell_out!).and_return(shellout_double)
         @provider.load_current_resource
-        expect(@provider.candidate_version).to eql('12.0.5-1')
+        expect(@provider.candidate_version).to eql("12.0.5-1")
+      end
+    end
+
+    describe "yum_binary accessor" do
+      it "when yum-deprecated exists" do
+        expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(true)
+        expect(@yum_cache).to receive(:yum_binary=).with("yum-deprecated")
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        expect(@provider.yum_binary).to eql("yum-deprecated")
+      end
+
+      it "when yum-deprecated does not exist" do
+        expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(false)
+        expect(@yum_cache).to receive(:yum_binary=).with("yum")
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        expect(@provider.yum_binary).to eql("yum")
+      end
+
+      it "when the yum_binary is set on the resource" do
+        @new_resource.yum_binary "/usr/bin/yum-something"
+        expect(File).not_to receive(:exist?)
+        expect(@yum_cache).to receive(:yum_binary=).with("/usr/bin/yum-something")
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        expect(@provider.yum_binary).to eql("/usr/bin/yum-something")
+      end
+
+      it "when the new_resource is a vanilla package class and yum-deprecated exists" do
+        @new_resource = Chef::Resource::Package.new("cups")
+        expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(true)
+        expect(@yum_cache).to receive(:yum_binary=).with("yum-deprecated")
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        expect(@provider.yum_binary).to eql("yum-deprecated")
+      end
+
+      it "when the new_resource is a vanilla package class and yum-deprecated does not exist" do
+        @new_resource = Chef::Resource::Package.new("cups")
+        expect(File).to receive(:exist?).with("/usr/bin/yum-deprecated").and_return(false)
+        expect(@yum_cache).to receive(:yum_binary=).with("yum")
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        expect(@provider.yum_binary).to eql("yum")
       end
     end
 
     describe "when arch in package_name" do
       it "should set the arch if no existing package_name is found and new_package_name+new_arch is available" do
-        @new_resource = Chef::Resource::YumPackage.new('testing.noarch')
+        @new_resource = Chef::Resource::YumPackage.new("testing.noarch")
         @yum_cache = double(
-          'Chef::Provider::Yum::YumCache'
+          "Chef::Provider::Yum::YumCache"
         )
         allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
           # nothing installed for package_name/new_package_name
@@ -108,13 +150,14 @@ describe Chef::Provider::Package::Yum do
         allow(@yum_cache).to receive(:package_available?).and_return(true)
         allow(@yum_cache).to receive(:disable_extra_repo_control).and_return(true)
         allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+        allow(@yum_cache).to receive(:yum_binary=).with("yum")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing")
         expect(@provider.new_resource.arch).to eq("noarch")
         expect(@provider.arch).to eq("noarch")
 
-        @new_resource = Chef::Resource::YumPackage.new('testing.more.noarch')
+        @new_resource = Chef::Resource::YumPackage.new("testing.more.noarch")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing.more")
@@ -122,10 +165,30 @@ describe Chef::Provider::Package::Yum do
         expect(@provider.arch).to eq("noarch")
       end
 
+      describe "when version constraint in package_name" do
+        it "should set package_version if no existing package_name is found and new_package_name is available" do
+          @new_resource = Chef::Resource::Package.new("cups = 1.2.4-11.18.el5_2.3")
+          @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+          allow(@yum_cache).to receive(:package_available?) { |pkg| pkg == "cups" ? true : false }
+          allow(@yum_cache).to receive(:packages_from_require) do |pkg|
+            [Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base"),
+            Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.2", "noarch", [], false, true, "base")]
+          end
+          expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{checking yum info})
+          expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{installed version})
+          expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{matched 2 packages,})
+          @provider.load_current_resource
+          expect(@provider.new_resource.package_name).to eq("cups")
+          expect(@provider.new_resource.version).to eq("1.2.4-11.18.el5_2.3")
+          expect(@provider.send(:new_version_array)).to eq(["1.2.4-11.18.el5_2.3"])
+          expect(@provider.send(:package_name_array)).to eq(["cups"])
+        end
+      end
+
       it "should not set the arch when an existing package_name is found" do
-        @new_resource = Chef::Resource::YumPackage.new('testing.beta3')
+        @new_resource = Chef::Resource::YumPackage.new("testing.beta3")
         @yum_cache = double(
-          'Chef::Provider::Yum::YumCache'
+          "Chef::Provider::Yum::YumCache"
         )
         allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
           # installed for package_name
@@ -142,6 +205,7 @@ describe Chef::Provider::Package::Yum do
         allow(@yum_cache).to receive(:package_available?).and_return(true)
         allow(@yum_cache).to receive(:disable_extra_repo_control).and_return(true)
         allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+        allow(@yum_cache).to receive(:yum_binary=).with("yum")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         # annoying side effect of the fun stub'ing above
         @provider.load_current_resource
@@ -149,7 +213,7 @@ describe Chef::Provider::Package::Yum do
         expect(@provider.new_resource.arch).to eq(nil)
         expect(@provider.arch).to eq(nil)
 
-        @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more')
+        @new_resource = Chef::Resource::YumPackage.new("testing.beta3.more")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing.beta3.more")
@@ -158,9 +222,9 @@ describe Chef::Provider::Package::Yum do
       end
 
       it "should not set the arch when no existing package_name or new_package_name+new_arch is found" do
-        @new_resource = Chef::Resource::YumPackage.new('testing.beta3')
+        @new_resource = Chef::Resource::YumPackage.new("testing.beta3")
         @yum_cache = double(
-          'Chef::Provider::Yum::YumCache'
+          "Chef::Provider::Yum::YumCache"
         )
         allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
           # nothing installed for package_name/new_package_name
@@ -173,13 +237,14 @@ describe Chef::Provider::Package::Yum do
         allow(@yum_cache).to receive(:package_available?).and_return(true)
         allow(@yum_cache).to receive(:disable_extra_repo_control).and_return(true)
         allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+        allow(@yum_cache).to receive(:yum_binary=).with("yum")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing.beta3")
         expect(@provider.new_resource.arch).to eq(nil)
         expect(@provider.arch).to eq(nil)
 
-        @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more')
+        @new_resource = Chef::Resource::YumPackage.new("testing.beta3.more")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing.beta3.more")
@@ -188,14 +253,14 @@ describe Chef::Provider::Package::Yum do
       end
 
       it "should ensure it doesn't clobber an existing arch if passed" do
-        @new_resource = Chef::Resource::YumPackage.new('testing.i386')
+        @new_resource = Chef::Resource::YumPackage.new("testing.i386")
         @new_resource.arch("x86_64")
         @yum_cache = double(
-          'Chef::Provider::Yum::YumCache'
+          "Chef::Provider::Yum::YumCache"
         )
-         allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
-           # nothing installed for package_name/new_package_name
-         nil
+        allow(@yum_cache).to receive(:installed_version) do |package_name, arch|
+          # nothing installed for package_name/new_package_name
+          nil
         end
         allow(@yum_cache).to receive(:candidate_version) do |package_name, arch|
           if package_name == "testing.noarch"
@@ -208,6 +273,7 @@ describe Chef::Provider::Package::Yum do
         allow(@yum_cache).to receive(:package_available?).and_return(true)
         allow(@yum_cache).to receive(:disable_extra_repo_control).and_return(true)
         allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+        allow(@yum_cache).to receive(:yum_binary=).with("yum")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
         expect(@provider.new_resource.package_name).to eq("testing.i386")
@@ -216,13 +282,13 @@ describe Chef::Provider::Package::Yum do
     end
 
     it "should flush the cache if :before is true" do
-      allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => true})
+      allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => true })
       expect(@yum_cache).to receive(:reload).once
       @provider.load_current_resource
     end
 
     it "should flush the cache if :before is false" do
-      allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => false})
+      allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => false })
       expect(@yum_cache).not_to receive(:reload)
       @provider.load_current_resource
     end
@@ -247,19 +313,20 @@ describe Chef::Provider::Package::Yum do
 
     context "when the package name isn't found" do
       let(:yum_cache) { double(
-          'Chef::Provider::Yum::YumCache',
+          "Chef::Provider::Yum::YumCache",
           :reload_installed => true,
           :reset => true,
           :installed_version => "1.0.1.el5",
           :candidate_version => "2.0.1.el5",
           :package_available? => false,
           :version_available? => true,
-          :disable_extra_repo_control => true
+          :disable_extra_repo_control => true,
       )
       }
 
       before do
         allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(yum_cache)
+        allow(yum_cache).to receive(:yum_binary=).with("yum")
         @pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "2.0.1.el5", "x86_64", [])
         expect(yum_cache).to receive(:packages_from_require).and_return([@pkg])
       end
@@ -267,70 +334,69 @@ describe Chef::Provider::Package::Yum do
       it "should search provides then set package_name to match" do
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq('test-package')
+        expect(@new_resource.package_name).to eq("test-package")
         expect(@new_resource.version).to eq(nil)
       end
 
       it "should search provides then set version to match if a requirement was passed in the package name" do
-        @new_resource = Chef::Resource::YumPackage.new('test-package = 2.0.1.el5')
+        @new_resource = Chef::Resource::YumPackage.new("test-package = 2.0.1.el5")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq('test-package')
-        expect(@new_resource.version).to eq('2.0.1.el5')
+        expect(@new_resource.package_name).to eq("test-package")
+        expect(@new_resource.version).to eq("2.0.1.el5")
       end
 
-
       it "should search provides then set version to match if a requirement was passed in the version" do
-        @new_resource = Chef::Resource::YumPackage.new('test-package')
-        @new_resource.version('= 2.0.1.el5')
+        @new_resource = Chef::Resource::YumPackage.new("test-package")
+        @new_resource.version("= 2.0.1.el5")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq('test-package')
-        expect(@new_resource.version).to eq('2.0.1.el5')
+        expect(@new_resource.package_name).to eq("test-package")
+        expect(@new_resource.version).to eq("2.0.1.el5")
       end
 
-
       it "should search provides and not set the version to match if a specific version was requested" do
-        @new_resource = Chef::Resource::YumPackage.new('test-package')
-        @new_resource.version('3.0.1.el5')
+        @new_resource = Chef::Resource::YumPackage.new("test-package")
+        @new_resource.version("3.0.1.el5")
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq('test-package')
-        expect(@new_resource.version).to eq('3.0.1.el5')
+        expect(@new_resource.package_name).to eq("test-package")
+        expect(@new_resource.version).to eq("3.0.1.el5")
       end
 
       it "should search provides then set versions to match if requirements were passed in the package name as an array" do
-        @new_resource = Chef::Resource::YumPackage.new(['test-package = 2.0.1.el5'])
+        @new_resource = Chef::Resource::YumPackage.new(["test-package = 2.0.1.el5"])
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq(['test-package'])
-        expect(@new_resource.version).to eq(['2.0.1.el5'])
+        expect(@new_resource.package_name).to eq(["test-package"])
+        expect(@new_resource.version).to eq(["2.0.1.el5"])
       end
 
       it "should search provides and not set the versions to match if specific versions were requested in an array" do
-        @new_resource = Chef::Resource::YumPackage.new(['test-package'])
-        @new_resource.version(['3.0.1.el5'])
+        @new_resource = Chef::Resource::YumPackage.new(["test-package"])
+        @new_resource.version(["3.0.1.el5"])
         @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
         @provider.load_current_resource
-        expect(@new_resource.package_name).to eq(['test-package'])
-        expect(@new_resource.version).to eq(['3.0.1.el5'])
+        expect(@new_resource.package_name).to eq(["test-package"])
+        expect(@new_resource.version).to eq(["3.0.1.el5"])
       end
 
     end
 
     it "should not return an error if no version number is specified in the resource" do
-      @new_resource = Chef::Resource::YumPackage.new('test-package')
+      @new_resource = Chef::Resource::YumPackage.new("test-package")
       @yum_cache = double(
-          'Chef::Provider::Yum::YumCache',
+          "Chef::Provider::Yum::YumCache",
           :reload_installed => true,
           :reset => true,
           :installed_version => "1.0.1.el5",
           :candidate_version => "2.0.1.el5",
           :package_available? => false,
           :version_available? => true,
-          :disable_extra_repo_control => true
+          :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "2.0.1.el5", "x86_64", [])
       expect(@yum_cache).to receive(:packages_from_require).and_return([pkg])
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@@ -340,64 +406,67 @@ describe Chef::Provider::Package::Yum do
     end
 
     it "should give precedence to the version attribute when both a requirement in the resource name and a version attribute are specified" do
-      @new_resource = Chef::Resource::YumPackage.new('test-package')
+      @new_resource = Chef::Resource::YumPackage.new("test-package")
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
         :candidate_version => "1.2.4-11.18.el5",
         :package_available? => false,
         :version_available? => true,
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "2.0.1.el5", "x86_64", [])
       expect(@yum_cache).to receive(:packages_from_require).and_return([pkg])
-      @new_resource = Chef::Resource::YumPackage.new('test-package = 2.0.1.el5')
-      @new_resource.version('3.0.1.el5')
+      @new_resource = Chef::Resource::YumPackage.new("test-package = 2.0.1.el5")
+      @new_resource.version("3.0.1.el5")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
-      expect(@new_resource.package_name).to eq('test-package')
-      expect(@new_resource.version).to eq('3.0.1.el5')
+      expect(@new_resource.package_name).to eq("test-package")
+      expect(@new_resource.version).to eq("3.0.1.el5")
     end
 
     it "should correctly detect the installed states of an array of package names and version numbers" do
       @yum_cache = double(
-          'Chef::Provider::Yum::YumCache',
+          "Chef::Provider::Yum::YumCache",
           :reload_installed => true,
           :reset => true,
           :installed_version => "1.0.1.el5",
           :candidate_version => "2.0.1.el5",
           :package_available? => false,
           :version_available? => true,
-          :disable_extra_repo_control => true
+          :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
 
       expect(@yum_cache).to receive(:packages_from_require).exactly(4).times.and_return([])
       expect(@yum_cache).to receive(:reload_provides).twice
 
-      @new_resource = Chef::Resource::YumPackage.new(['test-package','test-package2'])
-      @new_resource.version(['2.0.1.el5','3.0.1.el5'])
+      @new_resource = Chef::Resource::YumPackage.new(["test-package", "test-package2"])
+      @new_resource.version(["2.0.1.el5", "3.0.1.el5"])
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
-      expect(@new_resource.package_name).to eq(['test-package','test-package2'])
-      expect(@new_resource.version).to eq(['2.0.1.el5','3.0.1.el5'])
+      expect(@new_resource.package_name).to eq(["test-package", "test-package2"])
+      expect(@new_resource.version).to eq(["2.0.1.el5", "3.0.1.el5"])
     end
 
     it "should search provides if no package is available - if no match in installed provides then load the complete set" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
         :candidate_version => "1.2.4-11.18.el5",
         :package_available? => false,
         :version_available? => true,
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       expect(@yum_cache).to receive(:packages_from_require).twice.and_return([])
       expect(@yum_cache).to receive(:reload_provides)
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
@@ -407,16 +476,17 @@ describe Chef::Provider::Package::Yum do
 
     it "should search provides if no package is available and not load the complete set if action is :remove or :purge" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
         :candidate_version => "1.2.4-11.18.el5",
         :package_available? => false,
         :version_available? => true,
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       expect(@yum_cache).to receive(:packages_from_require).once.and_return([])
       expect(@yum_cache).not_to receive(:reload_provides)
@@ -430,7 +500,7 @@ describe Chef::Provider::Package::Yum do
 
     it "should search provides if no package is available - if no match in provides leave the name intact" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_provides => true,
         :reload_installed => true,
         :reset => true,
@@ -438,9 +508,10 @@ describe Chef::Provider::Package::Yum do
         :candidate_version => "1.2.4-11.18.el5",
         :package_available? => false,
         :version_available? => true,
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       expect(@yum_cache).to receive(:packages_from_require).twice.and_return([])
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
@@ -453,7 +524,7 @@ describe Chef::Provider::Package::Yum do
       @provider.load_current_resource
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.19.el5"
+        "-d0 -e0 -y install cups-1.2.4-11.19.el5"
       )
       @provider.install_package("cups", "1.2.4-11.19.el5")
     end
@@ -461,7 +532,7 @@ describe Chef::Provider::Package::Yum do
     it "should run yum localinstall if given a path to an rpm" do
       allow(@new_resource).to receive(:source).and_return("/tmp/emacs-21.4-20.el5.i386.rpm")
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm"
+        "-d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm"
       )
       @provider.install_package("emacs", "21.4-20.el5")
     end
@@ -472,7 +543,7 @@ describe Chef::Provider::Package::Yum do
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       expect(@new_resource.source).to eq("/tmp/emacs-21.4-20.el5.i386.rpm")
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm"
+        "-d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm"
       )
       @provider.install_package("/tmp/emacs-21.4-20.el5.i386.rpm", "21.4-20.el5")
     end
@@ -482,34 +553,35 @@ describe Chef::Provider::Package::Yum do
       allow(@new_resource).to receive(:arch).and_return("i386")
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.19.el5.i386"
+        "-d0 -e0 -y install cups-1.2.4-11.19.el5.i386"
       )
       @provider.install_package("cups", "1.2.4-11.19.el5")
     end
 
     it "installs the package with the options given in the resource" do
       @provider.load_current_resource
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      allow(@provider).to receive(:candidate_version).and_return("11")
       allow(@new_resource).to receive(:options).and_return("--disablerepo epmd")
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y --disablerepo epmd install cups-11"
+        "-d0 -e0 -y --disablerepo epmd install cups-11"
       )
       @provider.install_package(@new_resource.name, @provider.candidate_version)
     end
 
     it "should raise an exception if the package is not available" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_from_cache => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
         :candidate_version => "1.2.4-11.18.el5_2.3",
         :package_available? => true,
         :version_available? => nil,
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       expect { @provider.install_package("lolcats", "0.99") }.to raise_error(Chef::Exceptions::Package, %r{Version .* not found})
     end
@@ -517,7 +589,7 @@ describe Chef::Provider::Package::Yum do
     it "should raise an exception if candidate version is older than the installed version and allow_downgrade is false" do
       allow(@new_resource).to receive(:allow_downgrade).and_return(false)
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
@@ -525,9 +597,10 @@ describe Chef::Provider::Package::Yum do
         :package_available? => true,
         :version_available? => true,
         :allow_multi_install => [ "kernel" ],
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
       expect { @provider.install_package("cups", "1.2.4-11.15.el5") }.to raise_error(Chef::Exceptions::Package, %r{is newer than candidate package})
@@ -535,7 +608,7 @@ describe Chef::Provider::Package::Yum do
 
     it "should not raise an exception if candidate version is older than the installed version and the package is list in yum's installonlypkg option" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
@@ -544,13 +617,14 @@ describe Chef::Provider::Package::Yum do
         :version_available? => true,
         :allow_multi_install => [ "cups" ],
         :package_repository => "base",
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.15.el5"
+        "-d0 -e0 -y install cups-1.2.4-11.15.el5"
       )
       @provider.install_package("cups", "1.2.4-11.15.el5")
     end
@@ -558,7 +632,7 @@ describe Chef::Provider::Package::Yum do
     it "should run yum downgrade if candidate version is older than the installed version and allow_downgrade is true" do
       allow(@new_resource).to receive(:allow_downgrade).and_return(true)
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
@@ -567,34 +641,35 @@ describe Chef::Provider::Package::Yum do
         :version_available? => true,
         :allow_multi_install => [],
         :package_repository => "base",
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y downgrade cups-1.2.4-11.15.el5"
+        "-d0 -e0 -y downgrade cups-1.2.4-11.15.el5"
       )
       @provider.install_package("cups", "1.2.4-11.15.el5")
     end
 
     it "should run yum install then flush the cache if :after is true" do
-      allow(@new_resource).to receive(:flush_cache).and_return({:after => true, :before => false})
+      allow(@new_resource).to receive(:flush_cache).and_return({ :after => true, :before => false })
       @provider.load_current_resource
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.15.el5"
+        "-d0 -e0 -y install cups-1.2.4-11.15.el5"
       )
       expect(@yum_cache).to receive(:reload).once
       @provider.install_package("cups", "1.2.4-11.15.el5")
     end
 
     it "should run yum install then not flush the cache if :after is false" do
-      allow(@new_resource).to receive(:flush_cache).and_return({:after => false, :before => false})
+      allow(@new_resource).to receive(:flush_cache).and_return({ :after => false, :before => false })
       @provider.load_current_resource
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.15.el5"
+        "-d0 -e0 -y install cups-1.2.4-11.15.el5"
       )
       expect(@yum_cache).not_to receive(:reload)
       @provider.install_package("cups", "1.2.4-11.15.el5")
@@ -604,28 +679,28 @@ describe Chef::Provider::Package::Yum do
   describe "when upgrading a package" do
     it "should run yum install if the package is installed and a version is given" do
       @provider.load_current_resource
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      allow(@provider).to receive(:candidate_version).and_return("11")
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-11"
+        "-d0 -e0 -y install cups-11"
       )
       @provider.upgrade_package(@new_resource.name, @provider.candidate_version)
     end
 
     it "should run yum install if the package is not installed" do
       @provider.load_current_resource
-      @current_resource = Chef::Resource::Package.new('cups')
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      @current_resource = Chef::Resource::Package.new("cups")
+      allow(@provider).to receive(:candidate_version).and_return("11")
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-11"
+        "-d0 -e0 -y install cups-11"
       )
       @provider.upgrade_package(@new_resource.name, @provider.candidate_version)
     end
 
     it "should raise an exception if candidate version is older than the installed version" do
       @yum_cache = double(
-        'Chef::Provider::Yum::YumCache',
+        "Chef::Provider::Yum::YumCache",
         :reload_installed => true,
         :reset => true,
         :installed_version => "1.2.4-11.18.el5",
@@ -633,9 +708,10 @@ describe Chef::Provider::Package::Yum do
         :package_available? => true,
         :version_available? => true,
         :allow_multi_install => [ "kernel" ],
-        :disable_extra_repo_control => true
+        :disable_extra_repo_control => true,
       )
       allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+      allow(@yum_cache).to receive(:yum_binary=).with("yum")
       @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
       @provider.load_current_resource
       expect { @provider.upgrade_package("cups", "1.2.4-11.15.el5") }.to raise_error(Chef::Exceptions::Package, %r{is newer than candidate package})
@@ -644,18 +720,18 @@ describe Chef::Provider::Package::Yum do
     # Test our little workaround, some crossover into Chef::Provider::Package territory
     it "should call action_upgrade in the parent if the current resource version is nil" do
       allow(@yum_cache).to receive(:installed_version).and_return(nil)
-      @current_resource = Chef::Resource::Package.new('cups')
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      @current_resource = Chef::Resource::Package.new("cups")
+      allow(@provider).to receive(:candidate_version).and_return("11")
       expect(@provider).to receive(:upgrade_package).with(
         "cups",
-        "11"
+        "11",
       )
       @provider.run_action(:upgrade)
     end
 
     it "should call action_upgrade in the parent if the candidate version is nil" do
       @provider.load_current_resource
-      @current_resource = Chef::Resource::Package.new('cups')
+      @current_resource = Chef::Resource::Package.new("cups")
       allow(@provider).to receive(:candidate_version).and_return(nil)
       expect(@provider).not_to receive(:upgrade_package)
       @provider.run_action(:upgrade)
@@ -663,11 +739,11 @@ describe Chef::Provider::Package::Yum do
 
     it "should call action_upgrade in the parent if the candidate is newer" do
       @provider.load_current_resource
-      @current_resource = Chef::Resource::Package.new('cups')
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      @current_resource = Chef::Resource::Package.new("cups")
+      allow(@provider).to receive(:candidate_version).and_return("11")
       expect(@provider).to receive(:upgrade_package).with(
         "cups",
-        "11"
+        "11",
       )
       @provider.run_action(:upgrade)
     end
@@ -675,8 +751,8 @@ describe Chef::Provider::Package::Yum do
     it "should not call action_upgrade in the parent if the candidate is older" do
       allow(@yum_cache).to receive(:installed_version).and_return("12")
       @provider.load_current_resource
-      @current_resource = Chef::Resource::Package.new('cups')
-      allow(@provider).to receive(:candidate_version).and_return('11')
+      @current_resource = Chef::Resource::Package.new("cups")
+      allow(@provider).to receive(:candidate_version).and_return("11")
       expect(@provider).not_to receive(:upgrade_package)
       @provider.run_action(:upgrade)
     end
@@ -685,7 +761,7 @@ describe Chef::Provider::Package::Yum do
   describe "when removing a package" do
     it "should run yum remove with the package name" do
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y remove emacs-1.0"
+        "-d0 -e0 -y remove emacs-1.0"
       )
       @provider.remove_package("emacs", "1.0")
     end
@@ -693,7 +769,7 @@ describe Chef::Provider::Package::Yum do
     it "should run yum remove with the package name and arch" do
       allow(@new_resource).to receive(:arch).and_return("x86_64")
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y remove emacs-1.0.x86_64"
+        "-d0 -e0 -y remove emacs-1.0.x86_64"
       )
       @provider.remove_package("emacs", "1.0")
     end
@@ -702,7 +778,7 @@ describe Chef::Provider::Package::Yum do
   describe "when purging a package" do
     it "should run yum remove with the package name" do
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y remove emacs-1.0"
+        "-d0 -e0 -y remove emacs-1.0"
       )
       @provider.purge_package("emacs", "1.0")
     end
@@ -714,9 +790,9 @@ describe Chef::Provider::Package::Yum do
       allow(@provider).to receive(:shell_out).and_return(@status)
       expect(@provider).to receive(:shell_out).once.with(
         "yum -d0 -e0 -y install emacs-1.0",
-        {:timeout => Chef::Config[:yum_timeout]}
+        { :timeout => Chef::Config[:yum_timeout] },
       )
-      @provider.yum_command("yum -d0 -e0 -y install emacs-1.0")
+      @provider.yum_command("-d0 -e0 -y install emacs-1.0")
     end
 
     it "should run yum once if it exits with a return code > 0 and no scriptlet failures" do
@@ -724,33 +800,46 @@ describe Chef::Provider::Package::Yum do
       allow(@provider).to receive(:shell_out).and_return(@status)
       expect(@provider).to receive(:shell_out).once.with(
         "yum -d0 -e0 -y install emacs-1.0",
-        {:timeout => Chef::Config[:yum_timeout]}
+        { :timeout => Chef::Config[:yum_timeout] },
       )
-      expect { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+      expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
     end
 
     it "should run yum once if it exits with a return code of 1 and %pre scriptlet failures" do
       @status = double("Status", :exitstatus => 1, :stdout => "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
-                      :stderr => "")
+                                 :stderr => "")
       allow(@provider).to receive(:shell_out).and_return(@status)
       expect(@provider).to receive(:shell_out).once.with(
         "yum -d0 -e0 -y install emacs-1.0",
-        {:timeout => Chef::Config[:yum_timeout]}
+        { :timeout => Chef::Config[:yum_timeout] },
       )
       # will still raise an exception, can't stub out the subsequent call
-      expect { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+      expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
     end
 
     it "should run yum twice if it exits with a return code of 1 and %post scriptlet failures" do
       @status = double("Status", :exitstatus => 1, :stdout => "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
-                      :stderr => "")
+                                 :stderr => "")
       allow(@provider).to receive(:shell_out).and_return(@status)
       expect(@provider).to receive(:shell_out).twice.with(
         "yum -d0 -e0 -y install emacs-1.0",
-        {:timeout => Chef::Config[:yum_timeout]}
+        { :timeout => Chef::Config[:yum_timeout] },
       )
       # will still raise an exception, can't stub out the subsequent call
-      expect { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+      expect { @provider.yum_command("-d0 -e0 -y install emacs-1.0") }.to raise_error(Chef::Exceptions::Exec)
+    end
+
+    it "should pass the yum_binary to the command if its specified" do
+      @new_resource.yum_binary "yum-deprecated"
+      expect(@yum_cache).to receive(:yum_binary=).with("yum-deprecated")
+      @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+      @status = double("Status", :exitstatus => 0, :stdout => "", :stderr => "")
+      allow(@provider).to receive(:shell_out).and_return(@status)
+      expect(@provider).to receive(:shell_out).once.with(
+        "yum-deprecated -d0 -e0 -y install emacs-1.0",
+        { :timeout => Chef::Config[:yum_timeout] },
+      )
+      @provider.yum_command("-d0 -e0 -y install emacs-1.0")
     end
   end
 end
@@ -765,7 +854,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ "0:3.3", [ 0, "3.3", nil ] ],
         [ "9:1.7.3", [ 9, "1.7.3", nil ] ],
-        [ "15:20020927", [ 15, "20020927", nil ] ]
+        [ "15:20020927", [ 15, "20020927", nil ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -775,7 +864,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ ":3.3", [ 0, "3.3", nil ] ],
         [ "-1:1.7.3", [ nil, nil, "1:1.7.3" ] ],
-        [ "-:20020927", [ nil, nil, ":20020927" ] ]
+        [ "-:20020927", [ nil, nil, ":20020927" ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -785,7 +874,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ "3.3", [ nil, "3.3", nil ] ],
         [ "1.7.3", [ nil, "1.7.3", nil ] ],
-        [ "20020927", [ nil, "20020927", nil ] ]
+        [ "20020927", [ nil, "20020927", nil ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -795,7 +884,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ "3..3", [ nil, "3..3", nil ] ],
         [ "0001.7.3", [ nil, "0001.7.3", nil ] ],
-        [ "20020927,3", [ nil, "20020927,3", nil ] ]
+        [ "20020927,3", [ nil, "20020927,3", nil ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -805,7 +894,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ "3.3-0.pre3.1.60.el5_5.1", [ nil, "3.3", "0.pre3.1.60.el5_5.1" ] ],
         [ "1.7.3-1jpp.2.el5", [ nil, "1.7.3", "1jpp.2.el5" ] ],
-        [ "20020927-46.el5", [ nil, "20020927", "46.el5" ] ]
+        [ "20020927-46.el5", [ nil, "20020927", "46.el5" ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -815,7 +904,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
       [
         [ "3.3-", [ nil, "3.3", nil ] ],
         [ "-1jpp.2.el5", [ nil, nil, "1jpp.2.el5" ] ],
-        [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ]
+        [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ],
       ].each do |x, y|
         expect(@rpmutils.version_parse(x)).to eq(y)
       end
@@ -874,7 +963,7 @@ describe Chef::Provider::Package::Yum::RPMUtils do
         [ "0.0.1aa", "0.0.1aa", 0 ],
         [ "0.0.1a", "0.0.1aa", -1 ],
      ].each do |x, y, result|
-        expect(@rpmutils.rpmvercmp(x,y)).to eq(result)
+        expect(@rpmutils.rpmvercmp(x, y)).to eq(result)
       end
     end
 
@@ -891,44 +980,44 @@ describe Chef::Provider::Package::Yum::RPMUtils do
         [ nil, "1.0.1", -1 ],
         [ "1.0.1", "", 1 ],
         [ "", "", 0 ],
-        [ "", "1.0.1", -1 ]
+        [ "", "1.0.1", -1 ],
      ].each do |x, y, result|
-        expect(@rpmutils.rpmvercmp(x,y)).to eq(result)
+        expect(@rpmutils.rpmvercmp(x, y)).to eq(result)
       end
     end
 
     it "tests isalnum good input" do
-      [ 'a', 'z', 'A', 'Z', '0', '9' ].each do |t|
+      [ "a", "z", "A", "Z", "0", "9" ].each do |t|
         expect(@rpmutils.isalnum(t)).to eq(true)
       end
     end
 
     it "tests isalnum bad input" do
-      [ '-', '.', '!', '^', ':', '_' ].each do |t|
+      [ "-", ".", "!", "^", ":", "_" ].each do |t|
         expect(@rpmutils.isalnum(t)).to eq(false)
       end
     end
 
     it "tests isalpha good input" do
-      [ 'a', 'z', 'A', 'Z', ].each do |t|
+      [ "a", "z", "A", "Z" ].each do |t|
         expect(@rpmutils.isalpha(t)).to eq(true)
       end
     end
 
     it "tests isalpha bad input" do
-      [ '0', '9', '-', '.', '!', '^', ':', '_' ].each do |t|
+      [ "0", "9", "-", ".", "!", "^", ":", "_" ].each do |t|
         expect(@rpmutils.isalpha(t)).to eq(false)
       end
     end
 
     it "tests isdigit good input" do
-      [ '0', '9', ].each do |t|
+      [ "0", "9" ].each do |t|
         expect(@rpmutils.isdigit(t)).to eq(true)
       end
     end
 
     it "tests isdigit bad input" do
-      [ 'A', 'z', '-', '.', '!', '^', ':', '_' ].each do |t|
+      [ "A", "z", "-", ".", "!", "^", ":", "_" ].each do |t|
         expect(@rpmutils.isdigit(t)).to eq(false)
       end
     end
@@ -1011,7 +1100,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
         [ "0:1.4.10-7.20090624svn.el5",
           "0:1.4.10-7.20090625svn.el5" ],
         [ "0:2.3.4-2.el5",
-          "0:2.3.4-2.el6" ]
+          "0:2.3.4-2.el6" ],
       ].each do |smaller, larger|
         sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
         lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1037,7 +1126,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
         [ "0:1.9",
           "3:1.9" ],
         [ "2.3-2.el5",
-          "2.3-2.el6" ]
+          "2.3-2.el6" ],
       ].each do |smaller, larger|
         sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
         lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1054,7 +1143,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
         [ "0:2.3-15.el5",
           "0:2.3-15.el5" ],
         [ "0:alpha9.8-27.2",
-          "0:alpha9.8-27.2" ]
+          "0:alpha9.8-27.2" ],
       ].each do |smaller, larger|
         sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
         lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1069,7 +1158,7 @@ describe Chef::Provider::Package::Yum::RPMVersion do
         [ "2.3-15.el5",
           "2.3-15.el5" ],
         [ "alpha9.8-3",
-          "alpha9.8-3" ]
+          "alpha9.8-3" ],
       ].each do |smaller, larger|
         sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller)
         lg = Chef::Provider::Package::Yum::RPMVersion.new(larger)
@@ -1369,7 +1458,7 @@ describe Chef::Provider::Package::Yum::RPMDependency do
         [ "=", :== ],
         [ "==", :== ],
         [ "<=", :<= ],
-        [ "<", :< ]
+        [ "<", :< ],
       ].each do |before, after|
         @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1")
         expect(@rpmdep.flag).to eq(after)
@@ -1383,7 +1472,7 @@ describe Chef::Provider::Package::Yum::RPMDependency do
         [ ">>", :== ],
         [ "<<", :== ],
         [ "!", :== ],
-        [ "~", :== ]
+        [ "~", :== ],
       ].each do |before, after|
         @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1")
         expect(@rpmdep.name).to eq("testing #{before} 1:1.1-1")
@@ -1458,12 +1547,12 @@ describe Chef::Provider::Package::Yum::RPMDb do
     # name, version, arch, installed, available
     deps_v = [
       Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"),
-      Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a = 0:1.6.5-9.36.el5")
+      Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a = 0:1.6.5-9.36.el5"),
     ]
     deps_z = [
       Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"),
       Chef::Provider::Package::Yum::RPMDependency.parse("config(test) = 0:1.6.5-9.36.el5"),
-      Chef::Provider::Package::Yum::RPMDependency.parse("test-package-c = 0:1.6.5-9.36.el5")
+      Chef::Provider::Package::Yum::RPMDependency.parse("test-package-c = 0:1.6.5-9.36.el5"),
     ]
     @rpm_v = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-a", "0:1.6.5-9.36.el5", "i386", deps_v, true, false, "base")
     @rpm_w = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "i386", [], true, true, "extras")
@@ -1659,6 +1748,14 @@ describe Chef::Provider::Package::Yum::YumCache do
     end
   end
 
+  let(:yum_exe) {
+    StringIO.new("#!/usr/bin/python\n\naldsjfa\ldsajflkdsjf\lajsdfj")
+  }
+
+  let(:bin_exe) {
+    StringIO.new(SecureRandom.random_bytes)
+  }
+
   before(:each) do
     @stdin = double("STDIN", :nil_object => true)
     @stdout = double("STDOUT", :nil_object => true)
@@ -1704,12 +1801,20 @@ file: file://///etc/yum.repos.d/CentOS-Base.repo, line: 12
 'qeqwewe\n'
 EOF
     @status = double("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_good, :stderr => @stderr)
-
     # new singleton each time
     Chef::Provider::Package::Yum::YumCache.reset_instance
     @yc = Chef::Provider::Package::Yum::YumCache.instance
     # load valid data
+    @yc.yum_binary = "yum"
     allow(@yc).to receive(:shell_out!).and_return(@status)
+    allow_any_instance_of(described_class).to receive(:which).with("yum").and_return("/usr/bin/yum")
+    allow(::File).to receive(:open).with("/usr/bin/yum", "r") do |&block|
+      res = block.call(yum_exe)
+      # a bit of a hack. rewind this since it seem that no matter what
+      # I do, we get the same StringIO objects on multiple calls to
+      # ::File.open
+      yum_exe.rewind; res
+    end
   end
 
   describe "initialize" do
@@ -1726,6 +1831,30 @@ EOF
     end
   end
 
+  describe "python_bin" do
+    it "should return the default python if an error occurs" do
+      allow(::File).to receive(:open).with("/usr/bin/yum", "r").and_raise(StandardError)
+      expect(@yc.python_bin).to eq("/usr/bin/python")
+    end
+
+    it "should return the default python if the yum-executable doesn't start with #!" do
+      allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(bin_exe); bin_exe.rewind; r }
+      expect(@yc.python_bin).to eq("/usr/bin/python")
+    end
+
+    it "should return /usr/bin/python if the interpreter is /bin/bash" do
+      other = StringIO.new("#!/bin/bash\n# The yum executable redirecting to dnf from dnf-yum compatible package.")
+      allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r }
+      expect(@yc.python_bin).to eq("/usr/bin/python")
+    end
+
+    it "should return the interpreter for yum" do
+      other = StringIO.new("#!/usr/bin/super_python\n\nlasjdfdsaljf\nlasdjfs")
+      allow(::File).to receive(:open).with("/usr/bin/yum", "r") { |&b| r = b.call(other); other.rewind; r }
+      expect(@yc.python_bin).to eq("/usr/bin/super_python")
+    end
+  end
+
   describe "refresh" do
     it "should implicitly call yum-dump.py only once by default after being instantiated" do
       expect(@yc).to receive(:shell_out!).once
@@ -1736,32 +1865,32 @@ EOF
 
     it "should run yum-dump.py using the system python when next_refresh is for :all" do
       @yc.reload
-      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
       @yc.refresh
     end
 
     it "should run yum-dump.py with the installed flag when next_refresh is for :installed" do
       @yc.reload_installed
-      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --installed --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --installed --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
       @yc.refresh
     end
 
     it "should run yum-dump.py with the all-provides flag when next_refresh is for :provides" do
       @yc.reload_provides
-      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --all-provides --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --all-provides --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
       @yc.refresh
     end
 
     it "should pass extra_repo_control args to yum-dump.py" do
       @yc.enable_extra_repo_control("--enablerepo=foo --disablerepo=bar")
-      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 30$}, :timeout=>Chef::Config[:yum_timeout])
+      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 30$}, :timeout => Chef::Config[:yum_timeout])
       @yc.refresh
     end
 
     it "should pass extra_repo_control args and configured yum lock timeout to yum-dump.py" do
       Chef::Config[:yum_lock_timeout] = 999
       @yc.enable_extra_repo_control("--enablerepo=foo --disablerepo=bar")
-      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 999$}, :timeout=>Chef::Config[:yum_timeout])
+      expect(@yc).to receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar --yum-lock-timeout 999$}, :timeout => Chef::Config[:yum_timeout])
       @yc.refresh
     end
 
@@ -1789,7 +1918,7 @@ EOF
     it "should raise exception yum-dump.py exits with a non zero status" do
       @status = double("Status", :exitstatus => 1, :stdin => @stdin, :stdout => @stdout_no_output, :stderr => @stderr)
       allow(@yc).to receive(:shell_out!).and_return(@status)
-      expect { @yc.refresh}.to raise_error(Chef::Exceptions::Package, %r{CentOS-Base.repo, line: 12})
+      expect { @yc.refresh }.to raise_error(Chef::Exceptions::Package, %r{CentOS-Base.repo, line: 12})
     end
 
     it "should parse type 'i' into an installed state for a package" do
@@ -1984,21 +2113,23 @@ describe "Chef::Provider::Package::Yum - Multi" do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new(['cups', 'vim'])
+    @new_resource = Chef::Resource::Package.new(["cups", "vim"])
     @status = double("Status", :exitstatus => 0)
     @yum_cache = double(
-      'Chef::Provider::Yum::YumCache',
+      "Chef::Provider::Yum::YumCache",
       :reload_installed => true,
       :reset => true,
-      :installed_version => 'XXXX',
-      :candidate_version => 'YYYY',
+      :installed_version => "XXXX",
+      :candidate_version => "YYYY",
       :package_available? => true,
       :version_available? => true,
-      :allow_multi_install => [ 'kernel' ],
-      :package_repository => 'base',
-      :disable_extra_repo_control => true
+      :allow_multi_install => [ "kernel" ],
+      :package_repository => "base",
+      :disable_extra_repo_control => true,
     )
     allow(Chef::Provider::Package::Yum::YumCache).to receive(:instance).and_return(@yum_cache)
+    allow(@yum_cache).to receive(:yum_binary=).with("yum")
+    allow(@yum_cache).to receive(:yum_binary=).with("yum")
     @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
     @pid = double("PID")
   end
@@ -2006,12 +2137,12 @@ describe "Chef::Provider::Package::Yum - Multi" do
   describe "when loading the current system state" do
     it "should create a current resource with the name of the new_resource" do
       @provider.load_current_resource
-      expect(@provider.current_resource.name).to eq('cups, vim')
+      expect(@provider.current_resource.name).to eq("cups, vim")
     end
 
     it "should set the current resources package name to the new resources package name" do
       @provider.load_current_resource
-      expect(@provider.current_resource.package_name).to eq(['cups', 'vim'])
+      expect(@provider.current_resource.package_name).to eq(["cups", "vim"])
     end
 
     it "should set the installed version to nil on the current resource if no installed package" do
@@ -2021,38 +2152,68 @@ describe "Chef::Provider::Package::Yum - Multi" do
     end
 
     it "should set the installed version if yum has one" do
-      allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
-      allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0')
-      allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3')
-      allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5')
+      allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("1.0")
+      allow(@yum_cache).to receive(:candidate_version).with("cups", nil).and_return("1.2.4-11.18.el5_2.3")
+      allow(@yum_cache).to receive(:candidate_version).with("vim", nil).and_return("1.5")
       @provider.load_current_resource
-      expect(@provider.current_resource.version).to eq(['1.2.4-11.18.el5', '1.0'])
+      expect(@provider.current_resource.version).to eq(["1.2.4-11.18.el5", "1.0"])
     end
 
     it "should set the candidate version if yum info has one" do
-      allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
-      allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('1.0')
-      allow(@yum_cache).to receive(:candidate_version).with('cups', nil).and_return('1.2.4-11.18.el5_2.3')
-      allow(@yum_cache).to receive(:candidate_version).with('vim', nil).and_return('1.5')
+      allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("1.0")
+      allow(@yum_cache).to receive(:candidate_version).with("cups", nil).and_return("1.2.4-11.18.el5_2.3")
+      allow(@yum_cache).to receive(:candidate_version).with("vim", nil).and_return("1.5")
       @provider.load_current_resource
-      expect(@provider.candidate_version).to eql(['1.2.4-11.18.el5_2.3', '1.5'])
+      expect(@provider.candidate_version).to eql(["1.2.4-11.18.el5_2.3", "1.5"])
     end
 
     it "should return the current resouce" do
       expect(@provider.load_current_resource).to eql(@provider.current_resource)
     end
+
+    describe "when version constraint in package_name" do
+      it "should set package_version if no existing package_name is found and new_package_name is available" do
+        @new_resource = Chef::Resource::Package.new(["cups = 1.2.4-11.18.el5_2.3", "emacs = 24.4"])
+        @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+        allow(@yum_cache).to receive(:package_available?) { |pkg| %w{cups emacs}.include?(pkg) ? true : false }
+        allow(@yum_cache).to receive(:candidate_version) do |pkg|
+          if pkg == "cups"
+            "1.2.4-11.18.el5_2.3"
+          elsif pkg == "emacs"
+            "24.4"
+          end
+        end
+        allow(@yum_cache).to receive(:packages_from_require) do |pkg|
+          if pkg.name == "cups"
+            [Chef::Provider::Package::Yum::RPMDbPackage.new("cups", "1.2.4-11.18.el5_2.3", "noarch", [], false, true, "base")]
+          elsif pkg.name == "emacs"
+            [Chef::Provider::Package::Yum::RPMDbPackage.new("emacs", "24.4", "noarch", [], false, true, "base")]
+          end
+        end
+        expect(Chef::Log).to receive(:debug).exactly(2).times.with(%r{matched 1 package,})
+        expect(Chef::Log).to receive(:debug).exactly(1).times.with(%r{candidate version: \["1.2.4-11.18.el5_2.3", "24.4"\]})
+        expect(Chef::Log).to receive(:debug).at_least(2).times.with(%r{checking yum info})
+        @provider.load_current_resource
+        expect(@provider.new_resource.package_name).to eq(["cups", "emacs"])
+        expect(@provider.new_resource.version).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
+        expect(@provider.send(:package_name_array)).to eq(["cups", "emacs"])
+        expect(@provider.send(:new_version_array)).to eq(["1.2.4-11.18.el5_2.3", "24.4"])
+      end
+    end
   end
 
   describe "when installing a package" do
     it "should run yum install with the package name and version" do
       @provider.load_current_resource
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
-      allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
-      allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+      allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.19.el5 vim-1.0"
+        "-d0 -e0 -y install cups-1.2.4-11.19.el5 vim-1.0"
       )
-      @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+      @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"])
     end
 
     it "should run yum install with the package name, version and arch" do
@@ -2060,7 +2221,7 @@ describe "Chef::Provider::Package::Yum - Multi" do
       allow(@new_resource).to receive(:arch).and_return("i386")
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y install cups-1.2.4-11.19.el5.i386 vim-1.0.i386"
+        "-d0 -e0 -y install cups-1.2.4-11.19.el5.i386 vim-1.0.i386"
       )
       @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"])
     end
@@ -2068,13 +2229,39 @@ describe "Chef::Provider::Package::Yum - Multi" do
     it "installs the package with the options given in the resource" do
       @provider.load_current_resource
       allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
-      allow(@yum_cache).to receive(:installed_version).with('cups', nil).and_return('1.2.4-11.18.el5')
-      allow(@yum_cache).to receive(:installed_version).with('vim', nil).and_return('0.9')
+      allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
       expect(@provider).to receive(:yum_command).with(
-        "yum -d0 -e0 -y --disablerepo epmd install cups-1.2.4-11.19.el5 vim-1.0"
+        "-d0 -e0 -y --disablerepo epmd install cups-1.2.4-11.19.el5 vim-1.0"
       )
       allow(@new_resource).to receive(:options).and_return("--disablerepo epmd")
-      @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
+      @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"])
     end
+
+    it "should run yum install with the package name and version when name has arch" do
+      @new_resource = Chef::Resource::Package.new(["cups.x86_64", "vim"])
+      @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context)
+      allow(Chef::Provider::Package::Yum::RPMUtils).to receive(:rpmvercmp).and_return(-1)
+
+      # Inside of load_current_resource() we'll call parse_arch for cups,
+      # and we need to craft the right response. The default mock setup above
+      # will just return valid versions all the time which won't work for this
+      # test.
+      allow(@yum_cache).to receive(:installed_version).with("cups", "x86_64").and_return("XXXX")
+      allow(@yum_cache).to receive(:candidate_version).with("cups", "x86_64").and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("cups.x86_64").and_return(nil)
+      allow(@yum_cache).to receive(:candidate_version).with("cups.x86_64").and_return(nil)
+
+      # Normal mock's for the idempotency check
+      allow(@yum_cache).to receive(:installed_version).with("cups", nil).and_return("1.2.4-11.18.el5")
+      allow(@yum_cache).to receive(:installed_version).with("vim", nil).and_return("0.9")
+
+      @provider.load_current_resource
+      expect(@provider).to receive(:yum_command).with(
+        "-d0 -e0 -y install cups-1.2.4-11.19.el5.x86_64 vim-1.0"
+      )
+      @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", "1.0"])
+    end
+
   end
 end
diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb
index 706ad72..c998c93 100644
--- a/spec/unit/provider/package/zypper_spec.rb
+++ b/spec/unit/provider/package/zypper_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,129 +16,138 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package::Zypper do
+  let!(:new_resource) { Chef::Resource::ZypperPackage.new("cups") }
+
+  let!(:current_resource) { Chef::Resource::ZypperPackage.new("cups") }
+
+  let(:provider) do
+    node = Chef::Node.new
+    events = Chef::EventDispatch::Dispatcher.new
+    run_context = Chef::RunContext.new(node, {}, events)
+    Chef::Provider::Package::Zypper.new(new_resource, run_context)
+  end
+
+  let(:status) { double(:stdout => "\n", :exitstatus => 0) }
+
   before(:each) do
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new("cups")
-
-    @current_resource = Chef::Resource::Package.new("cups")
-
-    @provider = Chef::Provider::Package::Zypper.new(@new_resource, @run_context)
-    allow(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
-    @status = double(:stdout => "\n", :exitstatus => 0)
-    allow(@provider).to receive(:shell_out).and_return(@status)
-    allow(@provider).to receive(:`).and_return("2.0")
+    allow(Chef::Resource::Package).to receive(:new).and_return(current_resource)
+    allow(provider).to receive(:shell_out!).and_return(status)
+    allow(provider).to receive(:`).and_return("2.0")
+  end
+
+  def shell_out_expectation(command, options = nil)
+    options ||= { timeout: 900 }
+    expect(provider).to receive(:shell_out).with(command, options)
+  end
+
+  def shell_out_expectation!(command, options = nil)
+    options ||= { timeout: 900 }
+    expect(provider).to receive(:shell_out!).with(command, options)
   end
 
   describe "when loading the current package state" do
     it "should create a current resource with the name of the new_resource" do
-      expect(Chef::Resource::Package).to receive(:new).and_return(@current_resource)
-      @provider.load_current_resource
+      expect(Chef::Resource::Package).to receive(:new).with(new_resource.name).and_return(current_resource)
+      provider.load_current_resource
     end
 
     it "should set the current resources package name to the new resources package name" do
-      expect(@current_resource).to receive(:package_name).with(@new_resource.package_name)
-      @provider.load_current_resource
+      expect(current_resource).to receive(:package_name).with(new_resource.package_name)
+      provider.load_current_resource
     end
 
     it "should run zypper info with the package name" do
-      expect(@provider).to receive(:shell_out).with("zypper --non-interactive info #{@new_resource.package_name}").and_return(@status)
-      @provider.load_current_resource
+      shell_out_expectation!(
+        "zypper --non-interactive info #{new_resource.package_name}"
+      ).and_return(status)
+      provider.load_current_resource
     end
 
     it "should set the installed version to nil on the current resource if zypper info installed version is (none)" do
-      allow(@provider).to receive(:shell_out).and_return(@status)
-      expect(@current_resource).to receive(:version).with(nil).and_return(true)
-      @provider.load_current_resource
+      allow(provider).to receive(:shell_out).and_return(status)
+      expect(current_resource).to receive(:version).with([nil]).and_return(true)
+      provider.load_current_resource
     end
 
     it "should set the installed version if zypper info has one" do
       status = double(:stdout => "Version: 1.0\nInstalled: Yes\n", :exitstatus => 0)
 
-      allow(@provider).to receive(:shell_out).and_return(status)
-      expect(@current_resource).to receive(:version).with("1.0").and_return(true)
-      @provider.load_current_resource
+      allow(provider).to receive(:shell_out!).and_return(status)
+      expect(current_resource).to receive(:version).with(["1.0"]).and_return(true)
+      provider.load_current_resource
     end
 
     it "should set the candidate version if zypper info has one" do
       status = double(:stdout => "Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)", :exitstatus => 0)
 
-      allow(@provider).to receive(:shell_out).and_return(status)
-      @provider.load_current_resource
-      expect(@provider.candidate_version).to eql("1.0")
-    end
-
-    it "should raise an exception if zypper info fails" do
-      expect(@status).to receive(:exitstatus).and_return(1)
-      expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Package)
-    end
-
-    it "should not raise an exception if zypper info succeeds" do
-      expect(@status).to receive(:exitstatus).and_return(0)
-      expect { @provider.load_current_resource }.not_to raise_error
+      allow(provider).to receive(:shell_out!).and_return(status)
+      provider.load_current_resource
+      expect(provider.candidate_version).to eql(["1.0"])
     end
 
     it "should return the current resouce" do
-      expect(@provider.load_current_resource).to eql(@current_resource)
+      expect(provider.load_current_resource).to eql(current_resource)
     end
   end
 
   describe "install_package" do
     it "should run zypper install with the package name and version" do
       allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0")
-      @provider.install_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+      )
+      provider.install_package(["emacs"], ["1.0"])
     end
     it "should run zypper install without gpg checks" do
       allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks install "+
-        "--auto-agree-with-licenses emacs=1.0")
-      @provider.install_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0"
+      )
+      provider.install_package(["emacs"], ["1.0"])
     end
     it "should warn about gpg checks on zypper install" do
       expect(Chef::Log).to receive(:warn).with(
-        /All packages will be installed without gpg signature checks/)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks install "+
-        "--auto-agree-with-licenses emacs=1.0")
-      @provider.install_package("emacs", "1.0")
+        /All packages will be installed without gpg signature checks/
+      )
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0"
+      )
+      provider.install_package(["emacs"], ["1.0"])
     end
   end
 
   describe "upgrade_package" do
     it "should run zypper update with the package name and version" do
       allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0")
-      @provider.upgrade_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0"
+      )
+      provider.upgrade_package(["emacs"], ["1.0"])
     end
     it "should run zypper update without gpg checks" do
       allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks install "+
-        "--auto-agree-with-licenses emacs=1.0")
-      @provider.upgrade_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0"
+      )
+      provider.upgrade_package(["emacs"], ["1.0"])
     end
     it "should warn about gpg checks on zypper upgrade" do
       expect(Chef::Log).to receive(:warn).with(
-        /All packages will be installed without gpg signature checks/)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks install "+
-        "--auto-agree-with-licenses emacs=1.0")
-      @provider.upgrade_package("emacs", "1.0")
+        /All packages will be installed without gpg signature checks/
+      )
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0"
+      )
+      provider.upgrade_package(["emacs"], ["1.0"])
     end
     it "should run zypper upgrade without gpg checks" do
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks install "+
-        "--auto-agree-with-licenses emacs=1.0")
-
-      @provider.upgrade_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0"
+      )
+      provider.upgrade_package(["emacs"], ["1.0"])
     end
   end
 
@@ -147,84 +156,113 @@ describe Chef::Provider::Package::Zypper do
     context "when package version is not explicitly specified" do
       it "should run zypper remove with the package name" do
         allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
-        expect(@provider).to receive(:shell_out!).with(
-            "zypper --non-interactive remove emacs")
-        @provider.remove_package("emacs", nil)
+        shell_out_expectation!(
+            "zypper --non-interactive remove emacs"
+        )
+        provider.remove_package(["emacs"], [nil])
       end
     end
 
     context "when package version is explicitly specified" do
       it "should run zypper remove with the package name" do
         allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(true)
-        expect(@provider).to receive(:shell_out!).with(
-          "zypper --non-interactive remove emacs=1.0")
-        @provider.remove_package("emacs", "1.0")
+        shell_out_expectation!(
+          "zypper --non-interactive remove emacs=1.0"
+        )
+        provider.remove_package(["emacs"], ["1.0"])
       end
       it "should run zypper remove without gpg checks" do
         allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
-        expect(@provider).to receive(:shell_out!).with(
-            "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
-        @provider.remove_package("emacs", "1.0")
+        shell_out_expectation!(
+            "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+        )
+        provider.remove_package(["emacs"], ["1.0"])
       end
       it "should warn about gpg checks on zypper remove" do
         expect(Chef::Log).to receive(:warn).with(
-          /All packages will be installed without gpg signature checks/)
-        expect(@provider).to receive(:shell_out!).with(
-          "zypper --non-interactive --no-gpg-checks remove emacs=1.0")
-
-        @provider.remove_package("emacs", "1.0")
+          /All packages will be installed without gpg signature checks/
+        )
+        shell_out_expectation!(
+          "zypper --non-interactive --no-gpg-checks remove emacs=1.0"
+        )
+        provider.remove_package(["emacs"], ["1.0"])
       end
     end
   end
 
   describe "purge_package" do
-    it "should run remove_package with the name and version" do
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
-      @provider.purge_package("emacs", "1.0")
+    it "should run remove with the name and version and --clean-deps" do
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+      )
+      provider.purge_package(["emacs"], ["1.0"])
     end
     it "should run zypper purge without gpg checks" do
       allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
-      @provider.purge_package("emacs", "1.0")
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+      )
+      provider.purge_package(["emacs"], ["1.0"])
     end
     it "should warn about gpg checks on zypper purge" do
       expect(Chef::Log).to receive(:warn).with(
-        /All packages will be installed without gpg signature checks/)
-      expect(@provider).to receive(:shell_out!).with(
-        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0")
-      @provider.purge_package("emacs", "1.0")
+        /All packages will be installed without gpg signature checks/
+      )
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0"
+      )
+      provider.purge_package(["emacs"], ["1.0"])
     end
   end
 
   describe "on an older zypper" do
     before(:each) do
-      allow(@provider).to receive(:`).and_return("0.11.6")
+      allow(provider).to receive(:`).and_return("0.11.6")
     end
 
     describe "install_package" do
       it "should run zypper install with the package name and version" do
-        expect(@provider).to receive(:shell_out!).with(
-          "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs")
-        @provider.install_package("emacs", "1.0")
+        shell_out_expectation!(
+          "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+        )
+        provider.install_package(["emacs"], ["1.0"])
       end
     end
 
     describe "upgrade_package" do
       it "should run zypper update with the package name and version" do
-        expect(@provider).to receive(:shell_out!).with(
-          "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs")
-        @provider.upgrade_package("emacs", "1.0")
+        shell_out_expectation!(
+          "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs"
+        )
+        provider.upgrade_package(["emacs"], ["1.0"])
       end
     end
 
     describe "remove_package" do
       it "should run zypper remove with the package name" do
-        expect(@provider).to receive(:shell_out!).with(
-           "zypper --no-gpg-checks remove -y emacs")
-        @provider.remove_package("emacs", "1.0")
+        shell_out_expectation!(
+           "zypper --no-gpg-checks remove -y emacs"
+        )
+        provider.remove_package(["emacs"], ["1.0"])
       end
     end
   end
+
+  describe "when installing multiple packages" do # https://github.com/chef/chef/issues/3570
+    it "should install an array of package names and versions" do
+      allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks install " + "--auto-agree-with-licenses emacs=1.0 vim=2.0"
+      )
+      provider.install_package(["emacs", "vim"], ["1.0", "2.0"])
+    end
+
+    it "should remove an array of package names and versions" do
+      allow(Chef::Config).to receive(:[]).with(:zypper_check_gpg).and_return(false)
+      shell_out_expectation!(
+        "zypper --non-interactive --no-gpg-checks remove emacs=1.0 vim=2.0"
+      )
+      provider.remove_package(["emacs", "vim"], ["1.0", "2.0"])
+    end
+  end
 end
diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb
index 1633d18..50016c6 100644
--- a/spec/unit/provider/package_spec.rb
+++ b/spec/unit/provider/package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,409 +16,417 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Package do
-  before do
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new('emacs')
-    @current_resource = Chef::Resource::Package.new('emacs')
-    @provider = Chef::Provider::Package.new(@new_resource, @run_context)
-    @provider.current_resource = @current_resource
-
-    @provider.candidate_version = "1.0"
+  let(:node) do
+    node = Chef::Node.new
+    node.automatic_attrs[:platform] = :just_testing
+    node.automatic_attrs[:platform_version] = :just_testing
+    node
+  end
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:new_resource) { Chef::Resource::Package.new("emacs") }
+  let(:current_resource) { Chef::Resource::Package.new("emacs") }
+  let(:candidate_version) { "1.0" }
+  let(:provider) do
+    provider = Chef::Provider::Package.new(new_resource, run_context)
+    provider.current_resource = current_resource
+    provider.candidate_version = candidate_version
+    provider
   end
 
   describe "when installing a package" do
     before(:each) do
-      @provider.current_resource = @current_resource
-      allow(@provider).to receive(:install_package).and_return(true)
+      provider.current_resource = current_resource
+      allow(provider).to receive(:install_package).and_return(true)
+    end
+
+    it "raises a Chef::Exceptions::InvalidResourceSpecification if both multipackage and source are provided" do
+      new_resource.package_name(["a", "b"])
+      new_resource.source("foo")
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
     end
 
     it "should raise a Chef::Exceptions::Package if no version is specified, and no candidate is available" do
-      @provider.candidate_version = nil
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      provider.candidate_version = nil
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "should call preseed_package if a response_file is given" do
-      @new_resource.response_file("foo")
-      expect(@provider).to receive(:get_preseed_file).with(
-        @new_resource.name,
-        @provider.candidate_version
+      new_resource.response_file("foo")
+      expect(provider).to receive(:get_preseed_file).with(
+        new_resource.name,
+        provider.candidate_version,
       ).and_return("/var/cache/preseed-test")
 
-      expect(@provider).to receive(:preseed_package).with(
+      expect(provider).to receive(:preseed_package).with(
         "/var/cache/preseed-test"
       ).and_return(true)
-      @provider.run_action(:install)
+      provider.run_action(:install)
     end
 
     it "should not call preseed_package if a response_file is not given" do
-      expect(@provider).not_to receive(:preseed_package)
-      @provider.run_action(:install)
+      expect(provider).not_to receive(:preseed_package)
+      provider.run_action(:install)
     end
 
     it "should install the package at the candidate_version if it is not already installed" do
-      expect(@provider).to receive(:install_package).with(
-        @new_resource.name,
-        @provider.candidate_version
+      expect(provider).to receive(:install_package).with(
+        new_resource.name,
+        provider.candidate_version,
       ).and_return(true)
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should install the package at the version specified if it is not already installed" do
-      @new_resource.version("1.0")
-      expect(@provider).to receive(:install_package).with(
-        @new_resource.name,
-        @new_resource.version
+      new_resource.version("1.0")
+      expect(provider).to receive(:install_package).with(
+        new_resource.name,
+        new_resource.version,
       ).and_return(true)
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should install the package at the version specified if a different version is installed" do
-      @new_resource.version("1.0")
-      allow(@current_resource).to receive(:version).and_return("0.99")
-      expect(@provider).to receive(:install_package).with(
-        @new_resource.name,
-        @new_resource.version
+      new_resource.version("1.0")
+      allow(current_resource).to receive(:version).and_return("0.99")
+      expect(provider).to receive(:install_package).with(
+        new_resource.name,
+        new_resource.version,
       ).and_return(true)
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:install)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not install the package if it is already installed and no version is specified" do
-      @current_resource.version("1.0")
-      expect(@provider).not_to receive(:install_package)
-      @provider.run_action(:install)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version("1.0")
+      expect(provider).not_to receive(:install_package)
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should not install the package if it is already installed at the version specified" do
-      @current_resource.version("1.0")
-      @new_resource.version("1.0")
-      expect(@provider).not_to receive(:install_package)
-      @provider.run_action(:install)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version("1.0")
+      new_resource.version("1.0")
+      expect(provider).not_to receive(:install_package)
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should call the candidate_version accessor only once if the package is already installed and no version is specified" do
-      @current_resource.version("1.0")
-      allow(@provider).to receive(:candidate_version).and_return("1.0")
-      @provider.run_action(:install)
+      current_resource.version("1.0")
+      allow(provider).to receive(:candidate_version).and_return("1.0")
+      provider.run_action(:install)
     end
 
     it "should call the candidate_version accessor only once if the package is already installed at the version specified" do
-      @current_resource.version("1.0")
-      @new_resource.version("1.0")
-      @provider.run_action(:install)
+      current_resource.version("1.0")
+      new_resource.version("1.0")
+      provider.run_action(:install)
     end
 
     it "should set the resource to updated if it installs the package" do
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated
+      provider.run_action(:install)
+      expect(new_resource).to be_updated
     end
 
   end
 
   describe "when upgrading the package" do
     before(:each) do
-      allow(@provider).to receive(:upgrade_package).and_return(true)
+      allow(provider).to receive(:upgrade_package).and_return(true)
     end
 
     it "should upgrade the package if the current version is not the candidate version" do
-      expect(@provider).to receive(:upgrade_package).with(
-        @new_resource.name,
-        @provider.candidate_version
+      expect(provider).to receive(:upgrade_package).with(
+        new_resource.name,
+        provider.candidate_version,
       ).and_return(true)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should set the resource to updated if it installs the package" do
-      @provider.run_action(:upgrade)
-      expect(@new_resource).to be_updated
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated
     end
 
     it "should not install the package if the current version is the candidate version" do
-      @current_resource.version "1.0"
-      expect(@provider).not_to receive(:upgrade_package)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version "1.0"
+      expect(provider).not_to receive(:upgrade_package)
+      provider.run_action(:upgrade)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should print the word 'uninstalled' if there was no original version" do
-      allow(@current_resource).to receive(:version).and_return(nil)
+      allow(current_resource).to receive(:version).and_return(nil)
       expect(Chef::Log).to receive(:info).with("package[emacs] upgraded emacs to 1.0")
-      @provider.run_action(:upgrade)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should raise a Chef::Exceptions::Package if current version and candidate are nil" do
-      allow(@current_resource).to receive(:version).and_return(nil)
-      @provider.candidate_version = nil
-      expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+      allow(current_resource).to receive(:version).and_return(nil)
+      provider.candidate_version = nil
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "should not install the package if candidate version is nil" do
-      @current_resource.version "1.0"
-      @provider.candidate_version = nil
-      expect(@provider).not_to receive(:upgrade_package)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version "1.0"
+      provider.candidate_version = nil
+      expect(provider).not_to receive(:upgrade_package)
+      provider.run_action(:upgrade)
+      expect(new_resource).not_to be_updated_by_last_action
     end
   end
 
   describe "When removing the package" do
     before(:each) do
-      allow(@provider).to receive(:remove_package).and_return(true)
-      @current_resource.version '1.4.2'
+      allow(provider).to receive(:remove_package).and_return(true)
+      current_resource.version "1.4.2"
     end
 
     it "should remove the package if it is installed" do
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with('emacs', nil)
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with("emacs", nil)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should remove the package at a specific version if it is installed at that version" do
-      @new_resource.version "1.4.2"
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with('emacs', '1.4.2')
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version "1.4.2"
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with("emacs", "1.4.2")
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not remove the package at a specific version if it is not installed at that version" do
-      @new_resource.version "1.0"
-      expect(@provider).not_to be_removing_package
-      expect(@provider).not_to receive(:remove_package)
-      @provider.run_action(:remove)
-      expect(@new_resource).not_to be_updated_by_last_action
+      new_resource.version "1.0"
+      expect(provider).not_to be_removing_package
+      expect(provider).not_to receive(:remove_package)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should not remove the package if it is not installed" do
-      expect(@provider).not_to receive(:remove_package)
-      allow(@current_resource).to receive(:version).and_return(nil)
-      @provider.run_action(:remove)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:remove_package)
+      allow(current_resource).to receive(:version).and_return(nil)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should set the resource to updated if it removes the package" do
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated
     end
 
   end
 
   describe "When purging the package" do
     before(:each) do
-      allow(@provider).to receive(:purge_package).and_return(true)
-      @current_resource.version '1.4.2'
+      allow(provider).to receive(:purge_package).and_return(true)
+      current_resource.version "1.4.2"
     end
 
     it "should purge the package if it is installed" do
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with('emacs', nil)
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with("emacs", nil)
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should purge the package at a specific version if it is installed at that version" do
-      @new_resource.version "1.4.2"
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with('emacs', '1.4.2')
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version "1.4.2"
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with("emacs", "1.4.2")
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not purge the package at a specific version if it is not installed at that version" do
-      @new_resource.version "1.0"
-      expect(@provider).not_to be_removing_package
-      expect(@provider).not_to receive(:purge_package)
-      @provider.run_action(:purge)
-      expect(@new_resource).not_to be_updated_by_last_action
+      new_resource.version "1.0"
+      expect(provider).not_to be_removing_package
+      expect(provider).not_to receive(:purge_package)
+      provider.run_action(:purge)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should not purge the package if it is not installed" do
-      @current_resource.instance_variable_set(:@version, nil)
-      expect(@provider).not_to be_removing_package
+      current_resource.instance_variable_set(:@version, nil)
+      expect(provider).not_to be_removing_package
 
-      expect(@provider).not_to receive(:purge_package)
-      @provider.run_action(:purge)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:purge_package)
+      provider.run_action(:purge)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should set the resource to updated if it purges the package" do
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated
     end
 
   end
 
   describe "when reconfiguring the package" do
     before(:each) do
-      allow(@provider).to receive(:reconfig_package).and_return(true)
+      allow(provider).to receive(:reconfig_package).and_return(true)
     end
 
     it "should info log, reconfigure the package and update the resource" do
-      allow(@current_resource).to receive(:version).and_return('1.0')
-      allow(@new_resource).to receive(:response_file).and_return(true)
-      expect(@provider).to receive(:get_preseed_file).and_return('/var/cache/preseed-test')
-      allow(@provider).to receive(:preseed_package).and_return(true)
-      allow(@provider).to receive(:reconfig_package).and_return(true)
+      allow(current_resource).to receive(:version).and_return("1.0")
+      allow(new_resource).to receive(:response_file).and_return(true)
+      expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test")
+      allow(provider).to receive(:preseed_package).and_return(true)
+      allow(provider).to receive(:reconfig_package).and_return(true)
       expect(Chef::Log).to receive(:info).with("package[emacs] reconfigured")
-      expect(@provider).to receive(:reconfig_package)
-      @provider.run_action(:reconfig)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      expect(provider).to receive(:reconfig_package)
+      provider.run_action(:reconfig)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should debug log and not reconfigure the package if the package is not installed" do
-      allow(@current_resource).to receive(:version).and_return(nil)
+      allow(current_resource).to receive(:version).and_return(nil)
       expect(Chef::Log).to receive(:debug).with("package[emacs] is NOT installed - nothing to do")
-      expect(@provider).not_to receive(:reconfig_package)
-      @provider.run_action(:reconfig)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:reconfig_package)
+      provider.run_action(:reconfig)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should debug log and not reconfigure the package if no response_file is given" do
-      allow(@current_resource).to receive(:version).and_return('1.0')
-      allow(@new_resource).to receive(:response_file).and_return(nil)
+      allow(current_resource).to receive(:version).and_return("1.0")
+      allow(new_resource).to receive(:response_file).and_return(nil)
       expect(Chef::Log).to receive(:debug).with("package[emacs] no response_file provided - nothing to do")
-      expect(@provider).not_to receive(:reconfig_package)
-      @provider.run_action(:reconfig)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:reconfig_package)
+      provider.run_action(:reconfig)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should debug log and not reconfigure the package if the response_file has not changed" do
-      allow(@current_resource).to receive(:version).and_return('1.0')
-      allow(@new_resource).to receive(:response_file).and_return(true)
-      expect(@provider).to receive(:get_preseed_file).and_return(false)
-      allow(@provider).to receive(:preseed_package).and_return(false)
+      allow(current_resource).to receive(:version).and_return("1.0")
+      allow(new_resource).to receive(:response_file).and_return(true)
+      expect(provider).to receive(:get_preseed_file).and_return(false)
+      allow(provider).to receive(:preseed_package).and_return(false)
       expect(Chef::Log).to receive(:debug).with("package[emacs] preseeding has not changed - nothing to do")
-      expect(@provider).not_to receive(:reconfig_package)
-      @provider.run_action(:reconfig)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:reconfig_package)
+      provider.run_action(:reconfig)
+      expect(new_resource).not_to be_updated_by_last_action
     end
   end
 
   describe "when running commands to be implemented by subclasses" do
     it "should raises UnsupportedAction for install" do
-      expect { @provider.install_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.install_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
 
     it "should raises UnsupportedAction for upgrade" do
-      expect { @provider.upgrade_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.upgrade_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
 
     it "should raises UnsupportedAction for remove" do
-      expect { @provider.remove_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.remove_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
 
     it "should raises UnsupportedAction for purge" do
-      expect { @provider.purge_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.purge_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
 
     it "should raise UnsupportedAction for preseed_package" do
       preseed_file = "/tmp/sun-jdk-package-preseed-file.seed"
-      expect { @provider.preseed_package(preseed_file) }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.preseed_package(preseed_file) }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
 
     it "should raise UnsupportedAction for reconfig" do
-      expect { @provider.reconfig_package('emacs', '1.4.2') }.to raise_error(Chef::Exceptions::UnsupportedAction)
+      expect { provider.reconfig_package("emacs", "1.4.2") }.to raise_error(Chef::Exceptions::UnsupportedAction)
     end
   end
 
   describe "when given a response file" do
-    before(:each) do
-      @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
-      Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
-
-      @node = Chef::Node.new
-      cl = Chef::CookbookLoader.new(@cookbook_repo)
-      cl.load_cookbooks
-      @cookbook_collection = Chef::CookbookCollection.new(cl)
-
-      @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
-      @provider.run_context = @run_context
-
-      @node.automatic_attrs[:platform] = 'PLATFORM: just testing'
-      @node.automatic_attrs[:platform_version] = 'PLATFORM VERSION: just testing'
-
-      @new_resource.response_file('java.response')
-      @new_resource.cookbook_name = 'java'
+    let(:cookbook_repo) { File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) }
+    let(:cookbook_loader) do
+      Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo)
+      Chef::CookbookLoader.new(cookbook_repo)
+    end
+    let(:cookbook_collection) do
+      cookbook_loader.load_cookbooks
+      Chef::CookbookCollection.new(cookbook_loader)
+    end
+    let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
+    let(:new_resource) do
+      new_resource = Chef::Resource::Package.new("emacs")
+      new_resource.response_file("java.response")
+      new_resource.cookbook_name = "java"
+      new_resource
     end
 
     describe "creating the cookbook file resource to fetch the response file" do
       before do
-        expect(Chef::FileCache).to receive(:create_cache_path).with('preseed/java').and_return("/tmp/preseed/java")
+        expect(Chef::FileCache).to receive(:create_cache_path).with("preseed/java").and_return("/tmp/preseed/java")
       end
 
       it "sets the preseed resource's runcontext to its own run context" do
         allow(Chef::FileCache).to receive(:create_cache_path).and_return("/tmp/preseed/java")
-        expect(@provider.preseed_resource('java', '6').run_context).not_to be_nil
-        expect(@provider.preseed_resource('java', '6').run_context).to equal(@provider.run_context)
+        expect(provider.preseed_resource("java", "6").run_context).not_to be_nil
+        expect(provider.preseed_resource("java", "6").run_context).to equal(provider.run_context)
       end
 
       it "should set the cookbook name of the remote file to the new resources cookbook name" do
-        expect(@provider.preseed_resource('java', '6').cookbook_name).to eq('java')
+        expect(provider.preseed_resource("java", "6").cookbook_name).to eq("java")
       end
 
       it "should set remote files source to the new resources response file" do
-        expect(@provider.preseed_resource('java', '6').source).to eq('java.response')
+        expect(provider.preseed_resource("java", "6").source).to eq("java.response")
       end
 
       it "should never back up the cached response file" do
-        expect(@provider.preseed_resource('java', '6').backup).to be_falsey
+        expect(provider.preseed_resource("java", "6").backup).to be_falsey
       end
 
       it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do
-        expect(@provider.preseed_resource('java', '6').path).to eq('/tmp/preseed/java/java-6.seed')
+        expect(provider.preseed_resource("java", "6").path).to eq("/tmp/preseed/java/java-6.seed")
       end
     end
 
     describe "when installing the preseed file to the cache location" do
-      before do
-        @node.automatic_attrs[:platform] = :just_testing
-        @node.automatic_attrs[:platform_version] = :just_testing
+      let(:response_file_destination) { Dir.tmpdir + "/preseed--java--java-6.seed" }
+      let(:response_file_resource) {
+        response_file_resource = Chef::Resource::CookbookFile.new(response_file_destination, run_context)
+        response_file_resource.cookbook_name = "java"
+        response_file_resource.backup(false)
+        response_file_resource.source("java.response")
+        response_file_resource
+      }
 
-        @response_file_destination = Dir.tmpdir + '/preseed--java--java-6.seed'
-
-        @response_file_resource = Chef::Resource::CookbookFile.new(@response_file_destination, @run_context)
-        @response_file_resource.cookbook_name = 'java'
-        @response_file_resource.backup(false)
-        @response_file_resource.source('java.response')
-
-
-        expect(@provider).to receive(:preseed_resource).with('java', '6').and_return(@response_file_resource)
+      before do
+        expect(provider).to receive(:preseed_resource).with("java", "6").and_return(response_file_resource)
       end
 
       after do
-        FileUtils.rm(@response_file_destination) if ::File.exist?(@response_file_destination)
+        FileUtils.rm(response_file_destination) if ::File.exist?(response_file_destination)
       end
 
       it "creates the preseed file in the cache" do
-        expect(@response_file_resource).to receive(:run_action).with(:create)
-        @provider.get_preseed_file("java", "6")
+        expect(response_file_resource).to receive(:run_action).with(:create)
+        provider.get_preseed_file("java", "6")
       end
 
       it "returns the path to the response file if the response file was updated" do
-        expect(@provider.get_preseed_file("java", "6")).to eq(@response_file_destination)
+        expect(provider.get_preseed_file("java", "6")).to eq(response_file_destination)
       end
 
       it "should return false if the response file has not been updated" do
-        @response_file_resource.updated_by_last_action(false)
-        expect(@response_file_resource).not_to be_updated_by_last_action
+        response_file_resource.updated_by_last_action(false)
+        expect(response_file_resource).not_to be_updated_by_last_action
         # don't let the response_file_resource set updated to true
-        expect(@response_file_resource).to receive(:run_action).with(:create)
-        expect(@provider.get_preseed_file("java", "6")).to be(false)
+        expect(response_file_resource).to receive(:run_action).with(:create)
+        expect(provider.get_preseed_file("java", "6")).to be(false)
       end
 
     end
@@ -426,276 +434,437 @@ describe Chef::Provider::Package do
   end
 end
 
+describe "Subclass with use_multipackage_api" do
+  class MyPackageResource < Chef::Resource::Package
+  end
+
+  class MyPackageProvider < Chef::Provider::Package
+    use_multipackage_api
+  end
+
+  let(:node) { Chef::Node.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:new_resource) { MyPackageResource.new("installs the packages") }
+  let(:current_resource) { MyPackageResource.new("installs the packages") }
+  let(:provider) do
+    provider = MyPackageProvider.new(new_resource, run_context)
+    provider.current_resource = current_resource
+    provider
+  end
+
+  it "has use_multipackage_api? methods on the class and instance" do
+    expect(MyPackageProvider.use_multipackage_api?).to be true
+    expect(provider.use_multipackage_api?).to be true
+  end
+
+  it "offers a_to_s to subclasses to convert an array of strings to a single string" do
+    expect(provider.send(:a_to_s, "a", nil, "b", "", "c", " ", "d e", "f-g")).to eq("a b c   d e f-g")
+  end
+
+  it "when user passes string to package_name, passes arrays to install_package" do
+    new_resource.package_name "vim"
+    new_resource.version nil
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:install_package).with(
+      [ "vim" ],
+      [ "1.0" ],
+    ).and_return(true)
+    provider.run_action(:install)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql(nil)
+  end
+
+  it "when user pases string to package_name and version, passes arrays to install_package" do
+    new_resource.package_name "vim"
+    new_resource.version "1.0"
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:install_package).with(
+      [ "vim" ],
+      [ "1.0" ],
+    ).and_return(true)
+    provider.run_action(:install)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql("1.0")
+  end
+
+  it "when user passes string to package_name, passes arrays to upgrade_package" do
+    new_resource.package_name "vim"
+    new_resource.version nil
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:upgrade_package).with(
+      [ "vim" ],
+      [ "1.0" ],
+    ).and_return(true)
+    provider.run_action(:upgrade)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql(nil)
+  end
+
+  it "when user pases string to package_name and version, passes arrays to upgrade_package" do
+    new_resource.package_name "vim"
+    new_resource.version "1.0"
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:upgrade_package).with(
+      [ "vim" ],
+      [ "1.0" ],
+    ).and_return(true)
+    provider.run_action(:upgrade)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql("1.0")
+  end
+
+  it "when user passes string to package_name, passes arrays to remove_package" do
+    new_resource.package_name "vim"
+    current_resource.package_name "vim"
+    current_resource.version [ "1.0" ]
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:remove_package).with(
+      [ "vim" ],
+      [ nil ],
+    ).and_return(true)
+    provider.run_action(:remove)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql(nil)
+  end
+
+  it "when user passes string to package_name, passes arrays to purge_package" do
+    new_resource.package_name "vim"
+    current_resource.package_name "vim"
+    current_resource.version [ "1.0" ]
+    provider.candidate_version = [ "1.0" ]
+    expect(provider).to receive(:purge_package).with(
+      [ "vim" ],
+      [ nil ],
+    ).and_return(true)
+    provider.run_action(:purge)
+    expect(new_resource).to be_updated_by_last_action
+    expect(new_resource.version).to eql(nil)
+  end
+
+  it "when user passes string to package_name, passes arrays to reconfig_package" do
+    new_resource.package_name "vim"
+    current_resource.package_name "vim"
+    current_resource.version [ "1.0" ]
+    allow(new_resource).to receive(:response_file).and_return(true)
+    expect(provider).to receive(:get_preseed_file).and_return("/var/cache/preseed-test")
+    allow(provider).to receive(:preseed_package).and_return(true)
+    allow(provider).to receive(:reconfig_package).and_return(true)
+    expect(provider).to receive(:reconfig_package).with(
+      [ "vim" ],
+      [ "1.0" ],
+    ).and_return(true)
+    provider.run_action(:reconfig)
+    expect(new_resource).to be_updated_by_last_action
+  end
+end
+
 describe "Chef::Provider::Package - Multi" do
-  before do
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::Package.new(['emacs', 'vi'])
-    @current_resource = Chef::Resource::Package.new(['emacs', 'vi'])
-    @provider = Chef::Provider::Package.new(@new_resource, @run_context)
-    @provider.current_resource = @current_resource
-    @provider.candidate_version = ['1.0', '6.2']
+  let(:node) { Chef::Node.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, {}, events) }
+  let(:new_resource) { Chef::Resource::Package.new(["emacs", "vi"]) }
+  let(:current_resource) { Chef::Resource::Package.new(["emacs", "vi"]) }
+  let(:candidate_version) { [ "1.0", "6.2" ] }
+  let(:provider) do
+    provider = Chef::Provider::Package.new(new_resource, run_context)
+    provider.current_resource = current_resource
+    provider.candidate_version = candidate_version
+    provider
   end
 
   describe "when installing multiple packages" do
     before(:each) do
-      @provider.current_resource = @current_resource
-      allow(@provider).to receive(:install_package).and_return(true)
+      provider.current_resource = current_resource
+      allow(provider).to receive(:install_package).and_return(true)
     end
 
     it "installs the candidate versions when none are installed" do
-      expect(@provider).to receive(:install_package).with(
+      expect(provider).to receive(:install_package).with(
         ["emacs", "vi"],
-        ["1.0", "6.2"]
+        ["1.0", "6.2"],
       ).and_return(true)
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated
+      provider.run_action(:install)
+      expect(new_resource).to be_updated
     end
 
     it "installs the candidate versions when some are installed" do
-      expect(@provider).to receive(:install_package).with(
-        [ 'vi' ],
-        [ '6.2' ]
+      expect(provider).to receive(:install_package).with(
+        [ "vi" ],
+        [ "6.2" ],
       ).and_return(true)
-      @current_resource.version(['1.0', nil])
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated
+      current_resource.version(["1.0", nil])
+      provider.run_action(:install)
+      expect(new_resource).to be_updated
     end
 
     it "installs the specified version when some are out of date" do
-      @current_resource.version(['1.0', '6.2'])
-      @new_resource.version(['1.0', '6.1'])
-      @provider.run_action(:install)
-      expect(@new_resource).to be_updated
+      current_resource.version(["1.0", "6.2"])
+      new_resource.version(["1.0", "6.1"])
+      provider.run_action(:install)
+      expect(new_resource).to be_updated
     end
 
     it "does not install any version if all are installed at the right version" do
-      @current_resource.version(['1.0', '6.2'])
-      @new_resource.version(['1.0', '6.2'])
-      @provider.run_action(:install)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version(["1.0", "6.2"])
+      new_resource.version(["1.0", "6.2"])
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "does not install any version if all are installed, and no version was specified" do
-      @current_resource.version(['1.0', '6.2'])
-      @provider.run_action(:install)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version(["1.0", "6.2"])
+      provider.run_action(:install)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "raises an exception if both are not installed and no caondidates are available" do
-      @current_resource.version([nil, nil])
-      @provider.candidate_version = [nil, nil]
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      current_resource.version([nil, nil])
+      provider.candidate_version = [nil, nil]
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "raises an exception if one is not installed and no candidates are available" do
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = ['1.0', nil]
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = ["1.0", nil]
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "does not raise an exception if the packages are installed or have a candidate" do
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = [nil, '6.2']
-      expect { @provider.run_action(:install) }.not_to raise_error
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = [nil, "6.2"]
+      expect { provider.run_action(:install) }.not_to raise_error
     end
 
     it "raises an exception if an explicit version is asked for, an old version is installed, but no candidate" do
-      @new_resource.version ['1.0', '6.2']
-      @current_resource.version(['1.0', '6.1'])
-      @provider.candidate_version = ['1.0', nil]
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      new_resource.version ["1.0", "6.2"]
+      current_resource.version(["1.0", "6.1"])
+      provider.candidate_version = ["1.0", nil]
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "does not raise an exception if an explicit version is asked for, and is installed, but no candidate" do
-      @new_resource.version ['1.0', '6.2']
-      @current_resource.version(['1.0', '6.2'])
-      @provider.candidate_version = ['1.0', nil]
-      expect { @provider.run_action(:install) }.not_to raise_error
+      new_resource.version ["1.0", "6.2"]
+      current_resource.version(["1.0", "6.2"])
+      provider.candidate_version = ["1.0", nil]
+      expect { provider.run_action(:install) }.not_to raise_error
     end
 
     it "raise an exception if an explicit version is asked for, and is not installed, and no candidate" do
-      @new_resource.version ['1.0', '6.2']
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = ['1.0', nil]
-      expect { @provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
+      new_resource.version ["1.0", "6.2"]
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = ["1.0", nil]
+      expect { provider.run_action(:install) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "does not raise an exception if an explicit version is asked for, and is not installed, and there is a candidate" do
-      @new_resource.version ['1.0', '6.2']
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = ['1.0', '6.2']
-      expect { @provider.run_action(:install) }.not_to raise_error
+      new_resource.version ["1.0", "6.2"]
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = ["1.0", "6.2"]
+      expect { provider.run_action(:install) }.not_to raise_error
     end
   end
 
   describe "when upgrading multiple packages" do
     before(:each) do
-      @provider.current_resource = @current_resource
-      allow(@provider).to receive(:upgrade_package).and_return(true)
+      provider.current_resource = current_resource
+      allow(provider).to receive(:upgrade_package).and_return(true)
     end
 
     it "should upgrade the package if the current versions are not the candidate version" do
-      @current_resource.version ['0.9', '6.1']
-      expect(@provider).to receive(:upgrade_package).with(
-        @new_resource.package_name,
-        @provider.candidate_version
+      current_resource.version ["0.9", "6.1"]
+      expect(provider).to receive(:upgrade_package).with(
+        new_resource.package_name,
+        provider.candidate_version,
       ).and_return(true)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should upgrade the package if some of current versions are not the candidate versions" do
-      @current_resource.version ['1.0', '6.1']
-      expect(@provider).to receive(:upgrade_package).with(
+      current_resource.version ["1.0", "6.1"]
+      expect(provider).to receive(:upgrade_package).with(
         ["vi"],
-        ["6.2"]
+        ["6.2"],
       ).and_return(true)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).to be_updated_by_last_action
+      provider.run_action(:upgrade)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not install the package if the current versions are the candidate version" do
-      @current_resource.version ['1.0', '6.2']
-      expect(@provider).not_to receive(:upgrade_package)
-      @provider.run_action(:upgrade)
-      expect(@new_resource).not_to be_updated_by_last_action
+      current_resource.version ["1.0", "6.2"]
+      expect(provider).not_to receive(:upgrade_package)
+      provider.run_action(:upgrade)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should raise an exception if both are not installed and no caondidates are available" do
-      @current_resource.version([nil, nil])
-      @provider.candidate_version = [nil, nil]
-      expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+      current_resource.version([nil, nil])
+      provider.candidate_version = [nil, nil]
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "should raise an exception if one is not installed and no candidates are available" do
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = ['1.0', nil]
-      expect { @provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = ["1.0", nil]
+      expect { provider.run_action(:upgrade) }.to raise_error(Chef::Exceptions::Package)
     end
 
     it "should not raise an exception if the packages are installed or have a candidate" do
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = [nil, '6.2']
-      expect { @provider.run_action(:upgrade) }.not_to raise_error
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = [nil, "6.2"]
+      expect { provider.run_action(:upgrade) }.not_to raise_error
     end
 
     it "should not raise an exception if the packages are installed or have a candidate" do
-      @current_resource.version(['1.0', nil])
-      @provider.candidate_version = [nil, '6.2']
-      expect { @provider.run_action(:upgrade) }.not_to raise_error
+      current_resource.version(["1.0", nil])
+      provider.candidate_version = [nil, "6.2"]
+      expect { provider.run_action(:upgrade) }.not_to raise_error
     end
   end
 
   describe "When removing multiple packages " do
     before(:each) do
-      allow(@provider).to receive(:remove_package).and_return(true)
-      @current_resource.version ['1.0', '6.2']
+      allow(provider).to receive(:remove_package).and_return(true)
+      current_resource.version ["1.0", "6.2"]
     end
 
     it "should remove the packages if all are installed" do
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil)
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with(["emacs", "vi"], nil)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should remove the packages if some are installed" do
-      @current_resource.version ['1.0', nil]
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], nil)
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      current_resource.version ["1.0", nil]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with(["emacs", "vi"], nil)
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should remove the packages at a specific version if they are installed at that version" do
-      @new_resource.version ['1.0', '6.2']
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['1.0', '6.2'])
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version ["1.0", "6.2"]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with(["emacs", "vi"], ["1.0", "6.2"])
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should remove the packages at a specific version any are is installed at that version" do
-      @new_resource.version ['0.5', '6.2']
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:remove_package).with(['emacs', 'vi'], ['0.5', '6.2'])
-      @provider.run_action(:remove)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version ["0.5", "6.2"]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:remove_package).with(["emacs", "vi"], ["0.5", "6.2"])
+      provider.run_action(:remove)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not remove the packages at a specific version if they are not installed at that version" do
-      @new_resource.version ['0.5', '6.0']
-      expect(@provider).not_to be_removing_package
-      expect(@provider).not_to receive(:remove_package)
-      @provider.run_action(:remove)
-      expect(@new_resource).not_to be_updated_by_last_action
+      new_resource.version ["0.5", "6.0"]
+      expect(provider).not_to be_removing_package
+      expect(provider).not_to receive(:remove_package)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should not remove the packages if they are not installed" do
-      expect(@provider).not_to receive(:remove_package)
-      allow(@current_resource).to receive(:version).and_return(nil)
-      @provider.run_action(:remove)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:remove_package)
+      allow(current_resource).to receive(:version).and_return(nil)
+      provider.run_action(:remove)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
   end
 
   describe "When purging multiple packages " do
     before(:each) do
-      allow(@provider).to receive(:purge_package).and_return(true)
-      @current_resource.version ['1.0', '6.2']
+      allow(provider).to receive(:purge_package).and_return(true)
+      current_resource.version ["1.0", "6.2"]
     end
 
     it "should purge the packages if all are installed" do
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil)
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with(["emacs", "vi"], nil)
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should purge the packages if some are installed" do
-      @current_resource.version ['1.0', nil]
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], nil)
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated
-      expect(@new_resource).to be_updated_by_last_action
+      current_resource.version ["1.0", nil]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with(["emacs", "vi"], nil)
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should purge the packages at a specific version if they are installed at that version" do
-      @new_resource.version ['1.0', '6.2']
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['1.0', '6.2'])
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version ["1.0", "6.2"]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with(["emacs", "vi"], ["1.0", "6.2"])
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should purge the packages at a specific version any are is installed at that version" do
-      @new_resource.version ['0.5', '6.2']
-      expect(@provider).to be_removing_package
-      expect(@provider).to receive(:purge_package).with(['emacs', 'vi'], ['0.5', '6.2'])
-      @provider.run_action(:purge)
-      expect(@new_resource).to be_updated_by_last_action
+      new_resource.version ["0.5", "6.2"]
+      expect(provider).to be_removing_package
+      expect(provider).to receive(:purge_package).with(["emacs", "vi"], ["0.5", "6.2"])
+      provider.run_action(:purge)
+      expect(new_resource).to be_updated_by_last_action
     end
 
     it "should not purge the packages at a specific version if they are not installed at that version" do
-      @new_resource.version ['0.5', '6.0']
-      expect(@provider).not_to be_removing_package
-      expect(@provider).not_to receive(:purge_package)
-      @provider.run_action(:purge)
-      expect(@new_resource).not_to be_updated_by_last_action
+      new_resource.version ["0.5", "6.0"]
+      expect(provider).not_to be_removing_package
+      expect(provider).not_to receive(:purge_package)
+      provider.run_action(:purge)
+      expect(new_resource).not_to be_updated_by_last_action
     end
 
     it "should not purge the packages if they are not installed" do
-      expect(@provider).not_to receive(:purge_package)
-      allow(@current_resource).to receive(:version).and_return(nil)
-      @provider.run_action(:purge)
-      expect(@new_resource).not_to be_updated_by_last_action
+      expect(provider).not_to receive(:purge_package)
+      allow(current_resource).to receive(:version).and_return(nil)
+      provider.run_action(:purge)
+      expect(new_resource).not_to be_updated_by_last_action
+    end
+  end
+
+  describe "shell_out helpers" do
+    [ :shell_out_with_timeout, :shell_out_with_timeout! ].each do |method|
+      stubbed_method = method == :shell_out_with_timeout! ? :shell_out! : :shell_out
+      [ %w{command arg1 arg2}, "command arg1 arg2" ].each do |command|
+        it "#{method} defaults to 900 seconds" do
+          expect(provider).to receive(stubbed_method).with(*command, timeout: 900)
+          provider.send(method, *command)
+        end
+        it "#{method} overrides the default timeout with its options" do
+          expect(provider).to receive(stubbed_method).with(*command, timeout: 1)
+          provider.send(method, *command, timeout: 1)
+        end
+        it "#{method} overrides both timeouts with the new_resource.timeout" do
+          new_resource.timeout(99)
+          expect(provider).to receive(stubbed_method).with(*command, timeout: 99)
+          provider.send(method, *command, timeout: 1)
+        end
+        it "#{method} defaults to 900 seconds and preserves options" do
+          expect(provider).to receive(stubbed_method).with(*command, env: nil, timeout: 900)
+          provider.send(method, *command, env: nil)
+        end
+        it "#{method} overrides the default timeout with its options and preserves options" do
+          expect(provider).to receive(stubbed_method).with(*command, timeout: 1, env: nil)
+          provider.send(method, *command, timeout: 1, env: nil)
+        end
+        it "#{method} overrides both timeouts with the new_resource.timeout and preseves options" do
+          new_resource.timeout(99)
+          expect(provider).to receive(stubbed_method).with(*command, timeout: 99, env: nil)
+          provider.send(method, *command, timeout: 1, env: nil)
+        end
+      end
     end
   end
 end
diff --git a/spec/unit/provider/package_spec.rbe b/spec/unit/provider/package_spec.rbe
deleted file mode 100644
index e69de29..0000000
diff --git a/spec/unit/provider/powershell_script_spec.rb b/spec/unit/provider/powershell_script_spec.rb
new file mode 100644
index 0000000..c44c445
--- /dev/null
+++ b/spec/unit/provider/powershell_script_spec.rb
@@ -0,0 +1,106 @@
+#
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+describe Chef::Provider::PowershellScript, "action_run" do
+
+  let(:powershell_version) { nil }
+  let(:node) {
+    node = Chef::Node.new
+    node.default["kernel"] = Hash.new
+    node.default["kernel"][:machine] = :x86_64.to_s
+    if ! powershell_version.nil?
+      node.default[:languages] = { :powershell => { :version => powershell_version } }
+    end
+    node
+  }
+
+  let(:provider) {
+    empty_events = Chef::EventDispatch::Dispatcher.new
+    run_context = Chef::RunContext.new(node, {}, empty_events)
+    new_resource = Chef::Resource::PowershellScript.new("run some powershell code", run_context)
+    Chef::Provider::PowershellScript.new(new_resource, run_context)
+  }
+
+  context "when setting interpreter flags" do
+    context "on nano" do
+      before(:each) do
+        allow(Chef::Platform).to receive(:windows_nano_server?).and_return(true)
+        allow(provider).to receive(:is_forced_32bit).and_return(false)
+        os_info_double = double("os_info")
+        allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
+        allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+      end
+
+      it "sets the -Command flag as the last flag" do
+        flags = provider.command.split(" ").keep_if { |flag| flag =~ /^-/ }
+        expect(flags.pop).to eq("-Command")
+      end
+    end
+
+    context "not on nano" do
+      before(:each) do
+        allow(Chef::Platform).to receive(:windows_nano_server?).and_return(false)
+        allow(provider).to receive(:is_forced_32bit).and_return(false)
+        os_info_double = double("os_info")
+        allow(provider.run_context.node.kernel).to receive(:os_info).and_return(os_info_double)
+        allow(os_info_double).to receive(:system_directory).and_return("C:\\Windows\\system32")
+      end
+
+      it "sets the -File flag as the last flag" do
+        flags = provider.command.split(" ").keep_if { |flag| flag =~ /^-/ }
+        expect(flags.pop).to eq("-File")
+      end
+
+      let(:execution_policy_flag) do
+        execution_policy_index = 0
+        provider_flags = provider.flags.split(" ")
+        execution_policy_specified = false
+
+        provider_flags.find do |value|
+          execution_policy_index += 1
+          execution_policy_specified = value.downcase == "-ExecutionPolicy".downcase
+        end
+
+        execution_policy = execution_policy_specified ? provider_flags[execution_policy_index] : nil
+      end
+
+      context "when running with an unspecified PowerShell version" do
+        let(:powershell_version) { nil }
+        it "sets the -ExecutionPolicy flag to 'Unrestricted' by default" do
+          expect(execution_policy_flag.downcase).to eq("unrestricted".downcase)
+        end
+      end
+
+      { "2.0" => "Unrestricted",
+        "2.5" => "Unrestricted",
+        "3.0" => "Bypass",
+        "3.6" => "Bypass",
+        "4.0" => "Bypass",
+        "5.0" => "Bypass" }.each do |version_policy|
+        let(:powershell_version) { version_policy[0].to_f }
+        context "when running PowerShell version #{version_policy[0]}" do
+          let(:powershell_version) { version_policy[0].to_f }
+          it "sets the -ExecutionPolicy flag to '#{version_policy[1]}'" do
+            expect(execution_policy_flag.downcase).to eq(version_policy[1].downcase)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/provider/powershell_spec.rb b/spec/unit/provider/powershell_spec.rb
deleted file mode 100644
index 60dbcf8..0000000
--- a/spec/unit/provider/powershell_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-describe Chef::Provider::PowershellScript, "action_run" do
-
-  before(:each) do
-    @node = Chef::Node.new
-
-    @node.default["kernel"] = Hash.new
-    @node.default["kernel"][:machine] = :x86_64.to_s
-
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::PowershellScript.new('run some powershell code', @run_context)
-
-    @provider = Chef::Provider::PowershellScript.new(@new_resource, @run_context)
-  end
-
-  it "should set the -File flag as the last flag" do
-    expect(@provider.flags.split(' ').pop).to eq("-File")
-  end
-
-end
diff --git a/spec/unit/provider/registry_key_spec.rb b/spec/unit/provider/registry_key_spec.rb
index 79811fd..41bc5b3 100644
--- a/spec/unit/provider/registry_key_spec.rb
+++ b/spec/unit/provider/registry_key_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (lamont at opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Lamont Granquist (lamont at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 shared_examples_for "a registry key" do
   before(:each) do
@@ -77,6 +77,18 @@ shared_examples_for "a registry key" do
   end
 
   describe "action_create" do
+    context "when a case insensitive match for the key exists" do
+      before(:each) do
+        expect(@double_registry).to receive(:key_exists?).twice.with(keyname.downcase).and_return(true)
+      end
+      it "should do nothing if the if a case insensitive key and the value both exist" do
+        @provider.new_resource.key(keyname.downcase)
+        expect(@double_registry).to receive(:get_values).with(keyname.downcase).and_return( testval1 )
+        expect(@double_registry).not_to receive(:set_value)
+        @provider.load_current_resource
+        @provider.action_create
+      end
+    end
     context "when the key exists" do
       before(:each) do
         expect(@double_registry).to receive(:key_exists?).twice.with(keyname).and_return(true)
diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb
index 4434714..710d661 100644
--- a/spec/unit/provider/remote_directory_spec.rb
+++ b/spec/unit/provider/remote_directory_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2010 Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'digest/md5'
-require 'tmpdir'
-require 'chef/mixin/file_class'
+require "spec_helper"
+require "digest/md5"
+require "tmpdir"
+require "chef/mixin/file_class"
 
 class Chef::CFCCheck
   include Chef::Mixin::FileClass
@@ -32,7 +32,7 @@ describe Chef::Provider::RemoteDirectory do
     @resource = Chef::Resource::RemoteDirectory.new(File.join(Dir.tmpdir, "tafty"))
     # in CHEF_SPEC_DATA/cookbooks/openldap/files/default/remotedir
     @resource.source "remotedir"
-    @resource.cookbook('openldap')
+    @resource.cookbook("openldap")
 
     @cookbook_repo = ::File.expand_path(::File.join(CHEF_SPEC_DATA, "cookbooks"))
     Chef::Cookbook::FileVendor.fetch_from_disk(@cookbook_repo)
@@ -79,7 +79,7 @@ describe Chef::Provider::RemoteDirectory do
     end
 
     it "configures access control on intermediate directorys" do
-      directory_resource = @provider.send(:resource_for_directory, File.join(Dir.tmpdir, "intermediate_dir"))
+      directory_resource = @provider.send(:directory_resource, File.join(Dir.tmpdir, "intermediate_dir"))
       expect(directory_resource.path).to  eq(File.join(Dir.tmpdir, "intermediate_dir"))
       expect(directory_resource.mode).to  eq("0750")
       expect(directory_resource.group).to eq("wheel")
@@ -110,7 +110,7 @@ describe Chef::Provider::RemoteDirectory do
       @resource.path(@destination_dir)
     end
 
-    after {FileUtils.rm_rf(@destination_dir)}
+    after { FileUtils.rm_rf(@destination_dir) }
 
     # CHEF-3552
     it "creates the toplevel directory without error " do
@@ -121,12 +121,12 @@ describe Chef::Provider::RemoteDirectory do
 
     it "transfers the directory with all contents" do
       @provider.run_action(:create)
-      expect(::File.exist?(@destination_dir + '/remote_dir_file1.txt')).to be_truthy
-      expect(::File.exist?(@destination_dir + '/remote_dir_file2.txt')).to be_truthy
-      expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')).to be_truthy
-      expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt')).to be_truthy
-      expect(::File.exist?(@destination_dir + '/remotesubdir/.a_dotfile')).to be_truthy
-      expect(::File.exist?(@destination_dir + '/.a_dotdir/.a_dotfile_in_a_dotdir')).to be_truthy
+      expect(::File.exist?(@destination_dir + "/remote_dir_file1.txt")).to be_truthy
+      expect(::File.exist?(@destination_dir + "/remote_dir_file2.txt")).to be_truthy
+      expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")).to be_truthy
+      expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file2.txt")).to be_truthy
+      expect(::File.exist?(@destination_dir + "/remotesubdir/.a_dotfile")).to be_truthy
+      expect(::File.exist?(@destination_dir + "/.a_dotdir/.a_dotfile_in_a_dotdir")).to be_truthy
     end
 
     describe "only if it is missing" do
@@ -134,52 +134,52 @@ describe Chef::Provider::RemoteDirectory do
         @resource.overwrite(true)
         @provider.run_action(:create)
 
-        File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
-        File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
-        file1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt'))
-        subdirfile1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))
+        File.open(@destination_dir + "/remote_dir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+        File.open(@destination_dir + "/remotesubdir/remote_subdir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+        file1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + "/remote_dir_file1.txt"))
+        subdirfile1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt"))
 
         @provider.run_action(:create_if_missing)
 
-        expect(file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt')))).to be_truthy
-        expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')))).to be_truthy
+        expect(file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + "/remote_dir_file1.txt")))).to be_truthy
+        expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")))).to be_truthy
       end
     end
 
     describe "with purging enabled" do
-      before {@resource.purge(true)}
+      before { @resource.purge(true) }
 
       it "removes existing files if purge is true" do
         @provider.run_action(:create)
-        FileUtils.touch(@destination_dir + '/marked_for_death.txt')
-        FileUtils.touch(@destination_dir + '/remotesubdir/marked_for_death_again.txt')
+        FileUtils.touch(@destination_dir + "/marked_for_death.txt")
+        FileUtils.touch(@destination_dir + "/remotesubdir/marked_for_death_again.txt")
         @provider.run_action(:create)
 
-        expect(::File.exist?(@destination_dir + '/remote_dir_file1.txt')).to be_truthy
-        expect(::File.exist?(@destination_dir + '/remote_dir_file2.txt')).to be_truthy
-        expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')).to be_truthy
-        expect(::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt')).to be_truthy
+        expect(::File.exist?(@destination_dir + "/remote_dir_file1.txt")).to be_truthy
+        expect(::File.exist?(@destination_dir + "/remote_dir_file2.txt")).to be_truthy
+        expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")).to be_truthy
+        expect(::File.exist?(@destination_dir + "/remotesubdir/remote_subdir_file2.txt")).to be_truthy
 
-        expect(::File.exist?(@destination_dir + '/marked_for_death.txt')).to be_falsey
-        expect(::File.exist?(@destination_dir + '/remotesubdir/marked_for_death_again.txt')).to be_falsey
+        expect(::File.exist?(@destination_dir + "/marked_for_death.txt")).to be_falsey
+        expect(::File.exist?(@destination_dir + "/remotesubdir/marked_for_death_again.txt")).to be_falsey
       end
 
       it "removes files in subdirectories before files above" do
         @provider.run_action(:create)
-        FileUtils.mkdir_p(@destination_dir + '/a/multiply/nested/directory/')
-        FileUtils.touch(@destination_dir + '/a/foo.txt')
-        FileUtils.touch(@destination_dir + '/a/multiply/bar.txt')
-        FileUtils.touch(@destination_dir + '/a/multiply/nested/baz.txt')
-        FileUtils.touch(@destination_dir + '/a/multiply/nested/directory/qux.txt')
+        FileUtils.mkdir_p(@destination_dir + "/a/multiply/nested/directory/")
+        FileUtils.touch(@destination_dir + "/a/foo.txt")
+        FileUtils.touch(@destination_dir + "/a/multiply/bar.txt")
+        FileUtils.touch(@destination_dir + "/a/multiply/nested/baz.txt")
+        FileUtils.touch(@destination_dir + "/a/multiply/nested/directory/qux.txt")
         @provider.run_action(:create)
-        expect(::File.exist?(@destination_dir + '/a/foo.txt')).to be_falsey
-        expect(::File.exist?(@destination_dir + '/a/multiply/bar.txt')).to be_falsey
-        expect(::File.exist?(@destination_dir + '/a/multiply/nested/baz.txt')).to be_falsey
-        expect(::File.exist?(@destination_dir + '/a/multiply/nested/directory/qux.txt')).to be_falsey
+        expect(::File.exist?(@destination_dir + "/a/foo.txt")).to be_falsey
+        expect(::File.exist?(@destination_dir + "/a/multiply/bar.txt")).to be_falsey
+        expect(::File.exist?(@destination_dir + "/a/multiply/nested/baz.txt")).to be_falsey
+        expect(::File.exist?(@destination_dir + "/a/multiply/nested/directory/qux.txt")).to be_falsey
       end
 
       it "removes directory symlinks properly", :not_supported_on_win2k3 do
-        symlinked_dir_path = @destination_dir + '/symlinked_dir'
+        symlinked_dir_path = @destination_dir + "/symlinked_dir"
         @provider.action = :create
         @provider.run_action
 
@@ -194,29 +194,28 @@ describe Chef::Provider::RemoteDirectory do
 
             expect(::File.exist?(symlinked_dir_path)).to be_falsey
             expect(::File.exist?(tmp_dir)).to be_truthy
-          rescue Chef::Exceptions::Win32APIError => e
-            pending "This must be run as an Administrator to create symlinks"
+          rescue Chef::Exceptions::Win32APIError
+            skip "This must be run as an Administrator to create symlinks"
           end
         end
       end
     end
 
     describe "with overwrite disabled" do
-      before {@resource.purge(false)}
-      before {@resource.overwrite(false)}
+      before { @resource.purge(false) }
+      before { @resource.overwrite(false) }
 
       it "leaves modifications alone" do
         @provider.run_action(:create)
-        ::File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
-        ::File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" }
-        file1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt'))
-        subdirfile1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))
+        ::File.open(@destination_dir + "/remote_dir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+        ::File.open(@destination_dir + "/remotesubdir/remote_subdir_file1.txt", "a") { |f| f.puts "blah blah blah" }
+        file1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + "/remote_dir_file1.txt"))
+        subdirfile1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt"))
         @provider.run_action(:create)
-        expect(file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt')))).to be_truthy
-        expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')))).to be_truthy
+        expect(file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + "/remote_dir_file1.txt")))).to be_truthy
+        expect(subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + "/remotesubdir/remote_subdir_file1.txt")))).to be_truthy
       end
     end
 
   end
 end
-
diff --git a/spec/unit/provider/remote_file/cache_control_data_spec.rb b/spec/unit/provider/remote_file/cache_control_data_spec.rb
index 11f2af3..a80aa38 100644
--- a/spec/unit/provider/remote_file/cache_control_data_spec.rb
+++ b/spec/unit/provider/remote_file/cache_control_data_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,16 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'uri'
+require "spec_helper"
+require "uri"
 
 CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH = 64
-CACHE_FILE_MD5_HEX_LENGTH = 32
+CACHE_FILE_CHECKSUM_HEX_LENGTH = 32
 CACHE_FILE_JSON_FILE_EXTENSION_LENGTH = 5
 CACHE_FILE_PATH_LIMIT =
   CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH +
   1 +
-  CACHE_FILE_MD5_HEX_LENGTH +
+  CACHE_FILE_CHECKSUM_HEX_LENGTH +
   CACHE_FILE_JSON_FILE_EXTENSION_LENGTH # {friendly}-{md5hex}.json == 102
 
 describe Chef::Provider::RemoteFile::CacheControlData do
@@ -36,7 +36,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
     Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum)
   end
 
-  let(:cache_path) { "remote_file/http___www_google_com_robots_txt-9839677abeeadf0691026e0cabca2339.json" }
+  let(:cache_path) { "remote_file/http___www_google_com_robots_txt-6dc1b24315d0cff764d30344199c6f7b.json" }
+  let(:old_cache_path) { "remote_file/http___www_google_com_robots_txt-9839677abeeadf0691026e0cabca2339.json" }
 
   # the checksum of the file we have on disk already
   let(:current_file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }
@@ -44,7 +45,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
   context "when loading data for an unknown URI" do
 
     before do
-      expect(Chef::FileCache).to receive(:load).with(cache_path).and_raise(Chef::Exceptions::FileNotFound, "nope")
+      expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(false)
+      expect(Chef::FileCache).to receive(:has_key?).with(old_cache_path).and_return(false)
     end
 
     context "and there is no current copy of the file" do
@@ -64,7 +66,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
     context "and the URI contains a password" do
 
       let(:uri) { URI.parse("http://bob:password@example.org/") }
-      let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
+      let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-44be109aa176a165ef599c12d97af792.json" }
+      let(:old_cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
 
       it "loads the cache data from a path based on a sanitized URI" do
         Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum)
@@ -88,51 +91,73 @@ describe Chef::Provider::RemoteFile::CacheControlData do
       Chef::JSONCompat.to_json(cache)
     end
 
-    before do
-      expect(Chef::FileCache).to receive(:load).with(cache_path).and_return(cache_json_data)
-    end
-
-    context "and there is no on-disk copy of the file" do
-      let(:current_file_checksum) { nil }
-
-      it "returns empty cache control data" do
-        expect(cache_control_data.etag).to be_nil
-        expect(cache_control_data.mtime).to be_nil
+    context "when the cache control data uses sha256 for its name" do
+      before do
+        expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(true)
+        expect(Chef::FileCache).to receive(:load).with(cache_path).and_return(cache_json_data)
       end
-    end
 
-    context "and the cached checksum does not match the on-disk copy" do
-      let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" }
+      context "and there is no on-disk copy of the file" do
+        let(:current_file_checksum) { nil }
 
-      it "returns empty cache control data" do
-        expect(cache_control_data.etag).to be_nil
-        expect(cache_control_data.mtime).to be_nil
+        it "returns empty cache control data" do
+          expect(cache_control_data.etag).to be_nil
+          expect(cache_control_data.mtime).to be_nil
+        end
       end
-    end
 
-    context "and the cached checksum matches the on-disk copy" do
+      context "and the cached checksum does not match the on-disk copy" do
+        let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" }
 
-      it "populates the cache control data" do
-        expect(cache_control_data.etag).to eq(etag)
-        expect(cache_control_data.mtime).to eq(mtime)
+        it "returns empty cache control data" do
+          expect(cache_control_data.etag).to be_nil
+          expect(cache_control_data.mtime).to be_nil
+        end
       end
-    end
-
-    context "and the cached checksum data is corrupted" do
-      let(:cache_json_data) { '{"foo",,"bar" []}' }
 
-      it "returns empty cache control data" do
-        expect(cache_control_data.etag).to be_nil
-        expect(cache_control_data.mtime).to be_nil
+      context "and the cached checksum matches the on-disk copy" do
+        context "when the filename uses sha256" do
+          before do
+            expect(Chef::FileCache).not_to receive(:has_key?).with(old_cache_path)
+          end
+          it "populates the cache control data" do
+            expect(cache_control_data.etag).to eq(etag)
+            expect(cache_control_data.mtime).to eq(mtime)
+          end
+        end
       end
 
-      context "and it still is valid JSON" do
-        let(:cache_json_data) { '' }
+      context "and the cached checksum data is corrupted" do
+        let(:cache_json_data) { '{"foo",,"bar" []}' }
 
         it "returns empty cache control data" do
           expect(cache_control_data.etag).to be_nil
           expect(cache_control_data.mtime).to be_nil
         end
+
+        context "and it still is valid JSON" do
+          let(:cache_json_data) { "" }
+
+          it "returns empty cache control data" do
+            expect(cache_control_data.etag).to be_nil
+            expect(cache_control_data.mtime).to be_nil
+          end
+        end
+      end
+    end
+
+    context "when the filename uses md5" do
+      before do
+        expect(Chef::FileCache).to receive(:has_key?).with(cache_path).and_return(false)
+        expect(Chef::FileCache).to receive(:has_key?).with(old_cache_path).and_return(true)
+        expect(Chef::FileCache).to receive(:load).with(old_cache_path).and_return(cache_json_data)
+      end
+
+      it "populates the cache control data and creates the cache control data file with the correct path" do
+        expect(Chef::FileCache).to receive(:store).with(cache_path, cache_json_data)
+        expect(Chef::FileCache).to receive(:delete).with(old_cache_path)
+        expect(cache_control_data.etag).to eq(etag)
+        expect(cache_control_data.mtime).to eq(mtime)
       end
     end
   end
@@ -174,7 +199,8 @@ describe Chef::Provider::RemoteFile::CacheControlData do
     context "and the URI contains a password" do
 
       let(:uri) { URI.parse("http://bob:password@example.org/") }
-      let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
+      let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-44be109aa176a165ef599c12d97af792.json" }
+      let(:old_cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" }
 
       it "writes the data to the cache with a sanitized path name" do
         json_data = cache_control_data.json_data
@@ -188,16 +214,16 @@ describe Chef::Provider::RemoteFile::CacheControlData do
     # local file system path limits resulting in exceptions from
     # file system API's on both Windows and Unix systems.
     context "and the URI results in a file cache path that exceeds #{CACHE_FILE_PATH_LIMIT} characters in length" do
-      let(:long_remote_path) { "http://www.bing.com/" +  ('0' * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) }
+      let(:long_remote_path) { "http://www.bing.com/" + ("0" * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) }
       let(:uri) { URI.parse(long_remote_path) }
       let(:truncated_remote_uri) { URI.parse(long_remote_path[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]) }
       let(:truncated_file_cache_path) do
         cache_control_data_truncated = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(truncated_remote_uri, current_file_checksum)
-        cache_control_data_truncated.send('sanitized_cache_file_basename')[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]
+        cache_control_data_truncated.send("sanitized_cache_file_basename")[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]
       end
 
       it "truncates the file cache path to 102 characters" do
-        normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+        normalized_cache_path = cache_control_data.send("sanitized_cache_file_basename")
 
         expect(Chef::FileCache).to receive(:store).with("remote_file/" + normalized_cache_path, cache_control_data.json_data)
 
@@ -207,7 +233,7 @@ describe Chef::Provider::RemoteFile::CacheControlData do
       end
 
       it "uses a file cache path that starts with the first #{CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH} characters of the URI" do
-        normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename')
+        normalized_cache_path = cache_control_data.send("sanitized_cache_file_basename")
 
         expect(truncated_file_cache_path.length).to eq(CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH)
         expect(normalized_cache_path.start_with?(truncated_file_cache_path)).to eq(true)
@@ -217,4 +243,3 @@ describe Chef::Provider::RemoteFile::CacheControlData do
   end
 
 end
-
diff --git a/spec/unit/provider/remote_file/content_spec.rb b/spec/unit/provider/remote_file/content_spec.rb
index ce18d23..c6a560b 100644
--- a/spec/unit/provider/remote_file/content_spec.rb
+++ b/spec/unit/provider/remote_file/content_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RemoteFile::Content do
 
@@ -141,7 +141,6 @@ describe Chef::Provider::RemoteFile::Content do
     it_behaves_like "the resource needs fetching"
   end
 
-
   describe "when the fetcher throws an exception" do
     before do
       allow(new_resource).to receive(:checksum).and_return(nil)
@@ -163,7 +162,7 @@ describe Chef::Provider::RemoteFile::Content do
     # https://github.com/opscode/chef/pull/1358#issuecomment-40853299
     def create_exception(exception_class)
       if [ Net::HTTPServerException, Net::HTTPFatalError ].include? exception_class
-        exception_class.new("message", {"something" => 1})
+        exception_class.new("message", { "something" => 1 })
       else
         exception_class.new
       end
@@ -180,7 +179,7 @@ describe Chef::Provider::RemoteFile::Content do
       Timeout::Error,
       Net::HTTPServerException,
       Net::HTTPFatalError,
-      Net::FTPError
+      Net::FTPError,
     ].each do |exception|
       describe "with an exception of #{exception}" do
         before do
diff --git a/spec/unit/provider/remote_file/fetcher_spec.rb b/spec/unit/provider/remote_file/fetcher_spec.rb
index c049848..0fa213c 100644
--- a/spec/unit/provider/remote_file/fetcher_spec.rb
+++ b/spec/unit/provider/remote_file/fetcher_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RemoteFile::Fetcher do
 
@@ -24,6 +24,26 @@ describe Chef::Provider::RemoteFile::Fetcher do
   let(:new_resource) { double("new resource") }
   let(:fetcher_instance) { double("fetcher") }
 
+  describe "when passed a network share" do
+    before do
+      expect(Chef::Provider::RemoteFile::NetworkFile).to receive(:new).and_return(fetcher_instance)
+    end
+
+    context "when host is a name" do
+      let(:source) { "\\\\foohost\\fooshare\\Foo.tar.gz" }
+      it "returns a network file fetcher" do
+        expect(described_class.for_resource(source, new_resource, current_resource)).to eq(fetcher_instance)
+      end
+    end
+
+    context "when host is an ip" do
+      let(:source) { "\\\\127.0.0.1\\fooshare\\Foo.tar.gz" }
+      it "returns a network file fetcher" do
+        expect(described_class.for_resource(source, new_resource, current_resource)).to eq(fetcher_instance)
+      end
+    end
+  end
+
   describe "when passed an http url" do
     let(:uri) { double("uri", :scheme => "http" ) }
     before do
@@ -72,4 +92,3 @@ describe Chef::Provider::RemoteFile::Fetcher do
   end
 
 end
-
diff --git a/spec/unit/provider/remote_file/ftp_spec.rb b/spec/unit/provider/remote_file/ftp_spec.rb
index dbbddd8..c044621 100644
--- a/spec/unit/provider/remote_file/ftp_spec.rb
+++ b/spec/unit/provider/remote_file/ftp_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RemoteFile::FTP do
   let(:enclosing_directory) {
@@ -38,7 +38,7 @@ describe Chef::Provider::RemoteFile::FTP do
   end
 
   let(:ftp) do
-    ftp = double(Net::FTP, { })
+    ftp = double(Net::FTP, {})
     allow(ftp).to receive(:connect)
     allow(ftp).to receive(:login)
     allow(ftp).to receive(:voidcmd)
diff --git a/spec/unit/provider/remote_file/http_spec.rb b/spec/unit/provider/remote_file/http_spec.rb
index d9cfaa1..60ecd45 100644
--- a/spec/unit/provider/remote_file/http_spec.rb
+++ b/spec/unit/provider/remote_file/http_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Lamont Granquist
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Lamont Granquist
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RemoteFile::HTTP do
 
@@ -61,7 +61,7 @@ describe Chef::Provider::RemoteFile::HTTP do
         end
 
         it "has the user-specified custom headers" do
-          expect(fetcher.headers).to eq({"x-myapp-header" => "custom-header-value"})
+          expect(fetcher.headers).to eq({ "x-myapp-header" => "custom-header-value" })
         end
       end
 
@@ -178,7 +178,6 @@ describe Chef::Provider::RemoteFile::HTTP do
       expect(Chef::HTTP::Simple).to receive(:new).with(*expected_http_args).and_return(rest)
     end
 
-
     describe "and the request does not return new content" do
 
       it "should return a nil tempfile for a 304 HTTPNotModifed" do
@@ -207,7 +206,7 @@ describe Chef::Provider::RemoteFile::HTTP do
       end
 
       context "and the response does not contain an etag" do
-        let(:last_response) { {"etag" => nil} }
+        let(:last_response) { { "etag" => nil } }
         it "does not include an etag in the result" do
           fetcher.fetch
           expect(cache_control_data.etag).to be_nil
@@ -217,7 +216,7 @@ describe Chef::Provider::RemoteFile::HTTP do
       end
 
       context "and the response has an etag header" do
-        let(:last_response) { {"etag" => "abc123"} }
+        let(:last_response) { { "etag" => "abc123" } }
 
         it "includes the etag value in the response" do
           fetcher.fetch
@@ -229,7 +228,7 @@ describe Chef::Provider::RemoteFile::HTTP do
       end
 
       context "and the response has no Date or Last-Modified header" do
-        let(:last_response) { {"date" => nil, "last_modified" => nil} }
+        let(:last_response) { { "date" => nil, "last_modified" => nil } }
         it "does not set an mtime in the result" do
           # RFC 2616 suggests that servers that do not set a Date header do not
           # have a reliable clock, so no use in making them deal with dates.
@@ -243,7 +242,7 @@ describe Chef::Provider::RemoteFile::HTTP do
       context "and the response has a Last-Modified header" do
         let(:last_response) do
           # Last-Modified should be preferred to Date if both are set
-          {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => "Fri, 17 May 2013 11:11:11 GMT"}
+          { "date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => "Fri, 17 May 2013 11:11:11 GMT" }
         end
 
         it "sets the mtime to the Last-Modified time in the response" do
@@ -255,7 +254,7 @@ describe Chef::Provider::RemoteFile::HTTP do
 
       context "and the response has a Date header but no Last-Modified header" do
         let(:last_response) do
-          {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => nil}
+          { "date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => nil }
         end
 
         it "sets the mtime to the Date in the response" do
@@ -270,7 +269,7 @@ describe Chef::Provider::RemoteFile::HTTP do
       context "and the target file is a tarball [CHEF-3140]" do
 
         let(:uri) { URI.parse("http://opscode.com/tarball.tgz") }
-        let(:expected_http_opts) { {:disable_gzip => true} }
+        let(:expected_http_opts) { { :disable_gzip => true } }
 
         # CHEF-3140
         # Some servers return tarballs as content type tar and encoding gzip, which
@@ -300,4 +299,3 @@ describe Chef::Provider::RemoteFile::HTTP do
   end
 
 end
-
diff --git a/spec/unit/provider/remote_file/local_file_spec.rb b/spec/unit/provider/remote_file/local_file_spec.rb
index b33d82f..31f14fb 100644
--- a/spec/unit/provider/remote_file/local_file_spec.rb
+++ b/spec/unit/provider/remote_file/local_file_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jesse Campbell (<hikeit at gmail.com>)
-# Copyright:: Copyright (c) 2013 Jesse Campbell
+# Copyright:: Copyright 2013-2016, Jesse Campbell
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RemoteFile::LocalFile do
 
@@ -25,26 +25,45 @@ describe Chef::Provider::RemoteFile::LocalFile do
   let(:new_resource) { Chef::Resource::RemoteFile.new("local file backend test (new_resource)") }
   let(:current_resource) { Chef::Resource::RemoteFile.new("local file backend test (current_resource)") }
   subject(:fetcher) { Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource) }
-  
-  context "when parsing source path" do
+
+  context "when parsing source path on windows" do
+
+    before do
+      allow(Chef::Platform).to receive(:windows?).and_return(true)
+    end
+
     describe "when given local unix path" do
       let(:uri) { URI.parse("file:///nyan_cat.png") }
       it "returns a correct unix path" do
-        expect(fetcher.fix_windows_path(uri.path)).to eq("/nyan_cat.png")
+        expect(fetcher.source_path).to eq("/nyan_cat.png")
       end
     end
 
     describe "when given local windows path" do
       let(:uri) { URI.parse("file:///z:/windows/path/file.txt") }
       it "returns a valid windows local path" do
-        expect(fetcher.fix_windows_path(uri.path)).to eq("z:/windows/path/file.txt")
+        expect(fetcher.source_path).to eq("z:/windows/path/file.txt")
+      end
+    end
+
+    describe "when given local windows path with spaces" do
+      let(:uri) { URI.parse(URI.escape("file:///z:/windows/path/foo & bar.txt")) }
+      it "returns a valid windows local path" do
+        expect(fetcher.source_path).to eq("z:/windows/path/foo & bar.txt")
       end
     end
 
     describe "when given unc windows path" do
       let(:uri) { URI.parse("file:////server/share/windows/path/file.txt") }
       it "returns a valid windows unc path" do
-        expect(fetcher.fix_windows_path(uri.path)).to eq("//server/share/windows/path/file.txt")
+        expect(fetcher.source_path).to eq("//server/share/windows/path/file.txt")
+      end
+    end
+
+    describe "when given unc windows path with spaces" do
+      let(:uri) { URI.parse(URI.escape("file:////server/share/windows/path/foo & bar.txt")) }
+      it "returns a valid windows unc path" do
+        expect(fetcher.source_path).to eq("//server/share/windows/path/foo & bar.txt")
       end
     end
   end
@@ -73,7 +92,7 @@ describe Chef::Provider::RemoteFile::LocalFile do
     it "stages the local file to a temporary file" do
       expect(Chef::FileContentManagement::Tempfile).to receive(:new).with(new_resource).and_return(chef_tempfile)
       expect(::FileUtils).to receive(:cp).with(uri.path, tempfile.path)
-      expect(tempfile).to receive(:close)            
+      expect(tempfile).to receive(:close)
 
       result = fetcher.fetch
       expect(result).to eq(tempfile)
diff --git a/spec/unit/provider/remote_file/network_file_spec.rb b/spec/unit/provider/remote_file/network_file_spec.rb
new file mode 100644
index 0000000..de065c8
--- /dev/null
+++ b/spec/unit/provider/remote_file/network_file_spec.rb
@@ -0,0 +1,45 @@
+#
+# Author:: Jay Mundrawala (<jdm at chef.io>)
+# Copyright:: Copyright 2015-2016, Chef Software
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Provider::RemoteFile::NetworkFile do
+
+  let(:source) { "\\\\foohost\\fooshare\\Foo.tar.gz" }
+
+  let(:new_resource) { Chef::Resource::RemoteFile.new("network file (new_resource)") }
+  let(:current_resource) { Chef::Resource::RemoteFile.new("network file (current_resource)") }
+  subject(:fetcher) { Chef::Provider::RemoteFile::NetworkFile.new(source, new_resource, current_resource) }
+
+  describe "when fetching the object" do
+
+    let(:tempfile) { double("Tempfile", :path => "/tmp/foo/bar/Foo.tar.gz", :close => nil) }
+    let(:chef_tempfile) { double("Chef::FileContentManagement::Tempfile", :tempfile => tempfile) }
+
+    it "stages the local file to a temporary file" do
+      expect(Chef::FileContentManagement::Tempfile).to receive(:new).with(new_resource).and_return(chef_tempfile)
+      expect(::FileUtils).to receive(:cp).with(source, tempfile.path)
+      expect(tempfile).to receive(:close)
+
+      result = fetcher.fetch
+      expect(result).to eq(tempfile)
+    end
+
+  end
+
+end
diff --git a/spec/unit/provider/remote_file_spec.rb b/spec/unit/provider/remote_file_spec.rb
index de4a897..6107f93 100644
--- a/spec/unit/provider/remote_file_spec.rb
+++ b/spec/unit/provider/remote_file_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,10 +17,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-
-require 'support/shared/unit/provider/file'
+require "spec_helper"
 
+require "support/shared/unit/provider/file"
 
 describe Chef::Provider::RemoteFile do
   let(:resource) do
@@ -32,12 +31,12 @@ describe Chef::Provider::RemoteFile do
   end
 
   let(:content) do
-    content = double('Chef::Provider::File::Content::RemoteFile')
+    content = double("Chef::Provider::File::Content::RemoteFile")
   end
 
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
   let(:enclosing_directory) {
     canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
   }
@@ -60,4 +59,3 @@ describe Chef::Provider::RemoteFile do
 
   it_behaves_like "a file provider with source field"
 end
-
diff --git a/spec/unit/provider/route_spec.rb b/spec/unit/provider/route_spec.rb
index ff68eea..bd1e637 100644
--- a/spec/unit/provider/route_spec.rb
+++ b/spec/unit/provider/route_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Route do
   before do
@@ -25,9 +25,9 @@ describe Chef::Provider::Route do
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
 
-    @new_resource = Chef::Resource::Route.new('10.0.0.10')
+    @new_resource = Chef::Resource::Route.new("10.0.0.10")
     @new_resource.gateway "10.0.0.9"
-    @current_resource = Chef::Resource::Route.new('10.0.0.10')
+    @current_resource = Chef::Resource::Route.new("10.0.0.10")
     @current_resource.gateway "10.0.0.9"
 
     @provider = Chef::Provider::Route.new(@new_resource, @run_context)
@@ -36,22 +36,21 @@ describe Chef::Provider::Route do
 
   describe Chef::Provider::Route, "hex2ip" do
     it "should return nil if ip address is invalid" do
-      expect(@provider.hex2ip('foo')).to be_nil # does not even look like an ip
-      expect(@provider.hex2ip('ABCDEFGH')).to be_nil # 8 chars, but invalid
+      expect(@provider.hex2ip("foo")).to be_nil # does not even look like an ip
+      expect(@provider.hex2ip("ABCDEFGH")).to be_nil # 8 chars, but invalid
     end
 
     it "should return quad-dotted notation for a valid IP" do
-      expect(@provider.hex2ip('01234567')).to eq('103.69.35.1')
-      expect(@provider.hex2ip('0064a8c0')).to eq('192.168.100.0')
-      expect(@provider.hex2ip('00FFFFFF')).to eq('255.255.255.0')
+      expect(@provider.hex2ip("01234567")).to eq("103.69.35.1")
+      expect(@provider.hex2ip("0064a8c0")).to eq("192.168.100.0")
+      expect(@provider.hex2ip("00FFFFFF")).to eq("255.255.255.0")
     end
   end
 
-
   describe Chef::Provider::Route, "load_current_resource" do
     context "on linux" do
       before do
-        @node.automatic_attrs[:os] = 'linux'
+        @node.automatic_attrs[:os] = "linux"
         routing_table = "Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT\n" +
                         "eth0	0064A8C0	0984A8C0	0003	0	0	0	00FFFFFF	0	0	0\n"
         route_file = StringIO.new(routing_table)
@@ -59,7 +58,7 @@ describe Chef::Provider::Route do
       end
 
       it "should set is_running to false when a route is not detected" do
-        resource = Chef::Resource::Route.new('10.10.10.0/24')
+        resource = Chef::Resource::Route.new("10.10.10.0/24")
         allow(resource).to receive(:gateway).and_return("10.0.0.1")
         allow(resource).to receive(:device).and_return("eth0")
         provider = Chef::Provider::Route.new(resource, @run_context)
@@ -69,7 +68,7 @@ describe Chef::Provider::Route do
       end
 
       it "should detect existing routes and set is_running attribute correctly" do
-        resource = Chef::Resource::Route.new('192.168.100.0/24')
+        resource = Chef::Resource::Route.new("192.168.100.0/24")
         allow(resource).to receive(:gateway).and_return("192.168.132.9")
         allow(resource).to receive(:device).and_return("eth0")
         provider = Chef::Provider::Route.new(resource, @run_context)
@@ -79,7 +78,7 @@ describe Chef::Provider::Route do
       end
 
       it "should use gateway value when matching routes" do
-        resource = Chef::Resource::Route.new('192.168.100.0/24')
+        resource = Chef::Resource::Route.new("192.168.100.0/24")
         allow(resource).to receive(:gateway).and_return("10.10.10.10")
         allow(resource).to receive(:device).and_return("eth0")
         provider = Chef::Provider::Route.new(resource, @run_context)
@@ -110,11 +109,11 @@ describe Chef::Provider::Route do
     end
 
     it "should not delete config file for :add action (CHEF-3332)" do
-      @node.automatic_attrs[:platform] = 'centos'
+      @node.automatic_attrs[:platform] = "centos"
 
       route_file = StringIO.new
       expect(File).to receive(:new).and_return(route_file)
-      @resource_add = Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1')
+      @resource_add = Chef::Resource::Route.new("192.168.1.0/24 via 192.168.0.1")
       @run_context.resource_collection << @resource_add
       allow(@provider).to receive(:run_command).and_return(true)
 
@@ -145,7 +144,7 @@ describe Chef::Provider::Route do
 
   describe Chef::Provider::Route, "generate_command for action_add" do
     it "should include a netmask when a one is specified" do
-      allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
+      allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
       expect(@provider.generate_command(:add)).to match(/\/\d{1,2}\s/)
     end
 
@@ -166,7 +165,7 @@ describe Chef::Provider::Route do
 
   describe Chef::Provider::Route, "generate_command for action_delete" do
     it "should include a netmask when a one is specified" do
-      allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
+      allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
       expect(@provider.generate_command(:delete)).to match(/\/\d{1,2}\s/)
     end
 
@@ -187,16 +186,16 @@ describe Chef::Provider::Route do
 
   describe Chef::Provider::Route, "config_file_contents for action_add" do
     it "should include a netmask when a one is specified" do
-      allow(@new_resource).to receive(:netmask).and_return('255.255.0.0')
-      expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :netmask => @new_resource.netmask})).to match(/\/\d{1,2}.*\n$/)
+      allow(@new_resource).to receive(:netmask).and_return("255.255.0.0")
+      expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :netmask => @new_resource.netmask })).to match(/\/\d{1,2}.*\n$/)
     end
 
     it "should not include a netmask when a one is specified" do
-      expect(@provider.config_file_contents(:add, { :target => @new_resource.target})).not_to match(/\/\d{1,2}.*\n$/)
+      expect(@provider.config_file_contents(:add, { :target => @new_resource.target })).not_to match(/\/\d{1,2}.*\n$/)
     end
 
     it "should include ' via $gateway ' when a gateway is specified" do
-      expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :gateway => @new_resource.gateway})).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
+      expect(@provider.config_file_contents(:add, { :target => @new_resource.target, :gateway => @new_resource.gateway })).to match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/)
     end
 
     it "should not include ' via $gateway ' when a gateway is not specified" do
@@ -211,7 +210,7 @@ describe Chef::Provider::Route do
   end
 
   describe Chef::Provider::Route, "generate_config method" do
-    %w[ centos redhat fedora ].each do |platform|
+    %w{ centos redhat fedora }.each do |platform|
       it "should write a route file on #{platform} platform" do
         @node.automatic_attrs[:platform] = platform
 
@@ -224,13 +223,13 @@ describe Chef::Provider::Route do
     end
 
     it "should put all routes for a device in a route config file" do
-      @node.automatic_attrs[:platform] = 'centos'
+      @node.automatic_attrs[:platform] = "centos"
 
       route_file = StringIO.new
       expect(File).to receive(:new).and_return(route_file)
-      @run_context.resource_collection << Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1')
-      @run_context.resource_collection << Chef::Resource::Route.new('192.168.2.0/24 via 192.168.0.1')
-      @run_context.resource_collection << Chef::Resource::Route.new('192.168.3.0/24 via 192.168.0.1')
+      @run_context.resource_collection << Chef::Resource::Route.new("192.168.1.0/24 via 192.168.0.1")
+      @run_context.resource_collection << Chef::Resource::Route.new("192.168.2.0/24 via 192.168.0.1")
+      @run_context.resource_collection << Chef::Resource::Route.new("192.168.3.0/24 via 192.168.0.1")
 
       @provider.action = :add
       @provider.generate_config
diff --git a/spec/unit/provider/ruby_block_spec.rb b/spec/unit/provider/ruby_block_spec.rb
index 266c943..b49aef9 100644
--- a/spec/unit/provider/ruby_block_spec.rb
+++ b/spec/unit/provider/ruby_block_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2009-2016, Opscode
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::RubyBlock, "initialize" do
   before(:each) do
@@ -25,7 +25,7 @@ describe Chef::Provider::RubyBlock, "initialize" do
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
     @new_resource = Chef::Resource::RubyBlock.new("bloc party")
-    @new_resource.block { $evil_global_evil_laugh = :mwahahaha}
+    @new_resource.block { $evil_global_evil_laugh = :mwahahaha }
     @provider = Chef::Provider::RubyBlock.new(@new_resource, @run_context)
   end
 
@@ -43,4 +43,3 @@ describe Chef::Provider::RubyBlock, "initialize" do
     expect(@new_resource).to be_updated
   end
 end
-
diff --git a/spec/unit/provider/script_spec.rb b/spec/unit/provider/script_spec.rb
index d175998..4e8d8bd 100644
--- a/spec/unit/provider/script_spec.rb
+++ b/spec/unit/provider/script_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (adam at opscode.com)
-# Copyright:: Copyright (c) 2009 Opscode
+# Author:: Adam Jacob (adam at chef.io)
+# Copyright:: Copyright 2009-2016, Opscode
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Script, "action_run" do
   let(:node) { Chef::Node.new }
@@ -26,9 +26,9 @@ describe Chef::Provider::Script, "action_run" do
   let(:run_context) { Chef::RunContext.new(node, {}, events) }
 
   let(:new_resource) {
-    new_resource = Chef::Resource::Script.new('run some perl code')
+    new_resource = Chef::Resource::Script.new("run some perl code")
     new_resource.code "$| = 1; print 'i like beans'"
-    new_resource.interpreter 'perl'
+    new_resource.interpreter "perl"
     new_resource
   }
 
@@ -58,9 +58,9 @@ describe Chef::Provider::Script, "action_run" do
 
   context "#set_owner_and_group" do
     it "sets the owner and group for the script file" do
-      new_resource.user 'toor'
-      new_resource.group 'wheel'
-      expect(FileUtils).to receive(:chown).with('toor', 'wheel', tempfile.path)
+      new_resource.user "toor"
+      new_resource.group "wheel"
+      expect(FileUtils).to receive(:chown).with("toor", "wheel", tempfile.path)
       provider.set_owner_and_group
     end
   end
@@ -72,7 +72,7 @@ describe Chef::Provider::Script, "action_run" do
 
     describe "when writing the script to the file" do
       it "should put the contents of the script in the temp file" do
-        allow(provider).to receive(:unlink_script_file)  # stub to avoid remove
+        allow(provider).to receive(:unlink_script_file) # stub to avoid remove
         provider.action_run
         expect(IO.read(tempfile.path)).to eq("$| = 1; print 'i like beans'\n")
         provider.unlink_script_file
@@ -88,24 +88,24 @@ describe Chef::Provider::Script, "action_run" do
 
     describe "when running the script" do
       let (:default_opts) {
-        {timeout: 3600, returns: 0, log_level: :info, log_tag: "script[run some perl code]", live_stream: STDOUT}
+        { timeout: 3600, returns: 0, log_level: :info, log_tag: "script[run some perl code]" }
       }
 
       before do
-        allow(STDOUT).to receive(:tty?).and_return(true)
+        allow(STDOUT).to receive(:tty?).and_return(false)
       end
 
       it 'should set the command to "interpreter"  "tempfile"' do
         expect(provider.command).to eq(%Q{"perl"  "#{tempfile.path}"})
       end
 
-      it 'should call shell_out! with the command' do
+      it "should call shell_out! with the command" do
         expect(provider).to receive(:shell_out!).with(provider.command, default_opts).and_return(true)
         provider.action_run
       end
 
       it "should set the command to 'interpreter flags tempfile'" do
-        new_resource.flags '-f'
+        new_resource.flags "-f"
         expect(provider.command).to eq(%Q{"perl" -f "#{tempfile.path}"})
       end
     end
diff --git a/spec/unit/provider/service/aix_service_spec.rb b/spec/unit/provider/service/aix_service_spec.rb
index 7966611..802ccee 100644
--- a/spec/unit/provider/service/aix_service_spec.rb
+++ b/spec/unit/provider/service/aix_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Kaustubh <kaustubh at clogeny.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Aix do
   before(:each) do
@@ -51,22 +51,35 @@ describe Chef::Provider::Service::Aix do
       end
 
       it "current resource is running" do
-        expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
-        expect(@provider).to receive(:is_resource_group?).with(["chef chef 12345 active"])
+        expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+        expect(@provider).to receive(:is_resource_group?).and_return false
 
         @provider.load_current_resource
         expect(@current_resource.running).to be_truthy
       end
     end
 
-    context "when the service is inoprative" do
+    context "when the service is inoperative" do
       before do
         @status = double("Status", :exitstatus => 0, :stdout => "chef chef inoperative\n")
       end
 
       it "current resource is not running" do
-        expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
-        expect(@provider).to receive(:is_resource_group?).with(["chef chef inoperative"])
+        expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+        expect(@provider).to receive(:is_resource_group?).and_return false
+
+        @provider.load_current_resource
+        expect(@current_resource.running).to be_falsey
+      end
+    end
+
+    context "when there is no such service" do
+      before do
+        @status = double("Status", :exitstatus => 1, :stdout => "0513-085 The chef Subsystem is not on file.\n")
+      end
+      it "current resource is not running" do
+        expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@status)
+        expect(@provider).to receive(:is_resource_group?).and_return false
 
         @provider.load_current_resource
         expect(@current_resource.running).to be_falsey
@@ -75,13 +88,13 @@ describe Chef::Provider::Service::Aix do
   end
 
   describe "is resource group" do
-    context "when there are mutiple subsystems associated with group" do
+    context "when there are multiple subsystems associated with group" do
       before do
         @status = double("Status", :exitstatus => 0, :stdout => "chef1 chef 12345 active\nchef2 chef 12334 active\nchef3 chef inoperative")
       end
 
       it "service is a group" do
-        expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+        expect(@provider).to receive(:shell_out).with("lssrc -g chef").and_return(@status)
         @provider.load_current_resource
         expect(@provider.instance_eval("@is_resource_group")).to be_truthy
       end
@@ -93,19 +106,21 @@ describe Chef::Provider::Service::Aix do
       end
 
       it "service is a group" do
-        expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+        expect(@provider).to receive(:shell_out).with("lssrc -g chef").and_return(@status)
         @provider.load_current_resource
         expect(@provider.instance_eval("@is_resource_group")).to be_truthy
       end
     end
 
-    context "when there service is a subsytem" do
+    context "when the service is a subsystem" do
       before do
-        @status = double("Status", :exitstatus => 0, :stdout => "chef chef123 inoperative\n")
+        @group_status = double("Status", :exitstatus => 1, :stdout => "0513-086 The chef Group is not on file.\n")
+        @service_status = double("Status", :exitstatus => 0, :stdout => "chef chef inoperative\n")
       end
 
       it "service is a subsystem" do
-        expect(@provider).to receive(:shell_out!).with("lssrc -a | grep -w chef").and_return(@status)
+        expect(@provider).to receive(:shell_out).with("lssrc -g chef").and_return(@group_status)
+        expect(@provider).to receive(:shell_out!).with("lssrc -s chef").and_return(@service_status)
         @provider.load_current_resource
         expect(@provider.instance_eval("@is_resource_group")).to be_falsey
       end
@@ -118,7 +133,7 @@ describe Chef::Provider::Service::Aix do
     end
 
     it "should call the start command for groups" do
-      @provider.instance_eval('@is_resource_group = true')
+      @provider.instance_eval("@is_resource_group = true")
       expect(@provider).to receive(:shell_out!).with("startsrc -g #{@new_resource.service_name}")
 
       @provider.start_service
@@ -137,7 +152,7 @@ describe Chef::Provider::Service::Aix do
     end
 
     it "should call the stop command for groups" do
-      @provider.instance_eval('@is_resource_group = true')
+      @provider.instance_eval("@is_resource_group = true")
       expect(@provider).to receive(:shell_out!).with("stopsrc -g #{@new_resource.service_name}")
 
       @provider.stop_service
@@ -156,7 +171,7 @@ describe Chef::Provider::Service::Aix do
     end
 
     it "should call the reload command for groups" do
-      @provider.instance_eval('@is_resource_group = true')
+      @provider.instance_eval("@is_resource_group = true")
       expect(@provider).to receive(:shell_out!).with("refresh -g #{@new_resource.service_name}")
 
       @provider.reload_service
@@ -178,4 +193,3 @@ describe Chef::Provider::Service::Aix do
     end
   end
 end
-
diff --git a/spec/unit/provider/service/aixinit_service_spec.rb b/spec/unit/provider/service/aixinit_service_spec.rb
index e4c9faa..09c1779 100644
--- a/spec/unit/provider/service/aixinit_service_spec.rb
+++ b/spec/unit/provider/service/aixinit_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: kaustubh (<kaustubh at clogeny.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::AixInit do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => 'fuuuu'}
+    @node.automatic_attrs[:command] = { :ps => "fuuuu" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -102,7 +102,7 @@ describe Chef::Provider::Service::AixInit do
 
     context "when the service doesn't set a priority" do
       it "creates symlink with status S" do
-        expect(@provider).to receive(:create_symlink).with(2,'S','')
+        expect(@provider).to receive(:create_symlink).with(2, "S", "")
 
         @provider.enable_service
       end
@@ -114,7 +114,7 @@ describe Chef::Provider::Service::AixInit do
       end
 
       it "creates a symlink with status S and a priority" do
-        expect(@provider).to receive(:create_symlink).with(2,'S',75)
+        expect(@provider).to receive(:create_symlink).with(2, "S", 75)
 
         @provider.enable_service
       end
@@ -122,13 +122,13 @@ describe Chef::Provider::Service::AixInit do
 
     context "when the service sets complex priorities (hash)" do
       before do
-        priority = {2 => [:start, 20], 3 => [:stop, 10]}
+        priority = { 2 => [:start, 20], 3 => [:stop, 10] }
         @new_resource.priority(priority)
       end
 
       it "create symlink with status start (S) or stop (K) and a priority " do
-        expect(@provider).to receive(:create_symlink).with(2,'S',20)
-        expect(@provider).to receive(:create_symlink).with(3,'K',10)
+        expect(@provider).to receive(:create_symlink).with(2, "S", 20)
+        expect(@provider).to receive(:create_symlink).with(3, "K", 10)
 
         @provider.enable_service
       end
@@ -142,7 +142,7 @@ describe Chef::Provider::Service::AixInit do
 
     context "when the service doesn't set a priority" do
       it "creates symlinks with status stop (K)" do
-        expect(@provider).to receive(:create_symlink).with(2,'K','')
+        expect(@provider).to receive(:create_symlink).with(2, "K", "")
 
         @provider.disable_service
       end
@@ -154,7 +154,7 @@ describe Chef::Provider::Service::AixInit do
       end
 
       it "create symlink with status stop (k) and a priority " do
-        expect(@provider).to receive(:create_symlink).with(2,'K',25)
+        expect(@provider).to receive(:create_symlink).with(2, "K", 25)
 
         @provider.disable_service
       end
@@ -162,12 +162,12 @@ describe Chef::Provider::Service::AixInit do
 
     context "when the service sets complex priorities (hash)" do
       before do
-        @priority = {2 => [:start, 20], 3 => [:stop, 10]}
+        @priority = { 2 => [:start, 20], 3 => [:stop, 10] }
         @new_resource.priority(@priority)
       end
 
       it "create symlink with status stop (k) and a priority " do
-        expect(@provider).to receive(:create_symlink).with(3,'K',90)
+        expect(@provider).to receive(:create_symlink).with(3, "K", 90)
 
         @provider.disable_service
       end
@@ -183,17 +183,17 @@ describe Chef::Provider::Service::AixInit do
       end
 
       it "the service is enabled" do
-       expect(@provider.current_resource).to receive(:enabled).with(true)
-       expect(@provider.current_resource).to receive(:priority).with(20)
+        expect(@provider.current_resource).to receive(:enabled).with(true)
+        expect(@provider.current_resource).to receive(:priority).with(20)
 
-       @provider.set_current_resource_attributes
+        @provider.set_current_resource_attributes
       end
     end
 
     context "when rc2.d contains only stop script" do
       before do
         files = ["/etc/rc.d/rc2.d/K20apache"]
-        @priority = {2 => [:stop, 20]}
+        @priority = { 2 => [:stop, 20] }
 
         allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(files)
       end
@@ -208,7 +208,9 @@ describe Chef::Provider::Service::AixInit do
     context "when rc2.d contains both start and stop scripts" do
       before do
         @files = ["/etc/rc.d/rc2.d/S20apache", "/etc/rc.d/rc2.d/K80apache"]
-        @priority = {2 => [:start, 20], 2 => [:stop, 80]}
+        # FIXME: this is clearly buggy the duplicated keys do not work
+        #@priority = {2 => [:start, 20], 2 => [:stop, 80]}
+        @priority = { 2 => [:stop, 80] }
 
         allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]chef"]).and_return(@files)
       end
@@ -228,17 +230,17 @@ describe Chef::Provider::Service::AixInit do
       end
 
       it "the service is enabled" do
-       expect(@provider.current_resource).to receive(:enabled).with(true)
-       expect(@provider.current_resource).to receive(:priority).with('')
+        expect(@provider.current_resource).to receive(:enabled).with(true)
+        expect(@provider.current_resource).to receive(:priority).with("")
 
-       @provider.set_current_resource_attributes
+        @provider.set_current_resource_attributes
       end
     end
 
     context "when rc2.d contains only stop script (without priority)" do
       before do
         files = ["/etc/rc.d/rc2.d/Kapache"]
-        @priority = {2 => [:stop, '']}
+        @priority = { 2 => [:stop, ""] }
 
         allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
       end
@@ -253,7 +255,9 @@ describe Chef::Provider::Service::AixInit do
     context "when rc2.d contains both start and stop scripts" do
       before do
         files = ["/etc/rc.d/rc2.d/Sapache", "/etc/rc.d/rc2.d/Kapache"]
-        @priority = {2 => [:start, ''], 2 => [:stop, '']}
+        # FIXME: this is clearly buggy the duplicated keys do not work
+        #@priority = {2 => [:start, ''], 2 => [:stop, '']}
+        @priority = { 2 => [:stop, ""] }
 
         allow(Dir).to receive(:glob).with(["/etc/rc.d/rc2.d/[SK][0-9][0-9]#{@new_resource.service_name}", "/etc/rc.d/rc2.d/[SK]#{@new_resource.service_name}"]).and_return(files)
       end
@@ -266,4 +270,3 @@ describe Chef::Provider::Service::AixInit do
     end
   end
 end
-
diff --git a/spec/unit/provider/service/arch_service_spec.rb b/spec/unit/provider/service/arch_service_spec.rb
index 49be0e2..47f874c 100644
--- a/spec/unit/provider/service/arch_service_spec.rb
+++ b/spec/unit/provider/service/arch_service_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 # most of this code has been ripped from init_service_spec.rb
 # and is only slightly modified to match "arch" needs.
@@ -26,14 +26,14 @@ require 'ostruct'
 describe Chef::Provider::Service::Arch, "load_current_resource" do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+    @node.automatic_attrs[:command] = { :ps => "ps -ef" }
 
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
     @new_resource = Chef::Resource::Service.new("chef")
     @new_resource.pattern("chef")
-    @new_resource.supports({:status => false})
+    @new_resource.supports({ :status => false })
 
     @provider = Chef::Provider::Service::Arch.new(@new_resource, @run_context)
 
@@ -45,13 +45,13 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
     it "should set the current resources service name to the new resources service name" do
       allow(@provider).to receive(:shell_out).and_return(OpenStruct.new(:exitstatus => 0, :stdout => ""))
       @provider.load_current_resource
-      expect(@provider.current_resource.service_name).to eq('chef')
+      expect(@provider.current_resource.service_name).to eq("chef")
     end
   end
 
   describe "when the service supports status" do
     before do
-      @new_resource.supports({:status => true})
+      @new_resource.supports({ :status => true })
     end
 
     it "should run '/etc/rc.d/service_name status'" do
@@ -92,14 +92,14 @@ describe Chef::Provider::Service::Arch, "load_current_resource" do
   end
 
   it "should raise error if the node has a nil ps attribute and no other means to get status" do
-    @node.automatic_attrs[:command] = {:ps => nil}
+    @node.automatic_attrs[:command] = { :ps => nil }
     @provider.define_resource_requirements
     @provider.action = :start
     expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
   end
 
   it "should raise error if the node has an empty ps attribute and no other means to get status" do
-    @node.automatic_attrs[:command] = {:ps => ""}
+    @node.automatic_attrs[:command] = { :ps => "" }
     @provider.define_resource_requirements
     @provider.action = :start
     expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -125,7 +125,7 @@ DEFAULT_PS
       @status = double("Status", :exitstatus => 0, :stdout => @stdout)
       allow(@provider).to receive(:shell_out!).and_return(@status)
 
-      @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+      @node.automatic_attrs[:command] = { :ps => "ps -ef" }
     end
 
     it "determines the service is running when it appears in ps" do
@@ -155,7 +155,7 @@ RUNNING_PS
 
   it "should return existing entries in DAEMONS array" do
     allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network !apache ssh)")
-    expect(@provider.daemons).to eq(['network', '!apache', 'ssh'])
+    expect(@provider.daemons).to eq(["network", "!apache", "ssh"])
   end
 
   context "when the current service status is known" do
@@ -180,7 +180,7 @@ RUNNING_PS
 
       it "should add chef to DAEMONS array" do
         allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network)")
-        expect(@provider).to receive(:update_daemons).with(['network', 'chef'])
+        expect(@provider).to receive(:update_daemons).with(["network", "chef"])
         @provider.enable_service()
       end
     end
@@ -201,7 +201,7 @@ RUNNING_PS
 
       it "should remove chef from DAEMONS array" do
         allow(::File).to receive(:read).with("/etc/rc.conf").and_return("DAEMONS=(network chef)")
-        expect(@provider).to receive(:update_daemons).with(['network', '!chef'])
+        expect(@provider).to receive(:update_daemons).with(["network", "!chef"])
         @provider.disable_service()
       end
     end
@@ -274,7 +274,7 @@ RUNNING_PS
       # end
 
       it "should call 'restart' on the service_name if the resource supports it" do
-        allow(@new_resource).to receive(:supports).and_return({:restart => true})
+        allow(@new_resource).to receive(:supports).and_return({ :restart => true })
         expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restart")
         @provider.restart_service()
       end
@@ -309,7 +309,7 @@ RUNNING_PS
       # end
 
       it "should call 'reload' on the service if it supports it" do
-        allow(@new_resource).to receive(:supports).and_return({:reload => true})
+        allow(@new_resource).to receive(:supports).and_return({ :reload => true })
         expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} reload")
         @provider.reload_service()
       end
diff --git a/spec/unit/provider/service/debian_service_spec.rb b/spec/unit/provider/service/debian_service_spec.rb
index a4667e8..2192671 100644
--- a/spec/unit/provider/service/debian_service_spec.rb
+++ b/spec/unit/provider/service/debian_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
+# Copyright:: Copyright 2008-2016, HJK Solutions, LLC
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Debian do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => 'fuuuu'}
+    @node.automatic_attrs[:command] = { :ps => "fuuuu" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -114,7 +114,7 @@ describe Chef::Provider::Service::Debian do
       end
     end
 
-    {"Debian/Lenny and older" => {
+    { "Debian/Lenny and older" => {
         "linked" => {
           "stdout" => <<-STDOUT,
  Removing any system startup links for /etc/init.d/chef ...
@@ -128,18 +128,18 @@ describe Chef::Provider::Service::Debian do
           STDOUT
           "stderr" => "",
           "priorities" => {
-            "0"=>[:stop, "20"],
-            "1"=>[:stop, "20"],
-            "2"=>[:start, "20"],
-            "3"=>[:start, "20"],
-            "4"=>[:start, "20"],
-            "5"=>[:start, "20"],
-            "6"=>[:stop, "20"]
-          }
+            "0" => [:stop, "20"],
+            "1" => [:stop, "20"],
+            "2" => [:start, "20"],
+            "3" => [:start, "20"],
+            "4" => [:start, "20"],
+            "5" => [:start, "20"],
+            "6" => [:stop, "20"],
+          },
         },
         "not linked" => {
           "stdout" => " Removing any system startup links for /etc/init.d/chef ...",
-          "stderr" => ""
+          "stderr" => "",
         },
       },
       "Debian/Squeeze and earlier" => {
@@ -156,19 +156,19 @@ insserv: remove service /etc/init.d/../rc0.d/K20chef-client
   insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
           STDERR
           "priorities" => {
-            "0"=>[:stop, "20"],
-            "1"=>[:stop, "20"],
-            "2"=>[:start, "20"],
-            "3"=>[:start, "20"],
-            "4"=>[:start, "20"],
-            "5"=>[:start, "20"],
-            "6"=>[:stop, "20"]
-          }
+            "0" => [:stop, "20"],
+            "1" => [:stop, "20"],
+            "2" => [:start, "20"],
+            "3" => [:start, "20"],
+            "4" => [:start, "20"],
+            "5" => [:start, "20"],
+            "6" => [:stop, "20"],
+          },
         },
         "not linked" => {
           "stdout" => "update-rc.d: using dependency based boot sequencing",
-          "stderr" => ""
-        }
+          "stderr" => "",
+        },
       },
       "Debian/Wheezy and earlier, a service only starting at run level S" => {
         "linked" => {
@@ -181,17 +181,17 @@ insserv: remove service /etc/init.d/../rcS.d/S13rpcbind
 insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
           STDERR
           "priorities" => {
-            "0"=>[:stop, "06"],
-            "1"=>[:stop, "06"],
-            "6"=>[:stop, "06"],
-            "S"=>[:start, "13"]
-          }
+            "0" => [:stop, "06"],
+            "1" => [:stop, "06"],
+            "6" => [:stop, "06"],
+            "S" => [:start, "13"],
+          },
         },
         "not linked" => {
           "stdout" => "",
-          "stderr" => "insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop"
-        }
-      }
+          "stderr" => "insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop",
+        },
+      },
     }.each do |model, expected_results|
       context "on #{model}" do
         context "when update-rc.d shows init linked to rc*.d/" do
@@ -276,7 +276,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
     context "when the service is enabled" do
       before do
         @current_resource.enabled(true)
-	@current_resource.priority(80)
+        @current_resource.priority(80)
       end
 
       context "and the service sets no priority" do
@@ -311,7 +311,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
       it "calls update-rc.d 'service_name' defaults" do
         expect_commands(@provider, [
           "/usr/sbin/update-rc.d -f #{service_name} remove",
-          "/usr/sbin/update-rc.d #{service_name} defaults"
+          "/usr/sbin/update-rc.d #{service_name} defaults",
         ])
         @provider.enable_service
       end
@@ -325,7 +325,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
       it "calls update-rc.d 'service_name' defaults" do
         expect_commands(@provider, [
           "/usr/sbin/update-rc.d -f #{service_name} remove",
-          "/usr/sbin/update-rc.d #{service_name} defaults 75 25"
+          "/usr/sbin/update-rc.d #{service_name} defaults 75 25",
         ])
         @provider.enable_service
       end
@@ -339,7 +339,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
       it "calls update-rc.d 'service_name' with those priorities" do
         expect_commands(@provider, [
           "/usr/sbin/update-rc.d -f #{service_name} remove",
-          "/usr/sbin/update-rc.d #{service_name} start 20 2 . stop 55 3 . "
+          "/usr/sbin/update-rc.d #{service_name} start 20 2 . stop 55 3 . ",
         ])
         @provider.enable_service
       end
@@ -352,7 +352,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
       it "calls update-rc.d -f 'service_name' remove + stop with default priority" do
         expect_commands(@provider, [
           "/usr/sbin/update-rc.d -f #{service_name} remove",
-          "/usr/sbin/update-rc.d -f #{service_name} stop 80 2 3 4 5 ."
+          "/usr/sbin/update-rc.d -f #{service_name} stop 80 2 3 4 5 .",
         ])
         @provider.disable_service
       end
@@ -366,7 +366,7 @@ insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop
       it "calls update-rc.d -f 'service_name' remove + stop with the specified priority" do
         expect_commands(@provider, [
           "/usr/sbin/update-rc.d -f #{service_name} remove",
-          "/usr/sbin/update-rc.d -f #{service_name} stop #{100 - @new_resource.priority} 2 3 4 5 ."
+          "/usr/sbin/update-rc.d -f #{service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .",
         ])
         @provider.disable_service
       end
diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb
index 5a55425..e64aa51 100644
--- a/spec/unit/provider/service/freebsd_service_spec.rb
+++ b/spec/unit/provider/service/freebsd_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class Chef::Provider::Service::Freebsd
   public :service_enable_variable_name
@@ -27,14 +27,14 @@ end
 describe Chef::Provider::Service::Freebsd do
   let(:node) do
     node = Chef::Node.new
-    node.automatic_attrs[:command] = {:ps => "ps -ax"}
+    node.automatic_attrs[:command] = { :ps => "ps -ax" }
     node
   end
 
   let(:new_resource) do
     new_resource = Chef::Resource::Service.new("apache22")
     new_resource.pattern("httpd")
-    new_resource.supports({:status => false})
+    new_resource.supports({ :status => false })
     new_resource
   end
 
@@ -46,7 +46,7 @@ describe Chef::Provider::Service::Freebsd do
   let(:provider) do
     events = Chef::EventDispatch::Dispatcher.new
     run_context = Chef::RunContext.new(node, {}, events)
-    provider = Chef::Provider::Service::Freebsd.new(new_resource,run_context)
+    provider = Chef::Provider::Service::Freebsd.new(new_resource, run_context)
     provider.action = :start
     provider
   end
@@ -115,7 +115,7 @@ describe Chef::Provider::Service::Freebsd do
       let(:status) { double(:stdout => "", :exitstatus => 0) }
 
       before do
-        new_resource.supports({:status => true})
+        new_resource.supports({ :status => true })
       end
 
       it "should run '/etc/init.d/service_name status'" do
@@ -147,7 +147,7 @@ PS_SAMPLE
       let(:status) { double(:stdout => stdout, :exitstatus => 0) }
 
       before do
-        node.automatic_attrs[:command] = {:ps => "ps -ax"}
+        node.automatic_attrs[:command] = { :ps => "ps -ax" }
       end
 
       it "should shell_out! the node's ps command" do
@@ -189,21 +189,9 @@ PS_SAMPLE
         expect(provider.status_load_success).to be_nil
       end
 
-      context "when ps command is nil" do
-        before do
-          node.automatic_attrs[:command] = {:ps => nil}
-        end
-
-        it "should set running to nil" do
-          pending "superclass raises no conversion of nil to string which seems broken"
-          provider.determine_current_status!
-          expect(current_resource.running).to be_nil
-        end
-      end
-
       context "when ps is empty string" do
         before do
-          node.automatic_attrs[:command] = {:ps => ""}
+          node.automatic_attrs[:command] = { :ps => "" }
         end
 
         it "should set running to nil" do
@@ -477,7 +465,7 @@ EOF
 
     describe Chef::Provider::Service::Freebsd, "restart_service" do
       it "should call 'restart' on the service_name if the resource supports it" do
-        new_resource.supports({:restart => true})
+        new_resource.supports({ :restart => true })
         expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} fastrestart")
         provider.restart_service()
       end
diff --git a/spec/unit/provider/service/gentoo_service_spec.rb b/spec/unit/provider/service/gentoo_service_spec.rb
index c08982a..a00ca7a 100644
--- a/spec/unit/provider/service/gentoo_service_spec.rb
+++ b/spec/unit/provider/service/gentoo_service_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Lee Jensen (<ljensen at engineyard.com>)
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Gentoo do
   before(:each) do
@@ -100,7 +100,7 @@ describe Chef::Provider::Service::Gentoo do
         end
       end
 
-  end
+    end
 
     it "should return the current_resource" do
       expect(@provider.load_current_resource).to eq(@current_resource)
@@ -108,17 +108,17 @@ describe Chef::Provider::Service::Gentoo do
 
     it "should support the status command automatically" do
       @provider.load_current_resource
-      expect(@new_resource.supports[:status]).to be_truthy
+      expect(@provider.supports[:status]).to be true
     end
 
     it "should support the restart command automatically" do
       @provider.load_current_resource
-      expect(@new_resource.supports[:restart]).to be_truthy
+      expect(@provider.supports[:restart]).to be true
     end
 
     it "should not support the reload command automatically" do
       @provider.load_current_resource
-      expect(@new_resource.supports[:reload]).not_to be_truthy
+      expect(@provider.supports[:reload]).to be_falsey
     end
 
   end
diff --git a/spec/unit/provider/service/init_service_spec.rb b/spec/unit/provider/service/init_service_spec.rb
index 827a426..4b31e9c 100644
--- a/spec/unit/provider/service/init_service_spec.rb
+++ b/spec/unit/provider/service/init_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Init, "load_current_resource" do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+    @node.automatic_attrs[:command] = { :ps => "ps -ef" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -48,12 +48,12 @@ PS
 
   it "should set the current resources service name to the new resources service name" do
     @provider.load_current_resource
-    expect(@current_resource.service_name).to eq('chef')
+    expect(@current_resource.service_name).to eq("chef")
   end
 
   describe "when the service supports status" do
     before do
-      @new_resource.supports({:status => true})
+      @new_resource.supports({ :status => true })
     end
 
     it "should run '/etc/init.d/service_name status'" do
@@ -109,7 +109,7 @@ PS
   describe "when the node has not specified a ps command" do
 
     it "should raise an error if the node has a nil ps attribute" do
-      @node.automatic_attrs[:command] = {:ps => nil}
+      @node.automatic_attrs[:command] = { :ps => nil }
       @provider.load_current_resource
       @provider.action = :start
       @provider.define_resource_requirements
@@ -117,7 +117,7 @@ PS
     end
 
     it "should raise an error if the node has an empty ps attribute" do
-      @node.automatic_attrs[:command] = {:ps => ""}
+      @node.automatic_attrs[:command] = { :ps => "" }
       @provider.load_current_resource
       @provider.action = :start
       @provider.define_resource_requirements
@@ -189,7 +189,7 @@ RUNNING_PS
 
   describe "when restarting a service" do
     it "should call 'restart' on the service_name if the resource supports it" do
-      @new_resource.supports({:restart => true})
+      @new_resource.supports({ :restart => true })
       expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restart")
       @provider.restart_service()
     end
@@ -210,7 +210,7 @@ RUNNING_PS
 
   describe "when reloading a service" do
     it "should call 'reload' on the service if it supports it" do
-      @new_resource.supports({:reload => true})
+      @new_resource.supports({ :reload => true })
       expect(@provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef reload")
       @provider.reload_service()
     end
diff --git a/spec/unit/provider/service/insserv_service_spec.rb b/spec/unit/provider/service/insserv_service_spec.rb
index 3799dae..3b2b19c 100644
--- a/spec/unit/provider/service/insserv_service_spec.rb
+++ b/spec/unit/provider/service/insserv_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Insserv do
   before(:each) do
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
-    @node.automatic_attrs[:command] = {:ps => "ps -ax"}
+    @node.automatic_attrs[:command] = { :ps => "ps -ax" }
 
     @new_resource = Chef::Resource::Service.new("initgrediant")
     @current_resource = Chef::Resource::Service.new("initgrediant")
diff --git a/spec/unit/provider/service/invokercd_service_spec.rb b/spec/unit/provider/service/invokercd_service_spec.rb
index 81588c8..57b13d0 100644
--- a/spec/unit/provider/service/invokercd_service_spec.rb
+++ b/spec/unit/provider/service/invokercd_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Invokercd, "load_current_resource" do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+    @node.automatic_attrs[:command] = { :ps => "ps -ef" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -48,12 +48,12 @@ PS
 
   it "should set the current resources service name to the new resources service name" do
     @provider.load_current_resource
-    expect(@current_resource.service_name).to eq('chef')
+    expect(@current_resource.service_name).to eq("chef")
   end
 
   describe "when the service supports status" do
     before do
-      @new_resource.supports({:status => true})
+      @new_resource.supports({ :status => true })
     end
 
     it "should run '/usr/sbin/invoke-rc.d service_name status'" do
@@ -95,14 +95,14 @@ PS
 
   describe "when the node has not specified a ps command" do
     it "should raise error if the node has a nil ps attribute and no other means to get status" do
-      @node.automatic_attrs[:command] = {:ps => nil}
+      @node.automatic_attrs[:command] = { :ps => nil }
       @provider.action = :start
       @provider.define_resource_requirements
       expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
     end
 
     it "should raise error if the node has an empty ps attribute and no other means to get status" do
-      @node.automatic_attrs[:command] = {:ps => ""}
+      @node.automatic_attrs[:command] = { :ps => "" }
       @provider.action = :start
       @provider.define_resource_requirements
       expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -176,7 +176,7 @@ RUNNING_PS
 
   describe "when restarting a service" do
     it "should call 'restart' on the service_name if the resource supports it" do
-      @new_resource.supports({:restart => true})
+      @new_resource.supports({ :restart => true })
       expect(@provider).to receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart")
       @provider.restart_service()
     end
@@ -197,7 +197,7 @@ RUNNING_PS
 
   describe "when reloading a service" do
     it "should call 'reload' on the service if it supports it" do
-      @new_resource.supports({:reload => true})
+      @new_resource.supports({ :reload => true })
       expect(@provider).to receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef reload")
       @provider.reload_service()
     end
diff --git a/spec/unit/provider/service/macosx_spec.rb b/spec/unit/provider/service/macosx_spec.rb
index 597845a..29ebf2d 100644
--- a/spec/unit/provider/service/macosx_spec.rb
+++ b/spec/unit/provider/service/macosx_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Igor Afonov <afonov at gmail.com>
-# Copyright:: Copyright (c) 2011 Igor Afonov
+# Copyright:: Copyright 2011-2016, Igor Afonov
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,13 +16,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Macosx do
   describe ".gather_plist_dirs" do
     context "when HOME directory is set" do
       before do
-        allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_yield('/Users/someuser/Library/LaunchAgents')
+        allow(Chef::Util::PathHelper).to receive(:home).with("Library", "LaunchAgents").and_yield("/Users/someuser/Library/LaunchAgents")
       end
 
       it "includes users's LaunchAgents folder" do
@@ -32,7 +32,7 @@ describe Chef::Provider::Service::Macosx do
 
     context "when HOME directory is not set" do
       before do
-        allow(Chef::Util::PathHelper).to receive(:home).with('Library', 'LaunchAgents').and_return(nil)
+        allow(Chef::Util::PathHelper).to receive(:home).with("Library", "LaunchAgents").and_return(nil)
       end
 
       it "doesn't include user's LaunchAgents folder" do
@@ -43,7 +43,7 @@ describe Chef::Provider::Service::Macosx do
 
   context "when service name is given as" do
     let(:node) { Chef::Node.new }
-    let(:events) {Chef::EventDispatch::Dispatcher.new}
+    let(:events) { Chef::EventDispatch::Dispatcher.new }
     let(:run_context) { Chef::RunContext.new(node, {}, events) }
     let(:provider) { described_class.new(new_resource, run_context) }
     let(:launchctl_stdout) { StringIO.new }
@@ -60,31 +60,31 @@ XML
 
     ["Daemon", "Agent"].each do |service_type|
       ["redis-server", "io.redis.redis-server"].each do |service_name|
-        ["10.9", "10.10"].each do |platform_version|
-          let(:plist) {'/Library/LaunchDaemons/io.redis.redis-server.plist'}
+        ["10.9", "10.10", "10.11"].each do |platform_version|
+          let(:plist) { "/Library/LaunchDaemons/io.redis.redis-server.plist" }
           let(:session) { StringIO.new }
-          if service_type == 'Agent'
-            let(:plist) {'/Library/LaunchAgents/io.redis.redis-server.plist'}
-            let(:session) {'-S Aqua '}
-            let(:su_cmd) {'su igor -c'}
-            if platform_version != "10.10"
-              let(:su_cmd) {'su -l igor -c'}
+          if service_type == "Agent"
+            let(:plist) { "/Library/LaunchAgents/io.redis.redis-server.plist" }
+            let(:session) { "-S Aqua " }
+            let(:su_cmd) { "su -l igor -c" }
+            if platform_version == "10.9"
+              let(:su_cmd) { "su igor -c" }
             end
           end
-          let(:service_label) {'io.redis.redis-server'}
+          let(:service_label) { "io.redis.redis-server" }
           before do
             allow(Dir).to receive(:glob).and_return([plist], [])
-            allow(Etc).to receive(:getlogin).and_return('igor')
+            allow(Etc).to receive(:getlogin).and_return("igor")
             allow(node).to receive(:[]).with("platform_version").and_return(platform_version)
             cmd = "launchctl list #{service_label}"
             allow(provider).to receive(:shell_out_with_systems_locale).
-                    with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
-                    and_return(double("Status",
+              with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
+              and_return(double("Status",
                                     :stdout => launchctl_stdout, :exitstatus => 0))
             allow(File).to receive(:exists?).and_return([true], [])
             allow(provider).to receive(:shell_out_with_systems_locale!).
-                    with(/plutil -convert xml1 -o/).
-                    and_return(double("Status", :stdout => plutil_stdout))
+              with(/plutil -convert xml1 -o/).
+              and_return(double("Status", :stdout => plutil_stdout))
           end
 
           context "#{service_name} that is a #{service_type} running Osx #{platform_version}" do
@@ -109,8 +109,8 @@ XML
                   allow(Dir).to receive(:glob).and_return([])
                   allow(File).to receive(:exists?).and_return([true], [])
                   allow(provider).to receive(:shell_out!).
-                          with(/plutil -convert xml1 -o/).
-                          and_raise(Mixlib::ShellOut::ShellCommandFailed)
+                    with(/plutil -convert xml1 -o/).
+                    and_raise(Mixlib::ShellOut::ShellCommandFailed)
                 end
 
                 it "works for action :nothing" do
@@ -166,7 +166,7 @@ SVC_LIST
                   allow(File).to receive(:exists?).and_return([true], [])
                 end
                 it "should throw an exception when reload action is attempted" do
-                  expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
+                  expect { provider.run_action(:reload) }.to raise_error(Chef::Exceptions::UnsupportedAction)
                 end
               end
               context "when launchctl returns empty service pid" do
@@ -263,10 +263,10 @@ SVC_LIST
               end
 
               it "starts service via launchctl if service found" do
-                cmd = 'launchctl load -w ' + session + plist
+                cmd = "launchctl load -w " + session + plist
                 expect(provider).to receive(:shell_out_with_systems_locale).
-                        with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
-                        and_return(0)
+                  with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
+                  and_return(0)
 
                 provider.start_service
               end
@@ -295,10 +295,10 @@ SVC_LIST
               end
 
               it "stops the service via launchctl if service found" do
-                cmd = 'launchctl unload -w '+ plist
+                cmd = "launchctl unload -w " + plist
                 expect(provider).to receive(:shell_out_with_systems_locale).
-                        with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
-                        and_return(0)
+                  with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
+                  and_return(0)
 
                 provider.stop_service
               end
diff --git a/spec/unit/provider/service/openbsd_service_spec.rb b/spec/unit/provider/service/openbsd_service_spec.rb
index 1b52064..7b64214 100644
--- a/spec/unit/provider/service/openbsd_service_spec.rb
+++ b/spec/unit/provider/service/openbsd_service_spec.rb
@@ -1,8 +1,8 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
 # Author:: Scott Bonds (scott at ggr.com)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2014 Scott Bonds
+# Copyright:: Copyright 2009-2016, Bryan McLellan
+# Copyright:: Copyright 2014-2016, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class Chef::Provider::Service::Openbsd
   public :builtin_service_enable_variable_name
@@ -31,14 +31,16 @@ end
 describe Chef::Provider::Service::Openbsd do
   let(:node) do
     node = Chef::Node.new
-    node.automatic_attrs[:command] = {:ps => "ps -ax"}
+    node.automatic_attrs[:command] = { :ps => "ps -ax" }
     node
   end
 
+  let(:supports) { { :status => false } }
+
   let(:new_resource) do
     new_resource = Chef::Resource::Service.new("sndiod")
     new_resource.pattern("sndiod")
-    new_resource.supports({:status => false})
+    new_resource.supports(supports)
     new_resource
   end
 
@@ -50,9 +52,9 @@ describe Chef::Provider::Service::Openbsd do
   let(:provider) do
     events = Chef::EventDispatch::Dispatcher.new
     run_context = Chef::RunContext.new(node, {}, events)
-    allow(::File).to receive(:read).with('/etc/rc.conf').and_return('')
-    allow(::File).to receive(:read).with('/etc/rc.conf.local').and_return('')
-    provider = Chef::Provider::Service::Openbsd.new(new_resource,run_context)
+    allow(::File).to receive(:read).with("/etc/rc.conf").and_return("")
+    allow(::File).to receive(:read).with("/etc/rc.conf.local").and_return("")
+    provider = Chef::Provider::Service::Openbsd.new(new_resource, run_context)
     provider.action = :start
     provider
   end
@@ -78,7 +80,7 @@ describe Chef::Provider::Service::Openbsd do
     end
 
     it "should set init_command to nil if it can't find anything" do
-      expect(::File).to receive(:exist?).with('/etc/rc.d/sndiod').and_return(false)
+      expect(::File).to receive(:exist?).with("/etc/rc.d/sndiod").and_return(false)
       expect(provider.init_command).to be nil
     end
   end
@@ -106,9 +108,7 @@ describe Chef::Provider::Service::Openbsd do
     context "when the service supports status" do
       let(:status) { double(:stdout => "", :exitstatus => 0) }
 
-      before do
-        new_resource.supports({:status => true})
-      end
+      let(:supports) { { :status => true } }
 
       it "should run '/etc/rc.d/service_name status'" do
         expect(provider).to receive(:shell_out).with("/etc/rc.d/#{new_resource.service_name} check").and_return(status)
@@ -250,7 +250,7 @@ describe Chef::Provider::Service::Openbsd do
       current_resource.running(false)
       allow(provider).to receive(:service_enable_variable_name).and_return "#{new_resource.service_name}_enable"
       expect(::File).to receive(:open).with("/etc/rc.d/#{new_resource.service_name}")
-     end
+    end
 
     it "should create a current resource with the name of the new resource" do
       expect(Chef::Resource::Service).to receive(:new).and_return(current_resource)
@@ -305,10 +305,12 @@ describe Chef::Provider::Service::Openbsd do
     end
 
     describe Chef::Provider::Service::Openbsd, "restart_service" do
-      it "should call 'restart' on the service_name if the resource supports it" do
-        new_resource.supports({:restart => true})
-        expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{new_resource.service_name} restart")
-        provider.restart_service()
+      context "when the new_resource supports restart" do
+        let(:supports) { { restart: true } }
+        it "should call 'restart' on the service_name if the resource supports it" do
+          expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{new_resource.service_name} restart")
+          provider.restart_service()
+        end
       end
 
       it "should call the restart_command if one has been specified" do
@@ -379,7 +381,7 @@ describe Chef::Provider::Service::Openbsd do
   describe Chef::Provider::Service::Openbsd, "enable_service" do
     before do
       provider.current_resource = current_resource
-      allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local')
+      allow(FileUtils).to receive(:touch).with("/etc/rc.conf.local")
     end
     context "is builtin and disabled by default" do
       before do
@@ -396,10 +398,10 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is disabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should enable the service by adding a line to rc.conf.local" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"\""))
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", include("#{provider.builtin_service_enable_variable_name}=\"\""))
           expect(provider.is_enabled?).to be false
           provider.enable_service
           expect(provider.is_enabled?).to be true
@@ -412,7 +414,7 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is enabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should not change rc.conf.local since it is already enabled" do
           expect(::File).not_to receive(:write)
@@ -424,7 +426,7 @@ describe Chef::Provider::Service::Openbsd do
           provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=NO"
         end
         it "should enable the service by removing a line from rc.conf.local" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/)
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{provider.builtin_service_enable_variable_name})$/)
           expect(provider.is_enabled?).to be false
           provider.enable_service
           expect(provider.is_enabled?).to be true
@@ -433,7 +435,7 @@ describe Chef::Provider::Service::Openbsd do
     end
     context "is not builtin" do
       before do
-        provider.rc_conf = ''
+        provider.rc_conf = ""
       end
       context "is enabled" do
         before do
@@ -446,10 +448,10 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is disabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should enable the service by adding it to the pkg_scripts list" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', "\npkg_scripts=\"#{new_resource.service_name}\"\n")
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", "\npkg_scripts=\"#{new_resource.service_name}\"\n")
           expect(provider.is_enabled?).to be false
           provider.enable_service
           expect(provider.is_enabled?).to be true
@@ -461,7 +463,7 @@ describe Chef::Provider::Service::Openbsd do
   describe Chef::Provider::Service::Openbsd, "disable_service" do
     before do
       provider.current_resource = current_resource
-      allow(FileUtils).to receive(:touch).with('/etc/rc.conf.local')
+      allow(FileUtils).to receive(:touch).with("/etc/rc.conf.local")
     end
     context "is builtin and disabled by default" do
       before do
@@ -472,7 +474,7 @@ describe Chef::Provider::Service::Openbsd do
           provider.rc_conf_local = "#{provider.builtin_service_enable_variable_name}=\"\""
         end
         it "should disable the service by removing its line from rc.conf.local" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{provider.builtin_service_enable_variable_name})$/)
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{provider.builtin_service_enable_variable_name})$/)
           expect(provider.is_enabled?).to be true
           provider.disable_service
           expect(provider.is_enabled?).to be false
@@ -480,7 +482,7 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is disabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should not change rc.conf.local since it is already disabled" do
           expect(::File).not_to receive(:write)
@@ -494,10 +496,10 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is enabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should disable the service by adding a line to rc.conf.local" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', include("#{provider.builtin_service_enable_variable_name}=\"NO\""))
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", include("#{provider.builtin_service_enable_variable_name}=\"NO\""))
           expect(provider.is_enabled?).to be true
           provider.disable_service
           expect(provider.is_enabled?).to be false
@@ -515,14 +517,14 @@ describe Chef::Provider::Service::Openbsd do
     end
     context "is not builtin" do
       before do
-        provider.rc_conf = ''
+        provider.rc_conf = ""
       end
       context "is enabled" do
         before do
           provider.rc_conf_local = "pkg_scripts=\"#{new_resource.service_name}\"\n"
         end
         it "should disable the service by removing it from the pkg_scripts list" do
-          expect(::File).to receive(:write).with('/etc/rc.conf.local', /^(?!#{new_resource.service_name})$/)
+          expect(::File).to receive(:write).with("/etc/rc.conf.local", /^(?!#{new_resource.service_name})$/)
           expect(provider.is_enabled?).to be true
           provider.disable_service
           expect(provider.is_enabled?).to be false
@@ -530,7 +532,7 @@ describe Chef::Provider::Service::Openbsd do
       end
       context "is disabled" do
         before do
-          provider.rc_conf_local = ''
+          provider.rc_conf_local = ""
         end
         it "should not change rc.conf.local since it is already disabled" do
           expect(::File).not_to receive(:write)
diff --git a/spec/unit/provider/service/redhat_spec.rb b/spec/unit/provider/service/redhat_spec.rb
index 73cfec8..5d03c68 100644
--- a/spec/unit/provider/service/redhat_spec.rb
+++ b/spec/unit/provider/service/redhat_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 HJK Solutions, LLC
+# Copyright:: Copyright 2008-2016, HJK Solutions, LLC
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,13 @@
 #
 
 require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
-require 'ostruct'
+require "ostruct"
 
 shared_examples_for "define_resource_requirements_common" do
   it "should raise an error if /sbin/chkconfig does not exist" do
     allow(File).to receive(:exists?).with("/sbin/chkconfig").and_return(false)
     allow(@provider).to receive(:shell_out).with("/sbin/service chef status").and_raise(Errno::ENOENT)
-    allow(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_raise(Errno::ENOENT)
+    allow(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_raise(Errno::ENOENT)
     @provider.load_current_resource
     @provider.define_resource_requirements
     expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
@@ -33,7 +33,7 @@ shared_examples_for "define_resource_requirements_common" do
     status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "")
     expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
     chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "", :stderr => "service chef supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add chef')")
-    expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+    expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
     @provider.load_current_resource
     @provider.define_resource_requirements
     expect { @provider.process_resource_requirements }.not_to raise_error
@@ -44,7 +44,7 @@ describe "Chef::Provider::Service::Redhat" do
 
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => 'foo'}
+    @node.automatic_attrs[:command] = { :ps => "foo" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -64,24 +64,76 @@ describe "Chef::Provider::Service::Redhat" do
     end
 
     describe "load current resource" do
-      it "sets the current enabled status to true if the service is enabled for any run level" do
+      before do
         status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "")
-        expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
+        allow(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
+      end
+
+      it "sets supports[:status] to true by default" do
+        chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:off   2:off   3:off   4:off   5:on  6:off", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
+        @provider.load_current_resource
+        expect(@provider.supports[:status]).to be true
+      end
+
+      it "lets the user override supports[:status] in the new_resource" do
+        @new_resource.supports( { status: false } )
+        @new_resource.pattern "myservice"
+        chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:off   2:off   3:off   4:off   5:on  6:off", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        foo_out = double("ps_command", :exitstatus => 0, :stdout => "a line that matches myservice", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("foo").and_return(foo_out)
+        expect(@provider.service_missing).to be false
+        expect(@provider).not_to receive(:shell_out).with("/sbin/service chef status")
+        @provider.load_current_resource
+        expect(@provider.supports[:status]).to be false
+      end
+
+      it "sets the current enabled status to true if the service is enabled for any run level" do
         chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:off   2:off   3:off   4:off   5:on  6:off", :stderr => "")
-        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
-        expect(@provider.instance_variable_get("@service_missing")).to be_falsey
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
         @provider.load_current_resource
-        expect(@current_resource.enabled).to be_truthy
+        expect(@current_resource.enabled).to be true
       end
 
       it "sets the current enabled status to false if the regex does not match" do
-        status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "")
-        expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
         chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:off   2:off   3:off   4:off   5:off   6:off", :stderr => "")
-        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
-        expect(@provider.instance_variable_get("@service_missing")).to be_falsey
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
         expect(@provider.load_current_resource).to eql(@current_resource)
-        expect(@current_resource.enabled).to be_falsey
+        expect(@current_resource.enabled).to be false
+      end
+
+      it "sets the current enabled status to true if the service is enabled at specified run levels" do
+        @new_resource.run_levels([1, 2])
+        chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:on   2:on   3:off   4:off   5:off   6:off", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
+        @provider.load_current_resource
+        expect(@current_resource.enabled).to be true
+        expect(@provider.current_run_levels).to eql([1, 2])
+      end
+
+      it "sets the current enabled status to false if the service is enabled at a run level it should not" do
+        @new_resource.run_levels([1, 2])
+        chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:on   2:on   3:on   4:off   5:off   6:off", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
+        @provider.load_current_resource
+        expect(@current_resource.enabled).to be false
+        expect(@provider.current_run_levels).to eql([1, 2, 3])
+      end
+
+      it "sets the current enabled status to false if the service is not enabled at specified run levels" do
+        @new_resource.run_levels([ 2 ])
+        chkconfig = double("Chkconfig", :exitstatus => 0, :stdout => "chef    0:off   1:on   2:off   3:off   4:off   5:off   6:off", :stderr => "")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
+        expect(@provider.service_missing).to be false
+        @provider.load_current_resource
+        expect(@current_resource.enabled).to be false
+        expect(@provider.current_run_levels).to eql([1])
       end
     end
 
@@ -92,8 +144,8 @@ describe "Chef::Provider::Service::Redhat" do
         before do
           status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service")
           expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
-          chkconfig = double("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
-          expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+          chkconfig = double("Chkconfig", :existatus => 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
+          expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
           @provider.load_current_resource
           @provider.define_resource_requirements
         end
@@ -130,8 +182,8 @@ describe "Chef::Provider::Service::Redhat" do
       it "should not raise an error if the service does not exist" do
         status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service")
         expect(@provider).to receive(:shell_out).with("/sbin/service chef status").and_return(status)
-        chkconfig = double("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
-        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig)
+        chkconfig = double("Chkconfig", :existatus => 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory")
+        expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0, 1]).and_return(chkconfig)
         @provider.load_current_resource
         @provider.define_resource_requirements
         expect { @provider.process_resource_requirements }.not_to raise_error
@@ -144,6 +196,28 @@ describe "Chef::Provider::Service::Redhat" do
       expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig #{@new_resource.service_name} on")
       @provider.enable_service
     end
+
+    it "should call chkconfig to add 'service_name' at specified run_levels" do
+      allow(@provider).to receive(:run_levels).and_return([1, 2])
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 12 #{@new_resource.service_name} on")
+      @provider.enable_service
+    end
+
+    it "should call chkconfig to add 'service_name' at specified run_levels when run_levels do not match" do
+      allow(@provider).to receive(:run_levels).and_return([1, 2])
+      allow(@provider).to receive(:current_run_levels).and_return([1, 3])
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 12 #{@new_resource.service_name} on")
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 3 #{@new_resource.service_name} off")
+      @provider.enable_service
+    end
+
+    it "should call chkconfig to add 'service_name' at specified run_levels if there is an extra run_level" do
+      allow(@provider).to receive(:run_levels).and_return([1, 2])
+      allow(@provider).to receive(:current_run_levels).and_return([1, 2, 3])
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 12 #{@new_resource.service_name} on")
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 3 #{@new_resource.service_name} off")
+      @provider.enable_service
+    end
   end
 
   describe "disable_service" do
@@ -151,6 +225,12 @@ describe "Chef::Provider::Service::Redhat" do
       expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig #{@new_resource.service_name} off")
       @provider.disable_service
     end
+
+    it "should call chkconfig to del 'service_name' at specified run_levels" do
+      allow(@provider).to receive(:run_levels).and_return([1, 2])
+      expect(@provider).to receive(:shell_out!).with("/sbin/chkconfig --level 12 #{@new_resource.service_name} off")
+      @provider.disable_service
+    end
   end
 
 end
diff --git a/spec/unit/provider/service/simple_service_spec.rb b/spec/unit/provider/service/simple_service_spec.rb
index 895c559..499e0cc 100644
--- a/spec/unit/provider/service/simple_service_spec.rb
+++ b/spec/unit/provider/service/simple_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mathieu Sauve-Frankel <msf at kisoku.net>
-# Copyright:: Copyright (c) 2009, Mathieu Sauve Frankel
+# Copyright:: Copyright 2009-2016, Mathieu Sauve Frankel
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Simple, "load_current_resource" do
   before(:each) do
     @node = Chef::Node.new
-    @node.automatic_attrs[:command] = {:ps => "ps -ef"}
+    @node.automatic_attrs[:command] = { :ps => "ps -ef" }
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
@@ -51,13 +51,13 @@ NOMOCKINGSTRINGSPLZ
   end
 
   it "should raise error if the node has a nil ps attribute and no other means to get status" do
-    @node.automatic_attrs[:command] = {:ps => nil}
+    @node.automatic_attrs[:command] = { :ps => nil }
     @provider.define_resource_requirements
     expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
   end
 
   it "should raise error if the node has an empty ps attribute and no other means to get status" do
-    @node.automatic_attrs[:command] = {:ps => ""}
+    @node.automatic_attrs[:command] = { :ps => "" }
     @provider.define_resource_requirements
     expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
   end
diff --git a/spec/unit/provider/service/solaris_smf_service_spec.rb b/spec/unit/provider/service/solaris_smf_service_spec.rb
index 2039408..c6835be 100644
--- a/spec/unit/provider/service/solaris_smf_service_spec.rb
+++ b/spec/unit/provider/service/solaris_smf_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Toomas Pelberg (<toomasp at gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,81 +16,141 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Solaris do
   before(:each) do
-    @node =Chef::Node.new
+    @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
 
-    @new_resource = Chef::Resource::Service.new('chef')
+    @new_resource = Chef::Resource::Service.new("chef")
 
-    @current_resource = Chef::Resource::Service.new('chef')
+    @current_resource = Chef::Resource::Service.new("chef")
 
     @provider = Chef::Provider::Service::Solaris.new(@new_resource, @run_context)
     allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
 
-    @stdin = StringIO.new
-    @stdout = StringIO.new
-    @stderr = StringIO.new
-    @pid = 2342
-    @stdout_string = "state disabled"
-    allow(@stdout).to receive(:gets).and_return(@stdout_string)
-    @status = double("Status", :exitstatus => 0, :stdout => @stdout)
-    allow(@provider).to receive(:shell_out!).and_return(@status)
+    # enabled / started service (svcs -l chef)
+    enabled_svc_stdout = [
+      "fmri         svc:/application/chef:default",
+      "name         chef service",
+      "enabled      true",
+      "state        online",
+      "next_state   none",
+      "state_time   April  2, 2015 04:25:19 PM EDT",
+      "logfile      /var/svc/log/application-chef:default.log",
+      "restarter    svc:/system/svc/restarter:default",
+      "contract_id  1115271",
+      "dependency   require_all/error svc:/milestone/multi-user:default (online)",
+    ].join("\n")
+
+    # disabled / stopped service (svcs -l chef)
+    disabled_svc_stdout = [
+      "fmri         svc:/application/chef:default",
+      "name         chef service",
+      "enabled      false",
+      "state        disabled",
+      "next_state   none",
+      "state_time   April  2, 2015 04:25:19 PM EDT",
+      "logfile      /var/svc/log/application-chef:default.log",
+      "restarter    svc:/system/svc/restarter:default",
+      "contract_id  1115271",
+      "dependency   require_all/error svc:/milestone/multi-user:default (online)",
+    ].join("\n")
+
+    # disabled / stopped service (svcs -l chef)
+    maintenance_svc_stdout = [
+      "fmri         svc:/application/chef:default",
+      "name         chef service",
+      "enabled      true",
+      "state        maintenance",
+      "next_state   none",
+      "state_time   April  2, 2015 04:25:19 PM EDT",
+      "logfile      /var/svc/log/application-chef:default.log",
+      "restarter    svc:/system/svc/restarter:default",
+      "contract_id  1115271",
+      "dependency   require_all/error svc:/milestone/multi-user:default (online)",
+    ].join("\n")
+
+    # shell_out! return value for a service that is running
+    @enabled_svc_status = double("Status", :exitstatus => 0, :stdout => enabled_svc_stdout, :stdin => "", :stderr => "")
+
+    # shell_out! return value for a service that is disabled
+    @disabled_svc_status = double("Status", :exitstatus => 0, :stdout => disabled_svc_stdout, :stdin => "", :stderr => "")
+
+    # shell_out! return value for a service that is in maintenance mode
+    @maintenance_svc_status = double("Status", :exitstatus => 0, :stdout => maintenance_svc_stdout, :stdin => "", :stderr => "")
+
+    # shell_out! return value for a service that does not exist
+    @no_svc_status = double("Status", :exitstatus => 1, :stdout => "", :stdin => "", :stderr => "svcs: Pattern 'chef' doesn't match any instances\n")
+
+    # shell_out! return value for a successful execution
+    @success = double("clear", :exitstatus => 0, :stdout => "", :stdin => "", :stderr => "")
   end
 
-  it "should raise an error if /bin/svcs does not exist" do
-    expect(File).to receive(:exists?).with("/bin/svcs").and_return(false)
+  it "should raise an error if /bin/svcs and /usr/sbin/svcadm are not executable" do
+    allow(File).to receive(:executable?).with("/bin/svcs").and_return(false)
+    allow(File).to receive(:executable?).with("/usr/sbin/svcadm").and_return(false)
     expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Service)
   end
 
-  describe "on a host with /bin/svcs" do
+  it "should raise an error if /bin/svcs is not executable" do
+    allow(File).to receive(:executable?).with("/bin/svcs").and_return(false)
+    allow(File).to receive(:executable?).with("/usr/sbin/svcadm").and_return(true)
+    expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Service)
+  end
+
+  it "should raise an error if /usr/sbin/svcadm is not executable" do
+    allow(File).to receive(:executable?).with("/bin/svcs").and_return(true)
+    allow(File).to receive(:executable?).with("/usr/sbin/svcadm").and_return(false)
+    expect { @provider.load_current_resource }.to raise_error(Chef::Exceptions::Service)
+  end
+
+  describe "on a host with /bin/svcs and /usr/sbin/svcadm" do
 
     before do
-      allow(File).to receive(:exists?).with('/bin/svcs').and_return(true)
+      allow(File).to receive(:executable?).with("/bin/svcs").and_return(true)
+      allow(File).to receive(:executable?).with("/usr/sbin/svcadm").and_return(true)
     end
 
     describe "when discovering the current service state" do
       it "should create a current resource with the name of the new resource" do
-        allow(@provider).to receive(:shell_out!).with("/bin/svcs -l chef").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
         expect(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
         @provider.load_current_resource
       end
 
       it "should return the current resource" do
-        allow(@provider).to receive(:shell_out!).with("/bin/svcs -l chef").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
         expect(@provider.load_current_resource).to eql(@current_resource)
       end
 
       it "should call '/bin/svcs -l service_name'" do
-        expect(@provider).to receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
         @provider.load_current_resource
       end
 
       it "should mark service as not running" do
-        allow(@provider).to receive(:shell_out!).and_return(@status)
+        expect(@provider).to receive(:shell_out!).and_return(@disabled_svc_status)
         expect(@current_resource).to receive(:running).with(false)
         @provider.load_current_resource
       end
 
       it "should mark service as running" do
-        @status = double("Status", :exitstatus => 0, :stdout => 'state online')
-        allow(@provider).to receive(:shell_out!).and_return(@status)
+        expect(@provider).to receive(:shell_out!).and_return(@enabled_svc_status)
         expect(@current_resource).to receive(:running).with(true)
         @provider.load_current_resource
       end
 
       it "should not mark service as maintenance" do
-        allow(@provider).to receive(:shell_out!).and_return(@status)
+        expect(@provider).to receive(:shell_out!).and_return(@enabled_svc_status)
         @provider.load_current_resource
         expect(@provider.maintenance).to be_falsey
       end
 
       it "should mark service as maintenance" do
-        @status = double("Status", :exitstatus => 0, :stdout => 'state maintenance')
-        allow(@provider).to receive(:shell_out!).and_return(@status)
+        expect(@provider).to receive(:shell_out!).and_return(@maintenance_svc_status)
         @provider.load_current_resource
         expect(@provider.maintenance).to be_truthy
       end
@@ -99,30 +159,41 @@ describe Chef::Provider::Service::Solaris do
     describe "when enabling the service" do
       before(:each) do
         @provider.current_resource = @current_resource
-        @current_resource.enabled(true)
       end
 
       it "should call svcadm enable -s chef" do
-        expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}")
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
+        expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
+        @provider.load_current_resource
+
         expect(@provider.enable_service).to be_truthy
         expect(@current_resource.enabled).to be_truthy
       end
 
       it "should call svcadm enable -s chef for start_service" do
-        expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}")
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
+        expect(@provider).not_to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
+        @provider.load_current_resource
         expect(@provider.start_service).to be_truthy
         expect(@current_resource.enabled).to be_truthy
       end
 
       it "should call svcadm clear chef for start_service when state maintenance" do
-        @status = double("Status", :exitstatus => 0, :stdout => 'state maintenance')
-        allow(@provider).to receive(:shell_out!).and_return(@status)
+        # we are in maint mode
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@maintenance_svc_status)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "clear", @current_resource.service_name).and_return(@success)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "enable", "-s", @current_resource.service_name).and_return(@success)
+
+        # load the resource, then enable it
         @provider.load_current_resource
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}").and_return(@status)
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status)
         expect(@provider.enable_service).to be_truthy
+
+        # now we are enabled
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
+        @provider.load_current_resource
+
         expect(@current_resource.enabled).to be_truthy
       end
     end
@@ -130,17 +201,20 @@ describe Chef::Provider::Service::Solaris do
     describe "when disabling the service" do
       before(:each) do
         @provider.current_resource = @current_resource
-        @current_resource.enabled(false)
       end
 
       it "should call svcadm disable -s chef" do
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@disabled_svc_status)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "disable", "-s", "chef").and_return(@success)
+        @provider.load_current_resource
         expect(@provider.disable_service).to be_truthy
         expect(@current_resource.enabled).to be_falsey
       end
 
       it "should call svcadm disable -s chef for stop_service" do
-        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@disabled_svc_status)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "disable", "-s", "chef").and_return(@success)
+        @provider.load_current_resource
         expect(@provider.stop_service).to be_truthy
         expect(@current_resource.enabled).to be_falsey
       end
@@ -149,12 +223,12 @@ describe Chef::Provider::Service::Solaris do
 
     describe "when reloading the service" do
       before(:each) do
-        @status = double("Process::Status", :exitstatus => 0)
         @provider.current_resource = @current_resource
+        allow(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@enabled_svc_status)
       end
 
       it "should call svcadm refresh chef" do
-        expect(@provider).to receive(:shell_out_with_systems_locale!).with("/usr/sbin/svcadm refresh chef").and_return(@status)
+        expect(@provider).to receive(:shell_out!).with("/usr/sbin/svcadm", "refresh", "chef")
         @provider.reload_service
       end
 
@@ -162,19 +236,16 @@ describe Chef::Provider::Service::Solaris do
 
     describe "when the service doesn't exist" do
       before(:each) do
-        @stdout_string = ""
-        @status = double("Status", :exitstatus => 1, :stdout => @stdout)
         @provider.current_resource = @current_resource
+        expect(@provider).to receive(:shell_out!).with("/bin/svcs", "-l", "chef", { :returns => [0, 1] }).and_return(@no_svc_status)
       end
 
       it "should be marked not running" do
-        expect(@provider).to receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status)
         @provider.service_status
         expect(@current_resource.running).to be_falsey
       end
 
       it "should be marked not enabled" do
-        expect(@provider).to receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status)
         @provider.service_status
         expect(@current_resource.enabled).to be_falsey
       end
diff --git a/spec/unit/provider/service/systemd_service_spec.rb b/spec/unit/provider/service/systemd_service_spec.rb
index 90b669a..b445d93 100644
--- a/spec/unit/provider/service/systemd_service_spec.rb
+++ b/spec/unit/provider/service/systemd_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Systemd do
 
@@ -33,11 +33,11 @@ describe Chef::Provider::Service::Systemd do
   let(:provider) { Chef::Provider::Service::Systemd.new(new_resource, run_context) }
 
   let(:shell_out_success) do
-    double('shell_out_with_systems_locale', :exitstatus => 0, :error? => false)
+    double("shell_out_with_systems_locale", :exitstatus => 0, :error? => false)
   end
 
   let(:shell_out_failure) do
-    double('shell_out_with_systems_locale', :exitstatus => 1, :error? => true)
+    double("shell_out_with_systems_locale", :exitstatus => 1, :error? => true)
   end
 
   let(:current_resource) { Chef::Resource::Service.new(service_name) }
diff --git a/spec/unit/provider/service/upstart_service_spec.rb b/spec/unit/provider/service/upstart_service_spec.rb
index ca7ce8f..fd9ea05 100644
--- a/spec/unit/provider/service/upstart_service_spec.rb
+++ b/spec/unit/provider/service/upstart_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Copyright:: Copyright (c) 2010 Bryan McLellan
+# Copyright:: Copyright 2010-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,18 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service::Upstart do
+  let(:shell_out_success) do
+    double("shell_out_with_systems_locale", :exitstatus => 0, :error? => false)
+  end
+
   before(:each) do
-    @node =Chef::Node.new
-    @node.name('upstarter')
-    @node.automatic_attrs[:platform] = 'ubuntu'
-    @node.automatic_attrs[:platform_version] = '9.10'
+    @node = Chef::Node.new
+    @node.name("upstarter")
+    @node.automatic_attrs[:platform] = "ubuntu"
+    @node.automatic_attrs[:platform_version] = "9.10"
 
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
@@ -38,7 +42,7 @@ describe Chef::Provider::Service::Upstart do
     end
 
     it "should return /etc/event.d as the upstart job directory when running on Ubuntu 9.04" do
-      @node.automatic_attrs[:platform_version] = '9.04'
+      @node.automatic_attrs[:platform_version] = "9.04"
       #Chef::Platform.stub(:find_platform_and_version).and_return([ "ubuntu", "9.04" ])
       @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
       expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/event.d")
@@ -46,14 +50,14 @@ describe Chef::Provider::Service::Upstart do
     end
 
     it "should return /etc/init as the upstart job directory when running on Ubuntu 9.10" do
-      @node.automatic_attrs[:platform_version] = '9.10'
+      @node.automatic_attrs[:platform_version] = "9.10"
       @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
       expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/init")
       expect(@provider.instance_variable_get(:@upstart_conf_suffix)).to eq(".conf")
     end
 
     it "should return /etc/init as the upstart job directory by default" do
-      @node.automatic_attrs[:platform_version] = '9000'
+      @node.automatic_attrs[:platform_version] = "9000"
       @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
       expect(@provider.instance_variable_get(:@upstart_job_dir)).to eq("/etc/init")
       expect(@provider.instance_variable_get(:@upstart_conf_suffix)).to eq(".conf")
@@ -62,7 +66,7 @@ describe Chef::Provider::Service::Upstart do
 
   describe "load_current_resource" do
     before(:each) do
-      @node.automatic_attrs[:command] = {:ps => "ps -ax"}
+      @node.automatic_attrs[:command] = { :ps => "ps -ax" }
 
       @current_resource = Chef::Resource::Service.new("rsyslog")
       allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
@@ -119,6 +123,25 @@ describe Chef::Provider::Service::Upstart do
       end
     end
 
+    describe "when the status command uses the new format with an instance" do
+      before do
+      end
+
+      it "should set running to true if the status command returns 0" do
+        @stdout = StringIO.new("rsyslog (test) start/running, process 100")
+        allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+        @provider.load_current_resource
+        expect(@current_resource.running).to be_truthy
+      end
+
+      it "should set running to false if the status command returns anything except 0" do
+        @stdout = StringIO.new("rsyslog (test) stop/waiting, process 100")
+        allow(@provider).to receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status)
+        @provider.load_current_resource
+        expect(@current_resource.running).to be_falsey
+      end
+    end
+
     describe "when the status command uses the old format" do
       it "should set running to true if the status command returns 0" do
         @stdout = StringIO.new("rsyslog (start) running, process 32225")
@@ -173,7 +196,7 @@ describe Chef::Provider::Service::Upstart do
       end
 
       it "should run the services status command if one has been specified" do
-        allow(@provider).to receive(:shell_out!).with("/bin/chefhasmonkeypants status").and_return(0)
+        allow(@provider).to receive(:shell_out!).with("/bin/chefhasmonkeypants status").and_return(shell_out_success)
         expect(@current_resource).to receive(:running).with(true)
         @provider.load_current_resource
       end
@@ -205,7 +228,7 @@ describe Chef::Provider::Service::Upstart do
 
   describe "enable and disable service" do
     before(:each) do
-      @current_resource = Chef::Resource::Service.new('rsyslog')
+      @current_resource = Chef::Resource::Service.new("rsyslog")
       allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
       @provider.current_resource = @current_resource
       allow(Chef::Util::FileEdit).to receive(:new)
@@ -233,7 +256,7 @@ describe Chef::Provider::Service::Upstart do
 
   describe "start and stop service" do
     before(:each) do
-      @current_resource = Chef::Resource::Service.new('rsyslog')
+      @current_resource = Chef::Resource::Service.new("rsyslog")
 
       allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
       @provider.current_resource = @current_resource
@@ -246,7 +269,7 @@ describe Chef::Provider::Service::Upstart do
     end
 
     it "should call '/sbin/start service_name' if no start command is specified" do
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(shell_out_success)
       @provider.start_service()
     end
 
@@ -261,7 +284,7 @@ describe Chef::Provider::Service::Upstart do
       @new_resource.parameters({ "OSD_ID" => "2" })
       @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context)
       @provider.current_resource = @current_resource
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start rsyslog OSD_ID=2").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start rsyslog OSD_ID=2").and_return(shell_out_success)
       @provider.start_service()
     end
 
@@ -274,13 +297,13 @@ describe Chef::Provider::Service::Upstart do
 
     it "should call '/sbin/restart service_name' if no restart command is specified" do
       allow(@current_resource).to receive(:running).and_return(true)
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/restart #{@new_resource.service_name}").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/restart #{@new_resource.service_name}").and_return(shell_out_success)
       @provider.restart_service()
     end
 
     it "should call '/sbin/start service_name' if restart_service is called for a stopped service" do
       allow(@current_resource).to receive(:running).and_return(false)
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(shell_out_success)
       @provider.restart_service()
     end
 
@@ -293,7 +316,7 @@ describe Chef::Provider::Service::Upstart do
 
     it "should call '/sbin/reload service_name' if no reload command is specified" do
       allow(@current_resource).to receive(:running).and_return(true)
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/reload #{@new_resource.service_name}").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/reload #{@new_resource.service_name}").and_return(shell_out_success)
       @provider.reload_service()
     end
 
@@ -306,7 +329,7 @@ describe Chef::Provider::Service::Upstart do
 
     it "should call '/sbin/stop service_name' if no stop command is specified" do
       allow(@current_resource).to receive(:running).and_return(true)
-      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}").and_return(0)
+      expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}").and_return(shell_out_success)
       @provider.stop_service()
     end
 
diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb
index 784a223..f944d8f 100644
--- a/spec/unit/provider/service/windows_spec.rb
+++ b/spec/unit/provider/service/windows_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Nuo Yan <nuo at opscode.com>
-# Author:: Seth Chisamore <schisamo at opscode.com>
-# Copyright:: Copyright (c) 2010-2011 Opscode, Inc
+# Author:: Nuo Yan <nuo at chef.io>
+# Author:: Seth Chisamore <schisamo at chef.io>
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,373 +17,393 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'mixlib/shellout'
+require "spec_helper"
+require "mixlib/shellout"
 
 describe Chef::Provider::Service::Windows, "load_current_resource" do
-  before(:each) do
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, {}, @events)
-    @new_resource = Chef::Resource::WindowsService.new("chef")
-    @provider = Chef::Provider::Service::Windows.new(@new_resource, @run_context)
-    @provider.current_resource = Chef::Resource::WindowsService.new("current-chef")
-    Object.send(:remove_const, 'Win32') if defined?(Win32)
-    Win32 = Module.new
+  include_context "Win32"
+
+  let(:new_resource) { Chef::Resource::WindowsService.new("chef") }
+  let(:provider) do
+    prvdr = Chef::Provider::Service::Windows.new(new_resource,
+      Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new))
+    prvdr.current_resource = Chef::Resource::WindowsService.new("current-chef")
+    prvdr
+  end
+  let(:service_right) { Chef::Provider::Service::Windows::SERVICE_RIGHT }
+
+  before(:all) do
     Win32::Service = Class.new
+  end
+
+  before(:each) do
     Win32::Service::AUTO_START = 0x00000002
     Win32::Service::DEMAND_START = 0x00000003
     Win32::Service::DISABLED = 0x00000004
-    allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+
+    allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
       double("StatusStruct", :current_state => "running"))
-    allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+    allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
       double("ConfigStruct", :start_type => "auto start"))
     allow(Win32::Service).to receive(:exists?).and_return(true)
     allow(Win32::Service).to receive(:configure).and_return(Win32::Service)
+    allow(Chef::ReservedNames::Win32::Security).to receive(:get_account_right).and_return([])
   end
 
-  it "should set the current resources service name to the new resources service name" do
-    @provider.load_current_resource
-    expect(@provider.current_resource.service_name).to eq('chef')
+  after(:each) do
+    Win32::Service.send(:remove_const, "AUTO_START") if defined?(Win32::Service::AUTO_START)
+    Win32::Service.send(:remove_const, "DEMAND_START") if defined?(Win32::Service::DEMAND_START)
+    Win32::Service.send(:remove_const, "DISABLED") if defined?(Win32::Service::DISABLED)
   end
 
-  it "should return the current resource" do
-    expect(@provider.load_current_resource).to equal(@provider.current_resource)
+  it "sets the current resources service name to the new resources service name" do
+    provider.load_current_resource
+    expect(provider.current_resource.service_name).to eq("chef")
   end
 
-  it "should set the current resources status" do
-    @provider.load_current_resource
-    expect(@provider.current_resource.running).to be_truthy
+  it "returns the current resource" do
+    expect(provider.load_current_resource).to equal(provider.current_resource)
   end
 
-  it "should set the current resources start type" do
-    @provider.load_current_resource
-    expect(@provider.current_resource.enabled).to be_truthy
+  it "sets the current resources status" do
+    provider.load_current_resource
+    expect(provider.current_resource.running).to be_truthy
+  end
+
+  it "sets the current resources start type" do
+    provider.load_current_resource
+    expect(provider.current_resource.enabled).to be_truthy
   end
 
   it "does not set the current resources start type if it is neither AUTO START or DISABLED" do
-    allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+    allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
       double("ConfigStruct", :start_type => "manual"))
-    @provider.load_current_resource
-    expect(@provider.current_resource.enabled).to be_nil
+    provider.load_current_resource
+    expect(provider.current_resource.enabled).to be_nil
   end
 
   describe Chef::Provider::Service::Windows, "start_service" do
     before(:each) do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "stopped"),
         double("StatusStruct", :current_state => "running"))
     end
 
-    it "should call the start command if one is specified" do
-      @new_resource.start_command "sc start chef"
-      expect(@provider).to receive(:shell_out!).with("#{@new_resource.start_command}").and_return("Starting custom service")
-      @provider.start_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "calls the start command if one is specified" do
+      new_resource.start_command "sc start chef"
+      expect(provider).to receive(:shell_out!).with("#{new_resource.start_command}").and_return("Starting custom service")
+      provider.start_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should use the built-in command if no start command is specified" do
-      expect(Win32::Service).to receive(:start).with(@new_resource.service_name)
-      @provider.start_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "uses the built-in command if no start command is specified" do
+      expect(Win32::Service).to receive(:start).with(new_resource.service_name)
+      provider.start_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should do nothing if the service does not exist" do
-      allow(Win32::Service).to receive(:exists?).with(@new_resource.service_name).and_return(false)
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      @provider.start_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+    it "does nothing if the service does not exist" do
+      allow(Win32::Service).to receive(:exists?).with(new_resource.service_name).and_return(false)
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      provider.start_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should do nothing if the service is running" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "does nothing if the service is running" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "running"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      @provider.start_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      provider.start_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should raise an error if the service is paused" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "raises an error if the service is paused" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "paused"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      expect { @provider.start_service }.to raise_error( Chef::Exceptions::Service )
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      expect { provider.start_service }.to raise_error( Chef::Exceptions::Service )
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should wait and continue if the service is in start_pending" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "waits and continues if the service is in start_pending" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "start pending"),
         double("StatusStruct", :current_state => "start pending"),
         double("StatusStruct", :current_state => "running"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      @provider.start_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      provider.start_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should fail if the service is in stop_pending" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "fails if the service is in stop_pending" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "stop pending"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      expect { @provider.start_service }.to raise_error( Chef::Exceptions::Service )
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      expect { provider.start_service }.to raise_error( Chef::Exceptions::Service )
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
     describe "running as a different account" do
-      let(:old_run_as_user) { @new_resource.run_as_user }
-      let(:old_run_as_password) { @new_resource.run_as_password }
+      let(:old_run_as_user) { new_resource.run_as_user }
+      let(:old_run_as_password) { new_resource.run_as_password }
 
       before {
-        @new_resource.run_as_user(".\\wallace")
-        @new_resource.run_as_password("Wensleydale")
+        new_resource.run_as_user(".\\wallace")
+        new_resource.run_as_password("Wensleydale")
       }
 
       after {
-        @new_resource.run_as_user(old_run_as_user)
-        @new_resource.run_as_password(old_run_as_password)
+        new_resource.run_as_user(old_run_as_user)
+        new_resource.run_as_password(old_run_as_password)
       }
 
-      it "should call #grant_service_logon if the :run_as_user and :run_as_password attributes are present" do
+      it "calls #grant_service_logon if the :run_as_user and :run_as_password attributes are present" do
+        expect(Win32::Service).to receive(:start)
+        expect(provider).to receive(:grant_service_logon).and_return(true)
+        provider.start_service
+      end
+
+      it "does not grant user SeServiceLogonRight if it already has it" do
         expect(Win32::Service).to receive(:start)
-        expect(@provider).to receive(:grant_service_logon).and_return(true)
-        @provider.start_service
+        expect(Chef::ReservedNames::Win32::Security).to receive(:get_account_right).with("wallace").and_return([service_right])
+        expect(Chef::ReservedNames::Win32::Security).not_to receive(:add_account_right).with("wallace", service_right)
+        provider.start_service
       end
     end
   end
 
-
   describe Chef::Provider::Service::Windows, "stop_service" do
 
     before(:each) do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "running"),
         double("StatusStruct", :current_state => "stopped"))
     end
 
-    it "should call the stop command if one is specified" do
-      @new_resource.stop_command "sc stop chef"
-      expect(@provider).to receive(:shell_out!).with("#{@new_resource.stop_command}").and_return("Stopping custom service")
-      @provider.stop_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "calls the stop command if one is specified" do
+      new_resource.stop_command "sc stop chef"
+      expect(provider).to receive(:shell_out!).with("#{new_resource.stop_command}").and_return("Stopping custom service")
+      provider.stop_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should use the built-in command if no stop command is specified" do
-      expect(Win32::Service).to receive(:stop).with(@new_resource.service_name)
-      @provider.stop_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "uses the built-in command if no stop command is specified" do
+      expect(Win32::Service).to receive(:stop).with(new_resource.service_name)
+      provider.stop_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should do nothing if the service does not exist" do
-      allow(Win32::Service).to receive(:exists?).with(@new_resource.service_name).and_return(false)
-      expect(Win32::Service).not_to receive(:stop).with(@new_resource.service_name)
-      @provider.stop_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+    it "does nothing if the service does not exist" do
+      allow(Win32::Service).to receive(:exists?).with(new_resource.service_name).and_return(false)
+      expect(Win32::Service).not_to receive(:stop).with(new_resource.service_name)
+      provider.stop_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should do nothing if the service is stopped" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "does nothing if the service is stopped" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "stopped"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:stop).with(@new_resource.service_name)
-      @provider.stop_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:stop).with(new_resource.service_name)
+      provider.stop_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should raise an error if the service is paused" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "raises an error if the service is paused" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "paused"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service )
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      expect { provider.stop_service }.to raise_error( Chef::Exceptions::Service )
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should wait and continue if the service is in stop_pending" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "waits and continue if the service is in stop_pending" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "stop pending"),
         double("StatusStruct", :current_state => "stop pending"),
         double("StatusStruct", :current_state => "stopped"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:stop).with(@new_resource.service_name)
-      @provider.stop_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:stop).with(new_resource.service_name)
+      provider.stop_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should fail if the service is in start_pending" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "fails if the service is in start_pending" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "start pending"))
-      @provider.load_current_resource
-      expect(Win32::Service).not_to receive(:stop).with(@new_resource.service_name)
-      expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service )
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.load_current_resource
+      expect(Win32::Service).not_to receive(:stop).with(new_resource.service_name)
+      expect { provider.stop_service }.to raise_error( Chef::Exceptions::Service )
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
-    it "should pass custom timeout to the stop command if provided" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "passes custom timeout to the stop command if provided" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "running"))
-      @new_resource.timeout 1
-      expect(Win32::Service).to receive(:stop).with(@new_resource.service_name)
+      new_resource.timeout 1
+      expect(Win32::Service).to receive(:stop).with(new_resource.service_name)
       Timeout.timeout(2) do
-        expect { @provider.stop_service }.to raise_error(Timeout::Error)
+        expect { provider.stop_service }.to raise_error(Timeout::Error)
       end
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
   end
 
   describe Chef::Provider::Service::Windows, "restart_service" do
 
-    it "should call the restart command if one is specified" do
-      @new_resource.restart_command "sc restart"
-      expect(@provider).to receive(:shell_out!).with("#{@new_resource.restart_command}")
-      @provider.restart_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "calls the restart command if one is specified" do
+      new_resource.restart_command "sc restart"
+      expect(provider).to receive(:shell_out!).with("#{new_resource.restart_command}")
+      provider.restart_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should stop then start the service if it is running" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "stops then starts the service if it is running" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "running"),
         double("StatusStruct", :current_state => "stopped"),
         double("StatusStruct", :current_state => "stopped"),
         double("StatusStruct", :current_state => "running"))
-      expect(Win32::Service).to receive(:stop).with(@new_resource.service_name)
-      expect(Win32::Service).to receive(:start).with(@new_resource.service_name)
-      @provider.restart_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+      expect(Win32::Service).to receive(:stop).with(new_resource.service_name)
+      expect(Win32::Service).to receive(:start).with(new_resource.service_name)
+      provider.restart_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should just start the service if it is stopped" do
-      allow(Win32::Service).to receive(:status).with(@new_resource.service_name).and_return(
+    it "just starts the service if it is stopped" do
+      allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
         double("StatusStruct", :current_state => "stopped"),
         double("StatusStruct", :current_state => "stopped"),
         double("StatusStruct", :current_state => "running"))
-      expect(Win32::Service).to receive(:start).with(@new_resource.service_name)
-      @provider.restart_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+      expect(Win32::Service).to receive(:start).with(new_resource.service_name)
+      provider.restart_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should do nothing if the service does not exist" do
-      allow(Win32::Service).to receive(:exists?).with(@new_resource.service_name).and_return(false)
-      expect(Win32::Service).not_to receive(:stop).with(@new_resource.service_name)
-      expect(Win32::Service).not_to receive(:start).with(@new_resource.service_name)
-      @provider.restart_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+    it "does nothing if the service does not exist" do
+      allow(Win32::Service).to receive(:exists?).with(new_resource.service_name).and_return(false)
+      expect(Win32::Service).not_to receive(:stop).with(new_resource.service_name)
+      expect(Win32::Service).not_to receive(:start).with(new_resource.service_name)
+      provider.restart_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
 
   end
 
   describe Chef::Provider::Service::Windows, "enable_service" do
     before(:each) do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "disabled"))
     end
 
-    it "should enable service" do
-      expect(Win32::Service).to receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::AUTO_START)
-      @provider.enable_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+    it "enables service" do
+      expect(Win32::Service).to receive(:configure).with(:service_name => new_resource.service_name, :start_type => Win32::Service::AUTO_START)
+      provider.enable_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should do nothing if the service does not exist" do
-      allow(Win32::Service).to receive(:exists?).with(@new_resource.service_name).and_return(false)
+    it "does nothing if the service does not exist" do
+      allow(Win32::Service).to receive(:exists?).with(new_resource.service_name).and_return(false)
       expect(Win32::Service).not_to receive(:configure)
-      @provider.enable_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.enable_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
   end
 
   describe Chef::Provider::Service::Windows, "action_enable" do
     it "does nothing if the service is enabled" do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "auto start"))
-      expect(@provider).not_to receive(:enable_service)
-      @provider.action_enable
+      expect(provider).not_to receive(:enable_service)
+      provider.action_enable
     end
 
     it "enables the service if it is not set to automatic start" do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "disabled"))
-      expect(@provider).to receive(:enable_service)
-      @provider.action_enable
+      expect(provider).to receive(:enable_service)
+      provider.action_enable
     end
   end
 
   describe Chef::Provider::Service::Windows, "action_disable" do
     it "does nothing if the service is disabled" do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "disabled"))
-      expect(@provider).not_to receive(:disable_service)
-      @provider.action_disable
+      expect(provider).not_to receive(:disable_service)
+      provider.action_disable
     end
 
     it "disables the service if it is not set to disabled" do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "auto start"))
-      expect(@provider).to receive(:disable_service)
-      @provider.action_disable
+      expect(provider).to receive(:disable_service)
+      provider.action_disable
     end
   end
 
   describe Chef::Provider::Service::Windows, "disable_service" do
     before(:each) do
-      allow(Win32::Service).to receive(:config_info).with(@new_resource.service_name).and_return(
+      allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
         double("ConfigStruct", :start_type => "auto start"))
     end
 
-    it "should disable service" do
+    it "disables service" do
       expect(Win32::Service).to receive(:configure)
-      @provider.disable_service
-      expect(@new_resource.updated_by_last_action?).to be_truthy
+      provider.disable_service
+      expect(new_resource.updated_by_last_action?).to be_truthy
     end
 
-    it "should do nothing if the service does not exist" do
-      allow(Win32::Service).to receive(:exists?).with(@new_resource.service_name).and_return(false)
+    it "does nothing if the service does not exist" do
+      allow(Win32::Service).to receive(:exists?).with(new_resource.service_name).and_return(false)
       expect(Win32::Service).not_to receive(:configure)
-      @provider.disable_service
-      expect(@new_resource.updated_by_last_action?).to be_falsey
+      provider.disable_service
+      expect(new_resource.updated_by_last_action?).to be_falsey
     end
   end
 
   describe Chef::Provider::Service::Windows, "action_configure_startup" do
-    { :automatic => "auto start", :manual => "demand start", :disabled => "disabled" }.each do |type,win32|
+    { :automatic => "auto start", :manual => "demand start", :disabled => "disabled" }.each do |type, win32|
       it "sets the startup type to #{type} if it is something else" do
-        @new_resource.startup_type(type)
-        allow(@provider).to receive(:current_start_type).and_return("fire")
-        expect(@provider).to receive(:set_startup_type).with(type)
-        @provider.action_configure_startup
+        new_resource.startup_type(type)
+        allow(provider).to receive(:current_start_type).and_return("fire")
+        expect(provider).to receive(:set_startup_type).with(type)
+        provider.action_configure_startup
       end
 
       it "leaves the startup type as #{type} if it is already set" do
-        @new_resource.startup_type(type)
-        allow(@provider).to receive(:current_start_type).and_return(win32)
-        expect(@provider).not_to receive(:set_startup_type).with(type)
-        @provider.action_configure_startup
+        new_resource.startup_type(type)
+        allow(provider).to receive(:current_start_type).and_return(win32)
+        expect(provider).not_to receive(:set_startup_type).with(type)
+        provider.action_configure_startup
       end
     end
   end
 
   describe Chef::Provider::Service::Windows, "set_start_type" do
     it "when called with :automatic it calls Win32::Service#configure with Win32::Service::AUTO_START" do
-      expect(Win32::Service).to receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::AUTO_START)
-      @provider.send(:set_startup_type, :automatic)
+      expect(Win32::Service).to receive(:configure).with(:service_name => new_resource.service_name, :start_type => Win32::Service::AUTO_START)
+      provider.send(:set_startup_type, :automatic)
     end
 
     it "when called with :manual it calls Win32::Service#configure with Win32::Service::DEMAND_START" do
-      expect(Win32::Service).to receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::DEMAND_START)
-      @provider.send(:set_startup_type, :manual)
+      expect(Win32::Service).to receive(:configure).with(:service_name => new_resource.service_name, :start_type => Win32::Service::DEMAND_START)
+      provider.send(:set_startup_type, :manual)
     end
 
     it "when called with :disabled it calls Win32::Service#configure with Win32::Service::DISABLED" do
-      expect(Win32::Service).to receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::DISABLED)
-      @provider.send(:set_startup_type, :disabled)
+      expect(Win32::Service).to receive(:configure).with(:service_name => new_resource.service_name, :start_type => Win32::Service::DISABLED)
+      provider.send(:set_startup_type, :disabled)
     end
 
     it "raises an exception when given an unknown start type" do
-      expect { @provider.send(:set_startup_type, :fire_truck) }.to raise_error(Chef::Exceptions::ConfigurationError)
+      expect { provider.send(:set_startup_type, :fire_truck) }.to raise_error(Chef::Exceptions::ConfigurationError)
     end
   end
 
@@ -406,38 +426,20 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
     include_context "testing private methods"
 
     let(:username) { "unit_test_user" }
-    let(:success_string) { "The task has completed successfully.\r\nSee logfile etc." }
-    let(:failure_string) { "Look on my works, ye Mighty, and despair!" }
-    let(:command) {
-      dbfile = @provider.grant_dbfile_name(username)
-      policyfile = @provider.grant_policyfile_name(username)
-      logfile = @provider.grant_logfile_name(username)
-
-      %Q{secedit.exe /configure /db "#{dbfile}" /cfg "#{policyfile}" /areas USER_RIGHTS SECURITYPOLICY SERVICES /log "#{logfile}"}
-    }
-    let(:shellout_env) { {:environment=>{"LC_ALL"=>"en_US.UTF-8"}} }
-
-    before {
-      expect_any_instance_of(described_class).to receive(:shell_out).with(command).and_call_original
-      expect_any_instance_of(Mixlib::ShellOut).to receive(:run_command).and_return(nil)
-    }
 
-    after {
-      # only needed for the second test.
-      ::File.delete(@provider.grant_policyfile_name(username)) rescue nil
-      ::File.delete(@provider.grant_logfile_name(username)) rescue nil
-      ::File.delete(@provider.grant_dbfile_name(username)) rescue nil
-    }
+    it "calls win32 api to grant user SeServiceLogonRight" do
+      expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).with(username, service_right)
+      expect(provider.grant_service_logon(username)).to equal true
+    end
 
-    it "calls Mixlib::Shellout with the correct command string" do
-      expect_any_instance_of(Mixlib::ShellOut).to receive(:exitstatus).and_return(0)
-      expect(@provider.grant_service_logon(username)).to equal true
+    it "strips '.\' from user name when sending to win32 api" do
+      expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).with(username, service_right)
+      expect(provider.grant_service_logon(".\\#{username}")).to equal true
     end
 
-    it "raises an exception when the grant command fails" do
-      expect_any_instance_of(Mixlib::ShellOut).to receive(:exitstatus).and_return(1)
-      expect_any_instance_of(Mixlib::ShellOut).to receive(:stdout).and_return(failure_string)
-      expect { @provider.grant_service_logon(username) }.to raise_error(Chef::Exceptions::Service)
+    it "raises an exception when the grant fails" do
+      expect(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).and_raise(Chef::Exceptions::Win32APIError, "barf")
+      expect { provider.grant_service_logon(username) }.to raise_error(Chef::Exceptions::Service)
     end
   end
 
@@ -445,17 +447,17 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
     include_context "testing private methods"
 
     it "correctly reformats usernames to create valid filenames" do
-      expect(@provider.clean_username_for_path("\\\\problem username/oink.txt")).to eq("_problem_username_oink_txt")
-      expect(@provider.clean_username_for_path("boring_username")).to eq("boring_username")
+      expect(provider.clean_username_for_path("\\\\problem username/oink.txt")).to eq("_problem_username_oink_txt")
+      expect(provider.clean_username_for_path("boring_username")).to eq("boring_username")
     end
 
     it "correctly reformats usernames for the policy file" do
-      expect(@provider.canonicalize_username(".\\maryann")).to eq("maryann")
-      expect(@provider.canonicalize_username("maryann")).to eq("maryann")
+      expect(provider.canonicalize_username(".\\maryann")).to eq("maryann")
+      expect(provider.canonicalize_username("maryann")).to eq("maryann")
 
-      expect(@provider.canonicalize_username("\\\\maryann")).to eq("maryann")
-      expect(@provider.canonicalize_username("mydomain\\\\maryann")).to eq("mydomain\\\\maryann")
-      expect(@provider.canonicalize_username("\\\\mydomain\\\\maryann")).to eq("mydomain\\\\maryann")
+      expect(provider.canonicalize_username("\\\\maryann")).to eq("maryann")
+      expect(provider.canonicalize_username("mydomain\\\\maryann")).to eq("mydomain\\\\maryann")
+      expect(provider.canonicalize_username("\\\\mydomain\\\\maryann")).to eq("mydomain\\\\maryann")
     end
   end
 end
diff --git a/spec/unit/provider/service_spec.rb b/spec/unit/provider/service_spec.rb
index 17bade5..d775297 100644
--- a/spec/unit/provider/service_spec.rb
+++ b/spec/unit/provider/service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Service do
   before do
@@ -49,7 +49,6 @@ describe Chef::Provider::Service do
     end
   end
 
-
   describe "when disabling the service" do
     it "should disable the service if enabled and set the resource as updated" do
       allow(@current_resource).to receive(:enabled).and_return(true)
diff --git a/spec/unit/provider/subversion_spec.rb b/spec/unit/provider/subversion_spec.rb
index 9ca11b8..372f349 100644
--- a/spec/unit/provider/subversion_spec.rb
+++ b/spec/unit/provider/subversion_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Subversion do
 
@@ -27,6 +27,7 @@ describe Chef::Provider::Subversion do
     @resource.revision "12345"
     @resource.svn_arguments(false)
     @resource.svn_info_args(false)
+    @resource.svn_binary "svn"
     @node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
@@ -35,8 +36,8 @@ describe Chef::Provider::Subversion do
 
   it "converts resource attributes to options for run_command and popen4" do
     expect(@provider.run_options).to eq({})
-    @resource.user 'deployninja'
-    expect(@provider.run_options).to eq({:user => "deployninja"})
+    @resource.user "deployninja"
+    expect(@provider.run_options).to eq({ :user => "deployninja" })
   end
 
   context "determining the revision of the currently deployed code" do
@@ -63,28 +64,18 @@ describe Chef::Provider::Subversion do
                           "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
                           "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
       expect(::File).to receive(:exist?).at_least(1).times.with("/my/deploy/dir/.svn").and_return(true)
-      expect(::File).to receive(:directory?).with("/my/deploy/dir").and_return(true)
-      expect(::Dir).to receive(:chdir).with("/my/deploy/dir").and_yield
-      allow(@stdout).to receive(:string).and_return(example_svn_info)
-      allow(@stderr).to receive(:string).and_return("")
-      allow(@exitstatus).to receive(:exitstatus).and_return(0)
-      expected_command = ["svn info", {:cwd=>"/my/deploy/dir"}]
-      expect(@provider).to receive(:popen4).with(*expected_command).
-                                        and_yield("no-pid", "no-stdin", @stdout, at stderr).
-                                        and_return(@exitstatus)
+      expected_command = ["svn info", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
+      expect(@provider).to receive(:shell_out!).with(*expected_command).
+        and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
       expect(@provider.find_current_revision).to eql("11410")
     end
 
     it "gives nil as the current revision if the deploy dir isn't a SVN working copy" do
       example_svn_info = "svn: '/tmp/deploydir' is not a working copy\n"
       expect(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(true)
-      expect(::File).to receive(:directory?).with("/my/deploy/dir").and_return(true)
-      expect(::Dir).to receive(:chdir).with("/my/deploy/dir").and_yield
-      allow(@stdout).to receive(:string).and_return(example_svn_info)
-      allow(@stderr).to receive(:string).and_return("")
-      allow(@exitstatus).to receive(:exitstatus).and_return(1)
-      expect(@provider).to receive(:popen4).and_yield("no-pid", "no-stdin", @stdout, at stderr).
-                                        and_return(@exitstatus)
+      expected_command = ["svn info", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
+      expect(@provider).to receive(:shell_out!).with(*expected_command).
+        and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
       expect(@provider.find_current_revision).to be_nil
     end
 
@@ -127,28 +118,20 @@ describe Chef::Provider::Subversion do
                           "Last Changed Author: codeninja\n" +
                           "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision
                           "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n"
-      exitstatus = double("exitstatus")
-      allow(exitstatus).to receive(:exitstatus).and_return(0)
       @resource.revision "HEAD"
-      allow(@stdout).to receive(:string).and_return(example_svn_info)
-      allow(@stderr).to receive(:string).and_return("")
-      expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache  -rHEAD", {:cwd=>Dir.tmpdir}]
-      expect(@provider).to receive(:popen4).with(*expected_command).
-                                        and_yield("no-pid","no-stdin", at stdout, at stderr).
-                                        and_return(exitstatus)
+      expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache  -rHEAD", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
+      expect(@provider).to receive(:shell_out!).with(*expected_command).
+        and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
       expect(@provider.revision_int).to eql("11410")
     end
 
     it "returns a helpful message if data from `svn info` can't be parsed" do
       example_svn_info =  "some random text from an error message\n"
-      exitstatus = double("exitstatus")
-      allow(exitstatus).to receive(:exitstatus).and_return(0)
       @resource.revision "HEAD"
-      allow(@stdout).to receive(:string).and_return(example_svn_info)
-      allow(@stderr).to receive(:string).and_return("")
-      expect(@provider).to receive(:popen4).and_yield("no-pid","no-stdin", at stdout, at stderr).
-                                        and_return(exitstatus)
-      expect {@provider.revision_int}.to raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message")
+      expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache  -rHEAD", { :cwd => "/my/deploy/dir", :returns => [0, 1] }]
+      expect(@provider).to receive(:shell_out!).with(*expected_command).
+        and_return(double("ShellOut result", :stdout => example_svn_info, :stderr => ""))
+      expect { @provider.revision_int }.to raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message\n")
 
     end
 
@@ -171,8 +154,7 @@ describe Chef::Provider::Subversion do
 
   it "generates a checkout command with arbitrary options" do
     @resource.svn_arguments "--no-auth-cache"
-    expect(@provider.checkout_command).to eql("svn checkout --no-auth-cache -q  -r12345 "+
-                                          "http://svn.example.org/trunk/ /my/deploy/dir")
+    expect(@provider.checkout_command).to eql("svn checkout --no-auth-cache -q  -r12345 " + "http://svn.example.org/trunk/ /my/deploy/dir")
   end
 
   it "generates a sync command with default options" do
@@ -212,14 +194,14 @@ describe Chef::Provider::Subversion do
   end
 
   it "raises an error if the svn checkout command would fail because the enclosing directory doesn't exist" do
-    expect {@provider.run_action(:sync)}.to raise_error(Chef::Exceptions::MissingParentDirectory)
+    expect { @provider.run_action(:sync) }.to raise_error(Chef::Exceptions::MissingParentDirectory)
   end
 
   it "should not checkout if the destination exists or is a non empty directory" do
     allow(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(false)
     allow(::File).to receive(:exist?).with("/my/deploy/dir").and_return(true)
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
-    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar'])
+    allow(::Dir).to receive(:entries).with("/my/deploy/dir").and_return([".", "..", "foo", "bar"])
     expect(@provider).not_to receive(:checkout_command)
     @provider.run_action(:checkout)
     expect(@resource).not_to be_updated
@@ -230,7 +212,7 @@ describe Chef::Provider::Subversion do
     @resource.user "whois"
     @resource.group "thisis"
     expected_cmd = "svn checkout -q  -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
-    expect(@provider).to receive(:shell_out!).with(expected_cmd, {user: "whois", group: "thisis"})
+    expect(@provider).to receive(:shell_out!).with(expected_cmd, { user: "whois", group: "thisis" })
     @provider.run_action(:checkout)
     expect(@resource).to be_updated
   end
@@ -263,7 +245,7 @@ describe Chef::Provider::Subversion do
   it "does not fetch any updates if the remote revision matches the current revision" do
     allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
     expect(::File).to receive(:exist?).with("/my/deploy/dir/.svn").and_return(true)
-    allow(@provider).to receive(:find_current_revision).and_return('12345')
+    allow(@provider).to receive(:find_current_revision).and_return("12345")
     allow(@provider).to receive(:current_revision_matches_target_revision?).and_return(true)
     @provider.run_action(:sync)
     expect(@resource).not_to be_updated
@@ -277,4 +259,40 @@ describe Chef::Provider::Subversion do
     expect(@resource).to be_updated
   end
 
+  context "selects the correct svn binary" do
+    before do
+    end
+
+    it "selects 'svn' as the binary by default" do
+      @resource.svn_binary nil
+      allow(ChefConfig).to receive(:windows?) { false }
+      expect(@provider).to receive(:svn_binary).and_return("svn")
+      expect(@provider.export_command).to eql(
+        "svn export --force -q  -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+    end
+
+    it "selects an svn binary with an exe extension on windows" do
+      @resource.svn_binary nil
+      allow(ChefConfig).to receive(:windows?) { true }
+      expect(@provider).to receive(:svn_binary).and_return("svn.exe")
+      expect(@provider.export_command).to eql(
+        "svn.exe export --force -q  -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+    end
+
+    it "uses a custom svn binary as part of the svn command" do
+      @resource.svn_binary "teapot"
+      expect(@provider).to receive(:svn_binary).and_return("teapot")
+      expect(@provider.export_command).to eql(
+        "teapot export --force -q  -r12345 http://svn.example.org/trunk/ /my/deploy/dir")
+    end
+
+    it "wraps custom svn binary with quotes if it contains whitespace" do
+      @resource.svn_binary "c:/program files (x86)/subversion/svn.exe"
+      expect(@provider).to receive(:svn_binary).and_return("c:/program files (x86)/subversion/svn.exe")
+      expect(@provider.export_command).to eql(
+        '"c:/program files (x86)/subversion/svn.exe" export --force -q  -r12345 http://svn.example.org/trunk/ /my/deploy/dir')
+    end
+
+  end
+
 end
diff --git a/spec/unit/provider/template/content_spec.rb b/spec/unit/provider/template/content_spec.rb
index 4b88a3a..4f7b4c2 100644
--- a/spec/unit/provider/template/content_spec.rb
+++ b/spec/unit/provider/template/content_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,28 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::Template::Content do
 
+  let(:enclosing_directory) {
+    canonicalize_path(Dir.mktmpdir)
+  }
+
+  let(:resource_path) {
+    canonicalize_path(File.expand_path(File.join(enclosing_directory, "openldap_stuff.conf")))
+  }
+
   let(:new_resource) do
     double("Chef::Resource::Template (new)",
-         :cookbook_name => 'openldap',
-         :source => 'openldap_stuff.conf.erb',
+         :cookbook_name => "openldap",
+         :recipe_name => "default",
+         :source_line => "/Users/lamont/solo/cookbooks/openldap/recipes/default.rb:2:in `from_file'",
+         :source_line_file => "/Users/lamont/solo/cookbooks/openldap/recipes/default.rb",
+         :source_line_number => "2",
+         :source => "openldap_stuff.conf.erb",
+         :name => "openldap_stuff.conf",
+         :path => resource_path,
          :local => false,
          :cookbook => nil,
          :variables => {},
@@ -32,7 +46,10 @@ describe Chef::Provider::Template::Content do
          :helper_modules => [])
   end
 
-  let(:rendered_file_location) { Dir.tmpdir + '/openldap_stuff.conf' }
+  let(:rendered_file_locations) {
+    [Dir.tmpdir + "/openldap_stuff.conf",
+     enclosing_directory + "/openldap_stuff.conf"]
+  }
 
   let(:run_context) do
     cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
@@ -50,24 +67,59 @@ describe Chef::Provider::Template::Content do
   end
 
   after do
-    FileUtils.rm(rendered_file_location) if ::File.exist?(rendered_file_location)
+    rendered_file_locations.each do |file|
+      FileUtils.rm(file) if ::File.exist?(file)
+    end
   end
 
   it "finds the template file in the cookbook cache if it isn't local" do
-    expect(content.template_location).to eq(CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/openldap_stuff.conf.erb')
+    expect(content.template_location).to eq(CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/openldap_stuff.conf.erb")
   end
 
   it "finds the template file locally if it is local" do
     allow(new_resource).to receive(:local).and_return(true)
-    allow(new_resource).to receive(:source).and_return('/tmp/its_on_disk.erb')
-    expect(content.template_location).to eq('/tmp/its_on_disk.erb')
+    allow(new_resource).to receive(:source).and_return("/tmp/its_on_disk.erb")
+    expect(content.template_location).to eq("/tmp/its_on_disk.erb")
   end
 
   it "should use the cookbook name if defined in the template resource" do
-    allow(new_resource).to receive(:cookbook_name).and_return('apache2')
-    allow(new_resource).to receive(:cookbook).and_return('openldap')
+    allow(new_resource).to receive(:cookbook_name).and_return("apache2")
+    allow(new_resource).to receive(:cookbook).and_return("openldap")
     allow(new_resource).to receive(:source).and_return("test.erb")
-    expect(content.template_location).to eq(CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/test.erb')
+    expect(content.template_location).to eq(CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/test.erb")
+  end
+
+  it "returns a tempfile in the tempdir when :file_staging_uses_destdir is not set" do
+    Chef::Config[:file_staging_uses_destdir] = false
+    expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+    expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
+  end
+
+  it "returns a tempfile in the destdir when :file_staging_uses_destdir is set" do
+    Chef::Config[:file_staging_uses_destdir] = true
+    expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be true
+  end
+
+  context "when creating a tempfile in destdir fails" do
+    let(:enclosing_directory) {
+      canonicalize_path("/nonexisting/path")
+    }
+
+    it "returns a tempfile in the tempdir when :file_deployment_uses_destdir is set to :auto" do
+      Chef::Config[:file_staging_uses_destdir] = :auto
+      expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+      expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
+    end
+
+    it "fails when :file_desployment_uses_destdir is set" do
+      Chef::Config[:file_staging_uses_destdir] = true
+      expect { content.tempfile }.to raise_error(Chef::Exceptions::FileContentStagingError)
+    end
+
+    it "returns a tempfile in the tempdir when :file_desployment_uses_destdir is not set" do
+      expect(content.tempfile.path.start_with?(Dir::tmpdir)).to be true
+      expect(canonicalize_path(content.tempfile.path).start_with?(enclosing_directory)).to be false
+    end
   end
 
   it "creates the template with the rendered content" do
@@ -75,4 +127,43 @@ describe Chef::Provider::Template::Content do
     expect(IO.read(content.tempfile.path)).to eq("slappiness is a warm gun")
   end
 
+  describe "when using location helpers" do
+    let(:new_resource) do
+      double("Chef::Resource::Template (new)",
+             :cookbook_name => "openldap",
+             :recipe_name => "default",
+             :source_line => CHEF_SPEC_DATA + "/cookbooks/openldap/recipes/default.rb:2:in `from_file'",
+             :source_line_file => CHEF_SPEC_DATA + "/cookbooks/openldap/recipes/default.rb",
+             :source_line_number => "2",
+             :source => "helpers.erb",
+             :name => "helpers.erb",
+             :path => CHEF_SPEC_DATA + "/cookbooks/openldap/templates/default/helpers.erb",
+             :local => false,
+             :cookbook => nil,
+             :variables => {},
+             :inline_helper_blocks => {},
+             :inline_helper_modules => [],
+             :helper_modules => [])
+    end
+
+    it "creates the template with the rendered content" do
+      expect(IO.read(content.tempfile.path)).to eql <<EOF
+openldap
+default
+#{CHEF_SPEC_DATA}/cookbooks/openldap/recipes/default.rb:2:in `from_file'
+#{CHEF_SPEC_DATA}/cookbooks/openldap/recipes/default.rb
+2
+helpers.erb
+#{CHEF_SPEC_DATA}/cookbooks/openldap/templates/default/helpers.erb
+openldap
+default
+#{CHEF_SPEC_DATA}/cookbooks/openldap/recipes/default.rb:2:in `from_file'
+#{CHEF_SPEC_DATA}/cookbooks/openldap/recipes/default.rb
+2
+helpers.erb
+#{CHEF_SPEC_DATA}/cookbooks/openldap/templates/default/helpers.erb
+EOF
+    end
+
+  end
 end
diff --git a/spec/unit/provider/template_spec.rb b/spec/unit/provider/template_spec.rb
index 713303d..488039a 100644
--- a/spec/unit/provider/template_spec.rb
+++ b/spec/unit/provider/template_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2008-2013 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,17 +17,16 @@
 # limitations under the License.
 #
 
-require 'stringio'
-require 'spec_helper'
-require 'etc'
-require 'ostruct'
-require 'support/shared/unit/provider/file'
-
+require "stringio"
+require "spec_helper"
+require "etc"
+require "ostruct"
+require "support/shared/unit/provider/file"
 
 describe Chef::Provider::Template do
-  let(:node) { double('Chef::Node') }
-  let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-  let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
+  let(:node) { double("Chef::Node") }
+  let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+  let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
   let(:enclosing_directory) {
     canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
   }
@@ -50,7 +49,7 @@ describe Chef::Provider::Template do
   end
 
   let(:content) do
-    content = double('Chef::Provider::File::Content::Template', :template_location => "/foo/bar/baz")
+    content = double("Chef::Provider::File::Content::Template", :template_location => "/foo/bar/baz")
     allow(File).to receive(:exists?).with("/foo/bar/baz").and_return(true)
     content
   end
@@ -59,9 +58,9 @@ describe Chef::Provider::Template do
 
   context "when creating the template" do
 
-    let(:node) { double('Chef::Node') }
-    let(:events) { double('Chef::Events').as_null_object }  # mock all the methods
-    let(:run_context) { double('Chef::RunContext', :node => node, :events => events) }
+    let(:node) { double("Chef::Node") }
+    let(:events) { double("Chef::Events").as_null_object } # mock all the methods
+    let(:run_context) { double("Chef::RunContext", :node => node, :events => events) }
     let(:enclosing_directory) {
       canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates")))
     }
diff --git a/spec/unit/provider/user/dscl_spec.rb b/spec/unit/provider/user/dscl_spec.rb
index 5ea037d..712fbfc 100644
--- a/spec/unit/provider/user/dscl_spec.rb
+++ b/spec/unit/provider/user/dscl_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Dreamcat4 (<dreamcat4 at gmail.com>)
-# Copyright:: Copyright (c) 2009 OpsCode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,13 +18,13 @@
 
 ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus)
 
-require 'spec_helper'
-require 'ostruct'
-require 'mixlib/shellout'
+require "spec_helper"
+require "ostruct"
+require "mixlib/shellout"
 
 describe Chef::Provider::User::Dscl do
   before do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
   end
   let(:node) {
     node = Chef::Node.new
@@ -114,32 +114,32 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
 
   describe "when shelling out to dscl" do
     it "should run dscl with the supplied cmd /Path args" do
-      shell_return = ShellCmdResult.new('stdout', 'err', 0)
+      shell_return = ShellCmdResult.new("stdout", "err", 0)
       expect(provider).to receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return)
-      expect(provider.run_dscl("cmd /Path args")).to eq('stdout')
+      expect(provider.run_dscl("cmd /Path args")).to eq("stdout")
     end
 
     it "returns an empty string from delete commands" do
-      shell_return = ShellCmdResult.new('out', 'err', 23)
+      shell_return = ShellCmdResult.new("out", "err", 23)
       expect(provider).to receive(:shell_out).with("dscl . -delete /Path args").and_return(shell_return)
       expect(provider.run_dscl("delete /Path args")).to eq("")
     end
 
     it "should raise an exception for any other command" do
-      shell_return = ShellCmdResult.new('out', 'err', 23)
-      expect(provider).to receive(:shell_out).with('dscl . -cmd /Path arguments').and_return(shell_return)
+      shell_return = ShellCmdResult.new("out", "err", 23)
+      expect(provider).to receive(:shell_out).with("dscl . -cmd /Path arguments").and_return(shell_return)
       expect { provider.run_dscl("cmd /Path arguments") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
     end
 
     it "raises an exception when dscl reports 'no such key'" do
-      shell_return = ShellCmdResult.new("No such key: ", 'err', 23)
-      expect(provider).to receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return)
+      shell_return = ShellCmdResult.new("No such key: ", "err", 23)
+      expect(provider).to receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return)
       expect { provider.run_dscl("cmd /Path args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
     end
 
     it "raises an exception when dscl reports 'eDSRecordNotFound'" do
-      shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", 'err', -14136)
-      expect(provider).to receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return)
+      shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", "err", -14136)
+      expect(provider).to receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return)
       expect { provider.run_dscl("cmd /Path args") }.to raise_error(Chef::Exceptions::DsclCommandFailed)
     end
   end
@@ -197,7 +197,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
     end
 
     it "finds a valid, unused uid when none is specified" do
-      expect(provider).to receive(:run_dscl).with("list /Users uid").and_return('')
+      expect(provider).to receive(:run_dscl).with("list /Users uid").and_return("")
       expect(provider).to receive(:run_dscl).with("create /Users/toor UniqueID 501")
       expect(provider).to receive(:get_free_uid).and_return(501)
       provider.dscl_set_uid
@@ -207,7 +207,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
     it "sets the uid specified in the resource" do
       new_resource.uid(1000)
       expect(provider).to receive(:run_dscl).with("create /Users/toor UniqueID 1000").and_return(true)
-      expect(provider).to receive(:run_dscl).with("list /Users uid").and_return('')
+      expect(provider).to receive(:run_dscl).with("list /Users uid").and_return("")
       provider.dscl_set_uid
     end
   end
@@ -219,7 +219,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
 
     before do
       new_resource.supports({ :manage_home => true })
-      new_resource.home('/Users/toor')
+      new_resource.home("/Users/toor")
 
       provider.current_resource = current_resource
     end
@@ -230,40 +230,39 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
       provider.dscl_set_home
     end
 
-
     it "raises InvalidHomeDirectory when the resource's home directory doesn't look right" do
-      new_resource.home('epic-fail')
+      new_resource.home("epic-fail")
       expect { provider.dscl_set_home }.to raise_error(Chef::Exceptions::InvalidHomeDirectory)
     end
 
     it "moves the users home to the new location if it exists and the target location is different" do
       new_resource.supports(:manage_home => true)
 
-      current_home = CHEF_SPEC_DATA + '/old_home_dir'
-      current_home_files = [current_home + '/my-dot-emacs', current_home + '/my-dot-vim']
+      current_home = CHEF_SPEC_DATA + "/old_home_dir"
+      current_home_files = [current_home + "/my-dot-emacs", current_home + "/my-dot-vim"]
       current_resource.home(current_home)
       new_resource.gid(23)
-      allow(::File).to receive(:exists?).with('/old/home/toor').and_return(true)
-      allow(::File).to receive(:exists?).with('/Users/toor').and_return(true)
+      allow(::File).to receive(:exists?).with("/old/home/toor").and_return(true)
+      allow(::File).to receive(:exists?).with("/Users/toor").and_return(true)
 
-      expect(FileUtils).to receive(:mkdir_p).with('/Users/toor').and_return(true)
+      expect(FileUtils).to receive(:mkdir_p).with("/Users/toor").and_return(true)
       expect(FileUtils).to receive(:rmdir).with(current_home)
-      expect(::Dir).to receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*",::File::FNM_DOTMATCH).and_return(current_home_files)
+      expect(::Dir).to receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*", ::File::FNM_DOTMATCH).and_return(current_home_files)
       expect(FileUtils).to receive(:mv).with(current_home_files, "/Users/toor", :force => true)
-      expect(FileUtils).to receive(:chown_R).with('toor','23','/Users/toor')
+      expect(FileUtils).to receive(:chown_R).with("toor", "23", "/Users/toor")
 
       expect(provider).to receive(:run_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'")
       provider.dscl_set_home
     end
 
     it "should raise an exception when the systems user template dir (skel) cannot be found" do
-      allow(::File).to receive(:exists?).and_return(false,false,false)
+      allow(::File).to receive(:exists?).and_return(false, false, false)
       expect { provider.dscl_set_home }.to raise_error(Chef::Exceptions::User)
     end
 
     it "should run ditto to copy any missing files from skel to the new home dir" do
       expect(::File).to receive(:exists?).with("/System/Library/User\ Template/English.lproj").and_return(true)
-      expect(FileUtils).to receive(:chown_R).with('toor', '', '/Users/toor')
+      expect(FileUtils).to receive(:chown_R).with("toor", "", "/Users/toor")
       expect(provider).to receive(:shell_out!).with("ditto '/System/Library/User Template/English.lproj' '/Users/toor'")
       provider.ditto_home
     end
@@ -382,7 +381,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30"
       expect(provider).to receive(:shell_out).with("dscacheutil '-flushcache'")
       expect(provider).to receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do
         if user_plist_file.nil?
-          ShellCmdResult.new('Can not find the file', 'Sorry!!', 1)
+          ShellCmdResult.new("Can not find the file", "Sorry!!", 1)
         else
           ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.plist.xml")), "", 0)
         end
@@ -656,7 +655,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
         it "password_shadow_info should have salted-sha-512 format" do
           shadow_info = provider.prepare_password_shadow_info
           expect(shadow_info).to have_key("SALTED-SHA512")
-          info = shadow_info["SALTED-SHA512"].string.unpack('H*').first
+          info = shadow_info["SALTED-SHA512"].string.unpack("H*").first
           expect(provider.salted_sha512?(info)).to be_truthy
         end
       end
@@ -667,7 +666,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
         it "password_shadow_info should have salted-sha-512 format" do
           shadow_info = provider.prepare_password_shadow_info
           expect(shadow_info).to have_key("SALTED-SHA512")
-          info = shadow_info["SALTED-SHA512"].string.unpack('H*').first
+          info = shadow_info["SALTED-SHA512"].string.unpack("H*").first
           expect(provider.salted_sha512?(info)).to be_truthy
           expect(info).to eq(vagrant_sha_512)
         end
@@ -689,7 +688,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("entropy")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("salt")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("iterations")
-            info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first
+            info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first
             expect(provider.salted_sha512_pbkdf2?(info)).to be_truthy
           end
         end
@@ -705,7 +704,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("entropy")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("salt")
             expect(shadow_info["SALTED-SHA512-PBKDF2"]).to have_key("iterations")
-            info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first
+            info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first
             expect(provider.salted_sha512_pbkdf2?(info)).to be_truthy
             expect(info).to eq(vagrant_sha_512_pbkdf2)
           end
@@ -720,7 +719,7 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
     end
 
     it "should sleep and flush the dscl cache before saving the password" do
-      expect(provider).to receive(:prepare_password_shadow_info).and_return({ })
+      expect(provider).to receive(:prepare_password_shadow_info).and_return({})
       mock_shellout = double("Mock::Shellout")
       allow(mock_shellout).to receive(:run_command)
       expect(Mixlib::ShellOut).to receive(:new).and_return(mock_shellout)
@@ -760,6 +759,13 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
         provider.dscl_create_comment
       end
 
+      it "sets the comment field to username" do
+        new_resource.comment nil
+        expect(provider).to receive(:run_dscl).with("create /Users/toor RealName '#mockssuck'").and_return(true)
+        provider.dscl_create_comment
+        expect(new_resource.comment).to eq("#mockssuck")
+      end
+
       it "should run run_dscl with create /Users/user PrimaryGroupID to set the users primary group" do
         expect(provider).to receive(:run_dscl).with("create /Users/toor PrimaryGroupID '1001'").and_return(true)
         provider.dscl_set_gid
@@ -784,11 +790,18 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
       end
 
       it "should raise an exception when the group does not exist" do
-        shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", 'err', -14136)
-        expect(provider).to receive(:shell_out).with('dscl . -read /Groups/newgroup PrimaryGroupID').and_return(shell_return)
+        shell_return = ShellCmdResult.new("<dscl_cmd> DS Error: -14136 (eDSRecordNotFound)", "err", -14136)
+        expect(provider).to receive(:shell_out).with("dscl . -read /Groups/newgroup PrimaryGroupID").and_return(shell_return)
         expect { provider.dscl_set_gid }.to raise_error(Chef::Exceptions::GroupIDNotFound)
       end
     end
+
+    it "should set group ID to 20 if it's not specified" do
+      new_resource.gid nil
+      expect(provider).to receive(:run_dscl).with("create /Users/toor PrimaryGroupID '20'").ordered.and_return(true)
+      provider.dscl_set_gid
+      expect(new_resource.gid).to eq(20)
+    end
   end
 
   describe "when the user exists and chef is managing it" do
@@ -800,8 +813,8 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30")
       new_resource.username "mud"
       new_resource.uid 2342
       new_resource.gid 2342
-      new_resource.home '/Users/death'
-      new_resource.password 'goaway'
+      new_resource.home "/Users/death"
+      new_resource.password "goaway"
     end
 
     it "sets the user, comment field, uid, gid, moves the home directory, sets the shell, and sets the password" do
diff --git a/spec/unit/provider/user/pw_spec.rb b/spec/unit/provider/user/pw_spec.rb
index b225972..1e9fda9 100644
--- a/spec/unit/provider/user/pw_spec.rb
+++ b/spec/unit/provider/user/pw_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Stephen Haynes (<sh at nomitor.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::User::Pw do
   before(:each) do
@@ -48,11 +48,11 @@ describe Chef::Provider::User::Pw do
 
   describe "setting options to the pw command" do
     field_list = {
-      'comment' => "-c",
-      'home' => "-d",
-      'gid' => "-g",
-      'uid' => "-u",
-      'shell' => "-s"
+      "comment" => "-c",
+      "home" => "-d",
+      "gid" => "-g",
+      "uid" => "-u",
+      "shell" => "-s",
     }
     field_list.each do |attribute, option|
       it "should check for differences in #{attribute} between the new and current resources" do
@@ -67,7 +67,7 @@ describe Chef::Provider::User::Pw do
       end
 
       it "should set the option for #{attribute} if the new resources #{attribute} is not null, without homedir management" do
-        allow(@new_resource).to receive(:supports).and_return({:manage_home => false})
+        allow(@new_resource).to receive(:supports).and_return({ :manage_home => false })
         allow(@new_resource).to receive(attribute).and_return("hola")
         expect(@provider.set_options).to eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}'")
       end
@@ -75,7 +75,7 @@ describe Chef::Provider::User::Pw do
 
     it "should combine all the possible options" do
       match_string = " adam"
-      field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+      field_list.sort { |a, b| a[0] <=> b[0] }.each do |attribute, option|
         allow(@new_resource).to receive(attribute).and_return("hola")
         match_string << " #{option} 'hola'"
       end
@@ -126,7 +126,7 @@ describe Chef::Provider::User::Pw do
     end
 
     it "should run pw userdel with the new resources user name and -r if manage_home is true" do
-      expect(@provider).to receive(:run_command).with({ :command => "pw userdel #{@new_resource.username} -r"}).and_return(true)
+      expect(@provider).to receive(:run_command).with({ :command => "pw userdel #{@new_resource.username} -r" }).and_return(true)
       @provider.remove_user
     end
   end
@@ -145,14 +145,14 @@ describe Chef::Provider::User::Pw do
 
   describe "when locking the user" do
     it "should run pw lock with the new resources username" do
-      expect(@provider).to receive(:run_command).with({ :command => "pw lock #{@new_resource.username}"})
+      expect(@provider).to receive(:run_command).with({ :command => "pw lock #{@new_resource.username}" })
       @provider.lock_user
     end
   end
 
   describe "when unlocking the user" do
     it "should run pw unlock with the new resources username" do
-      expect(@provider).to receive(:run_command).with({ :command => "pw unlock #{@new_resource.username}"})
+      expect(@provider).to receive(:run_command).with({ :command => "pw unlock #{@new_resource.username}" })
       @provider.unlock_user
     end
   end
diff --git a/spec/unit/provider/user/solaris_spec.rb b/spec/unit/provider/user/solaris_spec.rb
index ef62fd1..984fab5 100644
--- a/spec/unit/provider/user/solaris_spec.rb
+++ b/spec/unit/provider/user/solaris_spec.rb
@@ -1,7 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Dave Eddy (<dave at daveeddy.com>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2015-2016, Dave Eddy
 #
 # License:: Apache License, Version 2.0
 #
@@ -18,7 +20,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus)
+
+require "mixlib/shellout"
+require "spec_helper"
 
 describe Chef::Provider::User::Solaris do
 
@@ -31,15 +36,6 @@ describe Chef::Provider::User::Solaris do
     p
   end
 
-  supported_useradd_options = {
-    'comment' => "-c",
-    'gid' => "-g",
-    'uid' => "-u",
-    'shell' => "-s"
-  }
-
-  include_examples "a useradd-based user provider", supported_useradd_options
-
   describe "when we want to set a password" do
     before(:each) do
       @node = Chef::Node.new
@@ -77,4 +73,65 @@ describe Chef::Provider::User::Solaris do
     end
   end
 
+  describe "when managing user locked status" do
+    before(:each) do
+      @node = Chef::Node.new
+      @events = Chef::EventDispatch::Dispatcher.new
+      @run_context = Chef::RunContext.new(@node, {}, @events)
+
+      @new_resource = Chef::Resource::User.new("dave")
+      @current_resource = @new_resource.dup
+
+      @provider = Chef::Provider::User::Solaris.new(@new_resource, @run_context)
+      @provider.current_resource = @current_resource
+    end
+    describe "when determining if the user is locked" do
+
+      # locked shadow lines
+      [
+        "dave:LK:::::::",
+        "dave:*LK*:::::::",
+        "dave:*LK*foobar:::::::",
+        "dave:*LK*bahamas10:::::::",
+        "dave:*LK*L....:::::::",
+      ].each do |shadow|
+        it "should return true if user is locked with #{shadow}" do
+          shell_return = ShellCmdResult.new(shadow + "\n", "", 0)
+          expect(provider).to receive(:shell_out!).with("getent", "shadow", @new_resource.username).and_return(shell_return)
+          expect(provider.check_lock).to eql(true)
+        end
+      end
+
+      # unlocked shadow lines
+      [
+        "dave:NP:::::::",
+        "dave:*NP*:::::::",
+        "dave:foobar:::::::",
+        "dave:bahamas10:::::::",
+        "dave:L...:::::::",
+      ].each do |shadow|
+        it "should return false if user is unlocked with #{shadow}" do
+          shell_return = ShellCmdResult.new(shadow + "\n", "", 0)
+          expect(provider).to receive(:shell_out!).with("getent", "shadow", @new_resource.username).and_return(shell_return)
+          expect(provider.check_lock).to eql(false)
+        end
+      end
+    end
+
+    describe "when locking the user" do
+      it "should run passwd -l with the new resources username" do
+        shell_return = ShellCmdResult.new("", "", 0)
+        expect(provider).to receive(:shell_out!).with("passwd", "-l", @new_resource.username).and_return(shell_return)
+        provider.lock_user
+      end
+    end
+
+    describe "when unlocking the user" do
+      it "should run passwd -u with the new resources username" do
+        shell_return = ShellCmdResult.new("", "", 0)
+        expect(provider).to receive(:shell_out!).with("passwd", "-u", @new_resource.username).and_return(shell_return)
+        provider.unlock_user
+      end
+    end
+  end
 end
diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb
index b9f6ee0..7c67449 100644
--- a/spec/unit/provider/user/useradd_spec.rb
+++ b/spec/unit/provider/user/useradd_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 #
 # License:: Apache License, Version 2.0
 #
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/provider/user/useradd'
+require "spec_helper"
+require "chef/provider/user/useradd"
 
 describe Chef::Provider::User::Useradd do
 
@@ -30,11 +30,11 @@ describe Chef::Provider::User::Useradd do
   end
 
   supported_useradd_options = {
-    'comment' => "-c",
-    'gid' => "-g",
-    'uid' => "-u",
-    'shell' => "-s",
-    'password' => "-p"
+    "comment" => "-c",
+    "gid" => "-g",
+    "uid" => "-u",
+    "shell" => "-s",
+    "password" => "-p",
   }
 
   include_examples "a useradd-based user provider", supported_useradd_options
diff --git a/spec/unit/provider/user/windows_spec.rb b/spec/unit/provider/user/windows_spec.rb
index e51e20a..4a62e6e 100644
--- a/spec/unit/provider/user/windows_spec.rb
+++ b/spec/unit/provider/user/windows_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class Chef
   class Util
@@ -104,11 +104,11 @@ describe Chef::Provider::User::Windows do
       end
 
       it "marks the home_dir attribute to be updated" do
-        expect(@provider.set_options[:home_dir]).to eq('/home/adam')
+        expect(@provider.set_options[:home_dir]).to eq("/home/adam")
       end
 
-      it "marks the primary_group_id attribute to be updated" do
-        expect(@provider.set_options[:primary_group_id]).to eq(1000)
+      it "ignores the primary_group_id attribute" do
+        expect(@provider.set_options[:primary_group_id]).to eq(nil)
       end
 
       it "marks the user_id attribute to be updated" do
@@ -116,30 +116,30 @@ describe Chef::Provider::User::Windows do
       end
 
       it "marks the script_path attribute to be updated" do
-        expect(@provider.set_options[:script_path]).to eq('/usr/bin/zsh')
+        expect(@provider.set_options[:script_path]).to eq("/usr/bin/zsh")
       end
 
       it "marks the password attribute to be updated" do
-        expect(@provider.set_options[:password]).to eq('abracadabra')
+        expect(@provider.set_options[:password]).to eq("abracadabra")
       end
     end
   end
 
   describe "when creating the user" do
     it "should call @net_user.add with the return of set_options" do
-      allow(@provider).to receive(:set_options).and_return(:name=> "monkey")
-      expect(@net_user).to receive(:add).with(:name=> "monkey")
+      allow(@provider).to receive(:set_options).and_return(:name => "monkey")
+      expect(@net_user).to receive(:add).with(:name => "monkey")
       @provider.create_user
     end
   end
 
   describe "manage_user" do
     before(:each) do
-      allow(@provider).to receive(:set_options).and_return(:name=> "monkey")
+      allow(@provider).to receive(:set_options).and_return(:name => "monkey")
     end
 
     it "should call @net_user.update with the return of set_options" do
-      expect(@net_user).to receive(:update).with(:name=> "monkey")
+      expect(@net_user).to receive(:update).with(:name => "monkey")
       @provider.manage_user
     end
   end
diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb
index 3811686..0794ce0 100644
--- a/spec/unit/provider/user_spec.rb
+++ b/spec/unit/provider/user_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 EtcPwnamIsh = Struct.new(:name, :passwd, :uid, :gid, :gecos, :dir, :shell, :change, :uclass, :expire)
 EtcGrnamIsh = Struct.new(:name, :passwd, :gid, :mem)
@@ -83,7 +83,7 @@ describe Chef::Provider::User do
 
     it "should create a current resource with the same name as the new resource" do
       @provider.load_current_resource
-      expect(@provider.current_resource.name).to eq('adam')
+      expect(@provider.current_resource.name).to eq("adam")
     end
 
     it "should set the username of the current resource to the username of the new resource" do
@@ -92,7 +92,7 @@ describe Chef::Provider::User do
     end
 
     it "should change the encoding of gecos to the encoding of the new resource" do
-      @pw_user.gecos.force_encoding('ASCII-8BIT')
+      @pw_user.gecos.force_encoding("ASCII-8BIT")
       @provider.load_current_resource
       expect(@provider.current_resource.comment.encoding).to eq(@new_resource.comment.encoding)
     end
@@ -114,7 +114,7 @@ describe Chef::Provider::User do
       :gid => :gid,
       :comment => :gecos,
       :home => :dir,
-      :shell => :shell
+      :shell => :shell,
     }
     user_attrib_map.each do |user_attrib, getpwnam_attrib|
       it "should set the current resources #{user_attrib} based on getpwnam #{getpwnam_attrib}" do
@@ -141,10 +141,10 @@ describe Chef::Provider::User do
     describe "and running assertions" do
       def self.shadow_lib_unavail?
         begin
-          require 'rubygems'
-          require 'shadow'
-        rescue LoadError => e
-          pending "ruby-shadow gem not installed for dynamic load test"
+          require "rubygems"
+          require "shadow"
+        rescue LoadError
+          skip "ruby-shadow gem not installed for dynamic load test"
           true
         else
           false
@@ -161,11 +161,11 @@ describe Chef::Provider::User do
 
       unless shadow_lib_unavail?
         context "and we have the ruby-shadow gem" do
-          pending "and we are not root (rerun this again as root)", :requires_unprivileged_user => true
+          skip "and we are not root (rerun this again as root)", :requires_unprivileged_user => true
 
           context "and we are root", :requires_root => true do
             it "should pass assertions when ruby-shadow can be loaded" do
-              @provider.action = 'create'
+              @provider.action = "create"
               original_method = @provider.method(:require)
               expect(@provider).to receive(:require) { |*args| original_method.call(*args) }
               passwd_info = Struct::PasswdEntry.new(:sp_namp => "adm ", :sp_pwdp => "$1$T0N0Q.lc$nyG6pFI3Dpqa5cxUz/57j0", :sp_lstchg => 14861, :sp_min => 0, :sp_max => 99999,
@@ -183,7 +183,7 @@ describe Chef::Provider::User do
         expect(@provider).to receive(:require).with("shadow") { raise LoadError }
         @provider.load_current_resource
         @provider.define_resource_requirements
-        expect {@provider.process_resource_requirements}.to raise_error Chef::Exceptions::MissingLibrary
+        expect { @provider.process_resource_requirements }.to raise_error Chef::Exceptions::MissingLibrary
       end
 
     end
@@ -192,13 +192,13 @@ describe Chef::Provider::User do
   describe "compare_user" do
     let(:mapping) {
       {
-        'username' => ["adam", "Adam"],
-        'comment' => ["Adam Jacob", "adam jacob"],
-        'uid' => [1000, 1001],
-        'gid' => [1000, 1001],
-        'home' => ["/home/adam", "/Users/adam"],
-        'shell'=> ["/usr/bin/zsh", "/bin/bash"],
-        'password'=> ["abcd","12345"]
+        "username" => ["adam", "Adam"],
+        "comment" => ["Adam Jacob", "adam jacob"],
+        "uid" => [1000, 1001],
+        "gid" => [1000, 1001],
+        "home" => ["/home/adam", "/Users/adam"],
+        "shell" => ["/usr/bin/zsh", "/bin/bash"],
+        "password" => ["abcd", "12345"],
       }
     }
 
@@ -380,7 +380,6 @@ describe Chef::Provider::User do
     end
   end
 
-
   describe "action_lock" do
     before(:each) do
       allow(@provider).to receive(:load_current_resource)
@@ -441,8 +440,8 @@ describe Chef::Provider::User do
 
   describe "convert_group_name" do
     before do
-      @new_resource.gid('999')
-      @group = EtcGrnamIsh.new('wheel', '*', 999, [])
+      @new_resource.gid("999")
+      @group = EtcGrnamIsh.new("wheel", "*", 999, [])
     end
 
     it "should lookup the group name locally" do
@@ -452,11 +451,20 @@ describe Chef::Provider::User do
 
     it "should raise an error if we can't translate the group name during resource assertions" do
       expect(Etc).to receive(:getgrnam).and_raise(ArgumentError)
+      @provider.action = :create
       @provider.define_resource_requirements
       @provider.convert_group_name
       expect { @provider.process_resource_requirements }.to raise_error(Chef::Exceptions::User)
     end
 
+    it "does not raise an error if we can't translate the group name during resource assertions if we are removing the user" do
+      expect(Etc).to receive(:getgrnam).and_raise(ArgumentError)
+      @provider.action = :remove
+      @provider.define_resource_requirements
+      @provider.convert_group_name
+      expect { @provider.process_resource_requirements }.not_to raise_error
+    end
+
     it "should set the new resources gid to the integerized version if available" do
       expect(Etc).to receive(:getgrnam).with("999").and_return(@group)
       @provider.convert_group_name
diff --git a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
index 2a4dccd..29d49ff 100644
--- a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
+++ b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Phil Dibowitz (<phild at fb.com>)
-# Copyright:: Copyright (c) 2013 Facebook
+# Copyright:: Copyright 2013-2016, Facebook
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
   before(:each) do
@@ -25,7 +25,7 @@ describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
     @new_resource = Chef::Resource::WhyrunSafeRubyBlock.new("bloc party")
-    @new_resource.block { $evil_global_evil_laugh = :mwahahaha}
+    @new_resource.block { $evil_global_evil_laugh = :mwahahaha }
     @provider = Chef::Provider::WhyrunSafeRubyBlock.new(@new_resource, @run_context)
   end
 
@@ -44,4 +44,3 @@ describe Chef::Provider::WhyrunSafeRubyBlock, "initialize" do
   end
 
 end
-
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index bdf6d06..3ac7da5 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at getchef.com>)
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,345 +16,426 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/mixin/convert_to_class_name'
-require 'chef/provider_resolver'
+require "spec_helper"
+require "chef/mixin/convert_to_class_name"
+require "chef/provider_resolver"
+require "chef/platform/service_helpers"
+require "support/shared/integration/integration_helper"
+require "tmpdir"
+require "fileutils"
 
 include Chef::Mixin::ConvertToClassName
 
-describe Chef::ProviderResolver do
-
-  let(:node) do
-    node = Chef::Node.new
-    allow(node).to receive(:[]).with(:os).and_return(os)
-    allow(node).to receive(:[]).with(:platform_family).and_return(platform_family)
-    allow(node).to receive(:[]).with(:platform).and_return(platform)
-    allow(node).to receive(:[]).with(:platform_version).and_return(platform_version)
-    allow(node).to receive(:is_a?).and_return(Chef::Node)
-    node
-  end
-
-  let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) }
-
-  let(:action) { :start }
-
-  let(:resolved_provider) { provider_resolver.resolve }
+# Open up Provider so we can write things down easier in here
+#module Chef::Provider
 
-  let(:provider) { nil }
-
-  let(:resource_name) { :service }
-
-  let(:resource) { double(Chef::Resource, provider: provider, resource_name: resource_name) }
-
-  before do
-    allow(resource).to receive(:is_a?).with(Chef::Resource).and_return(true)
-  end
+describe Chef::ProviderResolver do
+  include IntegrationSupport
 
-  describe "resolving service resource" do
-    def stub_service_providers(*services)
-      services ||= []
-      allow(Chef::Platform::ServiceHelpers).to receive(:service_resource_providers)
-        .and_return(services)
+  # Root the filesystem under a temp directory so Chef.path_to will point at it
+  when_the_repository "is empty" do
+    before do
+      allow(Chef).to receive(:path_to) { |path| File.join(path_to(""), path) }
     end
 
-    def stub_service_configs(*configs)
-      configs ||= []
-      allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-        .and_return(configs)
+    let(:resource_name) { :service }
+    let(:provider) { nil }
+    let(:action) { :start }
+
+    let(:node) do
+      node = Chef::Node.new
+      node.automatic[:os] = os
+      node.automatic[:platform_family] = platform_family
+      node.automatic[:platform] = platform
+      node.automatic[:platform_version] = platform_version
+      node.automatic[:kernel] = { machine: "i386" }
+      node
     end
-
-    before do
-      expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
-      allow(resource).to receive(:service_name).and_return("ntp")
+    let(:run_context) { Chef::RunContext.new(node, nil, nil) }
+
+    let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) }
+    let(:resolved_provider) do
+      begin
+        resource ? resource.provider_for_action(action).class : nil
+      rescue Chef::Exceptions::ProviderNotFound
+        nil
+      end
     end
 
-    shared_examples_for "an ubuntu platform with upstart, update-rc.d and systemd" do
-      before do
-        stub_service_providers(:debian, :invokercd, :upstart, :systemd)
+    let(:service_name) { "test" }
+    let(:resource) do
+      resource_class = Chef::ResourceResolver.resolve(resource_name, node: node)
+      if resource_class
+        resource = resource_class.new(service_name, run_context)
+        resource.provider = provider if provider
       end
+      resource
+    end
 
-      it "when only the SysV init script exists, it returns a Service::Debian provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :initd, :systemd ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+    def self.on_platform(platform, *tags,
+      platform_version: "11.0.1",
+      platform_family: nil,
+      os: nil,
+      &block)
+      Array(platform).each do |platform|
+        Array(platform_version).each do |platform_version|
+          on_one_platform(platform, platform_version, platform_family || platform, os || platform_family || platform, *tags, &block)
+        end
       end
+    end
 
-      it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :initd, :upstart, :systemd ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
-      end
+    def self.on_one_platform(platform, platform_version, platform_family, os, *tags, &block)
+      describe "on #{platform} #{platform_version}, platform_family: #{platform_family}, os: #{os}", *tags do
+        let(:os)               { os }
+        let(:platform)         { platform }
+        let(:platform_family)  { platform_family }
+        let(:platform_version) { platform_version }
 
-      it "when only the Upstart script exists, it returns a Service::Upstart provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :upstart, :systemd ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
-      end
+        define_singleton_method(:os) { os }
+        define_singleton_method(:platform) { platform }
+        define_singleton_method(:platform_family) { platform_family }
+        define_singleton_method(:platform_version) { platform_version }
 
-      it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :systemd ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
-      end
-      it "when only the SysV init script exists, it returns a Service::Debian provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :initd ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+        instance_eval(&block)
       end
+    end
 
-      it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :initd, :upstart ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
-      end
+    def self.expect_providers(**providers)
+      providers.each do |name, expected|
+        describe name.to_s do
+          let(:resource_name) { name }
+
+          tags = []
+          expected_provider = nil
+          expected_resource = nil
+          Array(expected).each do |p|
+            if p.is_a?(Class) && p <= Chef::Provider
+              expected_provider = p
+            elsif p.is_a?(Class) && p <= Chef::Resource
+              expected_resource = p
+            else
+              tags << p
+            end
+          end
 
-      it "when only the Upstart script exists, it returns a Service::Upstart provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ :upstart ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          if expected_resource && expected_provider
+            it "'#{name}' resolves to resource #{expected_resource} and provider #{expected_provider}", *tags do
+              expect(resource.class).to eql(expected_resource)
+              provider = double(expected_provider, class: expected_provider)
+              expect(provider).to receive(:action=).with(action)
+              expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider)
+              expect(resolved_provider).to eql(expected_provider)
+            end
+          elsif expected_provider
+            it "'#{name}' resolves to provider #{expected_provider}", *tags do
+              provider = double(expected_provider)
+              expect(provider).to receive(:action=).with(action)
+              expect(expected_provider).to receive(:new).with(resource, run_context).and_return(provider)
+              expect(resolved_provider).to eql(expected_provider)
+            end
+          else
+            it "'#{name}' fails to resolve (since #{name.inspect} is unsupported on #{platform} #{platform_version})", *tags do
+              expect(resolved_provider).to be_nil
+            end
+          end
+        end
       end
+    end
 
-      it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
-        allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-          .and_return( [ ] )
-        expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+    describe "resolving service resource" do
+      def stub_service_providers(*services)
+        services.each do |service|
+          case service
+          when :debian
+            file "usr/sbin/update-rc.d", ""
+          when :invokercd
+            file "usr/sbin/invoke-rc.d", ""
+          when :insserv
+            file "sbin/insserv", ""
+          when :upstart
+            file "sbin/initctl", ""
+          when :redhat
+            file "sbin/chkconfig", ""
+          when :systemd
+            file "proc/1/comm", "systemd\n"
+          else
+            raise ArgumentError, service
+          end
+        end
       end
-    end
 
-    shared_examples_for "an ubuntu platform with upstart and update-rc.d" do
-      before do
-        stub_service_providers(:debian, :invokercd, :upstart)
+      def stub_service_configs(*configs)
+        configs.each do |config|
+          case config
+          when :initd
+            file "etc/init.d/#{service_name}", ""
+          when :upstart
+            file "etc/init/#{service_name}.conf", ""
+          when :xinetd
+            file "etc/xinetd.d/#{service_name}", ""
+          when :etc_rcd
+            file "etc/rc.d/#{service_name}", ""
+          when :usr_local_etc_rcd
+            file "usr/local/etc/rc.d/#{service_name}", ""
+          when :systemd
+            file "proc/1/comm", "systemd\n"
+            file "etc/systemd/system/#{service_name}.service", ""
+          else
+            raise ArgumentError, config
+          end
+        end
       end
 
-      # needs to be handled by the highest priority init.d handler
-      context "when only the SysV init script exists" do
+      shared_examples_for "an ubuntu platform with upstart, update-rc.d and systemd" do
         before do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :initd ] )
+          stub_service_providers(:debian, :invokercd, :upstart, :systemd)
         end
 
-        it "enables init, invokercd, debian and upstart providers" do
-          expect(provider_resolver.enabled_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-            Chef::Provider::Service::Upstart,
-          )
+        it "when only the SysV init script exists, it returns a Service::Debian provider" do
+          stub_service_configs(:initd, :systemd)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
         end
 
-        it "supports all the enabled handlers except for upstart" do
-          expect(provider_resolver.supported_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-          )
-          expect(provider_resolver.supported_handlers).to_not include(
-            Chef::Provider::Service::Upstart,
-          )
+        it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+          stub_service_configs(:initd, :upstart, :systemd)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
         end
 
-        it "returns a Service::Debian provider" do
-          expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+        it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+          stub_service_configs(:upstart, :systemd)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
         end
-      end
 
-      # on ubuntu this must be handled by upstart, the init script will exit 1 and fail
-      context "when both SysV and Upstart scripts exist" do
-        before do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :initd, :upstart ] )
+        it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+          stub_service_configs(:systemd)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
         end
 
-        it "enables init, invokercd, debian and upstart providers" do
-          expect(provider_resolver.enabled_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-            Chef::Provider::Service::Upstart,
-          )
+        it "when only the SysV init script exists, it returns a Service::Debian provider" do
+          stub_service_configs(:initd)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
         end
 
-        it "supports all the enabled handlers" do
-          expect(provider_resolver.supported_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-            Chef::Provider::Service::Upstart,
-          )
+        it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+          stub_service_configs(:initd, :upstart)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
         end
 
-        it "returns a Service::Upstart provider" do
+        it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+          stub_service_configs(:upstart)
           expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
         end
+
+        it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+          stub_service_configs
+          expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+        end
       end
 
-      # this case is a pure-upstart script which is easy
-      context "when only the Upstart script exists" do
+      shared_examples_for "an ubuntu platform with upstart and update-rc.d" do
         before do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :upstart ] )
+          stub_service_providers(:debian, :invokercd, :upstart)
         end
 
-        it "enables init, invokercd, debian and upstart providers" do
-          expect(provider_resolver.enabled_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-            Chef::Provider::Service::Upstart,
-          )
-        end
+        # needs to be handled by the highest priority init.d handler
+        context "when only the SysV init script exists" do
+          before do
+            stub_service_configs(:initd)
+          end
 
-        it "supports only the upstart handler" do
-          expect(provider_resolver.supported_handlers).to include(
-            Chef::Provider::Service::Upstart,
-          )
-          expect(provider_resolver.supported_handlers).to_not include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-          )
-        end
+          it "enables init, invokercd, debian and upstart providers" do
+            expect(provider_resolver.enabled_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+              Chef::Provider::Service::Upstart,
+            )
+          end
 
-        it "returns a Service::Upstart provider" do
-          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
-        end
-      end
+          it "supports all the enabled handlers except for upstart" do
+            expect(provider_resolver.supported_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+            )
+            expect(provider_resolver.supported_handlers).to_not include(
+              Chef::Provider::Service::Upstart
+            )
+          end
 
-      # this case is important to get correct for why-run when no config is setup
-      context "when both do not exist" do
-        before do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ ] )
+          it "returns a Service::Debian provider" do
+            expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+          end
         end
 
-        it "enables init, invokercd, debian and upstart providers" do
-          expect(provider_resolver.enabled_handlers).to include(
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-            Chef::Provider::Service::Upstart,
-          )
-        end
+        # on ubuntu this must be handled by upstart, the init script will exit 1 and fail
+        context "when both SysV and Upstart scripts exist" do
+          before do
+            stub_service_configs(:initd, :upstart)
+          end
 
-        it "no providers claim to support the resource" do
-          expect(provider_resolver.supported_handlers).to_not include(
-            Chef::Provider::Service::Upstart,
-            Chef::Provider::Service::Debian,
-            Chef::Provider::Service::Init,
-            Chef::Provider::Service::Invokercd,
-          )
-        end
+          it "enables init, invokercd, debian and upstart providers" do
+            expect(provider_resolver.enabled_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+              Chef::Provider::Service::Upstart,
+            )
+          end
 
-        it "returns a Debian Provider" do
-          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
-        end
-      end
-    end
+          it "supports all the enabled handlers" do
+            expect(provider_resolver.supported_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+              Chef::Provider::Service::Upstart,
+            )
+          end
 
-    shared_examples_for "a debian platform using the insserv provider" do
-      context "with a default install" do
-        before do
-          stub_service_providers(:debian, :invokercd, :insserv)
+          it "returns a Service::Upstart provider" do
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
         end
 
-        it "uses the Service::Insserv Provider to manage sysv init scripts" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :initd ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
-        end
+        # this case is a pure-upstart script which is easy
+        context "when only the Upstart script exists" do
+          before do
+            stub_service_configs(:upstart)
+          end
 
-        it "uses the Service::Insserv Provider when there is no config" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
-        end
-      end
+          it "enables init, invokercd, debian and upstart providers" do
+            expect(provider_resolver.enabled_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+              Chef::Provider::Service::Upstart,
+            )
+          end
 
-      context "when the user has installed upstart" do
-        before do
-          stub_service_providers(:debian, :invokercd, :insserv, :upstart)
-        end
+          it "supports only the upstart handler" do
+            expect(provider_resolver.supported_handlers).to include(
+              Chef::Provider::Service::Upstart
+            )
+            expect(provider_resolver.supported_handlers).to_not include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+            )
+          end
 
-        it "when only the SysV init script exists, it returns an Insserv  provider" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :initd ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+          it "returns a Service::Upstart provider" do
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
         end
 
-        it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :initd, :upstart ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
-        end
+        # this case is important to get correct for why-run when no config is setup
+        context "when both do not exist" do
+          before do
+            stub_service_configs
+          end
 
-        it "when only the Upstart script exists, it returns a Service::Upstart provider" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ :upstart ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
-        end
+          it "enables init, invokercd, debian and upstart providers" do
+            expect(provider_resolver.enabled_handlers).to include(
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+              Chef::Provider::Service::Upstart,
+            )
+          end
 
-        it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
-          allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
-            .and_return( [ ] )
-          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          it "no providers claim to support the resource" do
+            expect(provider_resolver.supported_handlers).to_not include(
+              Chef::Provider::Service::Upstart,
+              Chef::Provider::Service::Debian,
+              Chef::Provider::Service::Init,
+              Chef::Provider::Service::Invokercd,
+            )
+          end
+
+          it "returns a Debian Provider" do
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
         end
       end
-    end
 
-    describe "on Ubuntu 14.10" do
-      let(:os) { "linux" }
-      let(:platform) { "ubuntu" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "14.04" }
+      shared_examples_for "a debian platform using the insserv provider" do
+        context "with a default install" do
+          before do
+            stub_service_providers(:debian, :invokercd, :insserv)
+          end
 
-      it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
-    end
+          it "uses the Service::Insserv Provider to manage sysv init scripts" do
+            stub_service_configs(:initd)
+            expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+          end
 
-    describe "on Ubuntu 14.04" do
-      let(:os) { "linux" }
-      let(:platform) { "ubuntu" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "14.04" }
+          it "uses the Service::Insserv Provider when there is no config" do
+            stub_service_configs
+            expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+          end
+        end
 
-      it_behaves_like "an ubuntu platform with upstart and update-rc.d"
-    end
+        context "when the user has installed upstart" do
+          before do
+            stub_service_providers(:debian, :invokercd, :insserv, :upstart)
+          end
 
-    describe "on Ubuntu 10.04" do
-      let(:os) { "linux" }
-      let(:platform) { "ubuntu" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "10.04" }
+          it "when only the SysV init script exists, it returns an Insserv  provider" do
+            stub_service_configs(:initd)
+            expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+          end
 
-      it_behaves_like "an ubuntu platform with upstart and update-rc.d"
-    end
+          it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+            stub_service_configs(:initd, :upstart)
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
 
-    # old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
-    describe "on Debian 4.0" do
-      let(:os) { "linux" }
-      let(:platform) { "debian" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "4.0" }
+          it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+            stub_service_configs(:upstart)
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
 
-      #it_behaves_like "a debian platform using the debian provider"
-    end
+          it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+            stub_service_configs
+            expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+          end
+        end
+      end
 
-    # Debian replaced the debian provider with insserv in the FIXME:VERSION distro
-    describe "on Debian 7.0" do
-      let(:os) { "linux" }
-      let(:platform) { "debian" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "7.0" }
+      on_platform "ubuntu", platform_version: "15.10", platform_family: "debian", os: "linux" do
+        it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
 
-      it_behaves_like "a debian platform using the insserv provider"
-    end
+        it "when the unit-files are missing and system-ctl list-unit-files returns an error" do
+          stub_service_providers(:debian, :invokercd, :upstart, :systemd)
+          stub_service_configs(:initd, :upstart)
+          mock_shellout_command("/bin/systemctl list-unit-files", exitstatus: 1)
+          expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+        end
+      end
+
+      on_platform "ubuntu", platform_version: "14.10", platform_family: "debian", os: "linux" do
+        it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
+      end
+
+      on_platform "ubuntu", platform_version: "14.04", platform_family: "debian", os: "linux" do
+        it_behaves_like "an ubuntu platform with upstart and update-rc.d"
+      end
 
-    %w{solaris2 openindiana opensolaris nexentacore omnios smartos}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "solaris2" }
-        let(:platform) { platform }
-        let(:platform_family) { platform }
-        let(:platform_version) { "5.11" }
+      on_platform "ubuntu", platform_version: "10.04", platform_family: "debian", os: "linux" do
+        it_behaves_like "an ubuntu platform with upstart and update-rc.d"
+      end
+
+      # old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
+      on_platform "debian", platform_version: "4.0", os: "linux" do
+        #it_behaves_like "a debian platform using the debian provider"
+      end
+
+      # Debian replaced the debian provider with insserv in the FIXME:VERSION distro
+      on_platform "debian", platform_version: "7.0", os: "linux" do
+        it_behaves_like "a debian platform using the insserv provider"
+      end
 
+      on_platform %w{solaris2 openindiana opensolaris nexentacore omnios smartos}, os: "solaris2", platform_version: "5.11" do
         it "returns a Solaris provider" do
           stub_service_providers
           stub_service_configs
@@ -364,19 +445,12 @@ describe Chef::ProviderResolver do
         it "always returns a Solaris provider" do
           # no matter what we stub on the next two lines we should get a Solaris provider
           stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
-          stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+          stub_service_configs(:initd, :upstart, :xinetd, :usr_local_etc_rcd, :systemd)
           expect(resolved_provider).to eql(Chef::Provider::Service::Solaris)
         end
       end
-    end
-
-    %w{mswin mingw32 windows}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "windows" }
-        let(:platform) { platform }
-        let(:platform_family) { "windows" }
-        let(:platform_version) { "5.11" }
 
+      on_platform %w{mswin mingw32 windows}, platform_family: "windows", platform_version: "5.11" do
         it "returns a Windows provider" do
           stub_service_providers
           stub_service_configs
@@ -386,19 +460,12 @@ describe Chef::ProviderResolver do
         it "always returns a Windows provider" do
           # no matter what we stub on the next two lines we should get a Windows provider
           stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
-          stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+          stub_service_configs(:initd, :upstart, :xinetd, :usr_local_etc_rcd, :systemd)
           expect(resolved_provider).to eql(Chef::Provider::Service::Windows)
         end
       end
-    end
-
-    %w{mac_os_x mac_os_x_server}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "darwin" }
-        let(:platform) { platform }
-        let(:platform_family) { "mac_os_x" }
-        let(:platform_version) { "10.9.2" }
 
+      on_platform %w{mac_os_x mac_os_x_server}, os: "darwin", platform_family: "mac_os_x", platform_version: "10.9.2" do
         it "returns a Macosx provider" do
           stub_service_providers
           stub_service_configs
@@ -408,19 +475,12 @@ describe Chef::ProviderResolver do
         it "always returns a Macosx provider" do
           # no matter what we stub on the next two lines we should get a Macosx provider
           stub_service_providers(:debian, :invokercd, :insserv, :upstart, :redhat, :systemd)
-          stub_service_configs(:initd, :upstart, :xinetd, :user_local_etc_rcd, :systemd)
+          stub_service_configs(:initd, :upstart, :xinetd, :usr_local_etc_rcd, :systemd)
           expect(resolved_provider).to eql(Chef::Provider::Service::Macosx)
         end
       end
-    end
-
-    %w{freebsd netbsd}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { platform }
-        let(:platform) { platform }
-        let(:platform_family) { platform }
-        let(:platform_version) { "10.0-RELEASE" }
 
+      on_platform %w{freebsd netbsd}, platform_version: "3.1.4" do
         it "returns a Freebsd provider if it finds the /usr/local/etc/rc.d initscript" do
           stub_service_providers
           stub_service_configs(:usr_local_etc_rcd)
@@ -453,237 +513,381 @@ describe Chef::ProviderResolver do
           expect(resolved_provider).to eql(Chef::Provider::Service::Freebsd)
         end
       end
-    end
-
-  end
-
-  describe "for the package provider" do
-    let(:resource_name) { :package }
 
-    before do
-      expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
     end
 
-    %w{mac_os_x mac_os_x_server}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "darwin" }
-        let(:platform) { platform }
-        let(:platform_family) { "mac_os_x" }
-        let(:platform_version) { "10.9.2" }
-
-
-        it "returns a Chef::Provider::Package::Homebrew provider" do
-          expect(resolved_provider).to eql(Chef::Provider::Package::Homebrew)
+    PROVIDERS =
+    {
+      bash:                   [ Chef::Resource::Bash, Chef::Provider::Script ],
+      breakpoint:             [ Chef::Resource::Breakpoint, Chef::Provider::Breakpoint ],
+      chef_gem:               [ Chef::Resource::ChefGem, Chef::Provider::Package::Rubygems ],
+      cookbook_file:          [ Chef::Resource::CookbookFile, Chef::Provider::CookbookFile ],
+      csh:                    [ Chef::Resource::Csh, Chef::Provider::Script ],
+      deploy:                 [ Chef::Resource::Deploy, Chef::Provider::Deploy::Timestamped ],
+      deploy_revision:        [ Chef::Resource::DeployRevision, Chef::Provider::Deploy::Revision ],
+      directory:              [ Chef::Resource::Directory, Chef::Provider::Directory ],
+      easy_install_package:   [ Chef::Resource::EasyInstallPackage, Chef::Provider::Package::EasyInstall ],
+      erl_call:               [ Chef::Resource::ErlCall, Chef::Provider::ErlCall ],
+      execute:                [ Chef::Resource::Execute, Chef::Provider::Execute ],
+      file:                   [ Chef::Resource::File, Chef::Provider::File ],
+      gem_package:            [ Chef::Resource::GemPackage, Chef::Provider::Package::Rubygems ],
+      git:                    [ Chef::Resource::Git, Chef::Provider::Git ],
+      group:                  [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+      homebrew_package:       [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+      http_request:           [ Chef::Resource::HttpRequest, Chef::Provider::HttpRequest ],
+      ifconfig:               [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+      link:                   [ Chef::Resource::Link, Chef::Provider::Link ],
+      log:                    [ Chef::Resource::Log, Chef::Provider::Log::ChefLog ],
+      macports_package:       [ Chef::Resource::MacportsPackage, Chef::Provider::Package::Macports ],
+      mdadm:                  [ Chef::Resource::Mdadm, Chef::Provider::Mdadm ],
+      mount:                  [ Chef::Resource::Mount, Chef::Provider::Mount::Mount ],
+      perl:                   [ Chef::Resource::Perl, Chef::Provider::Script ],
+      portage_package:        [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+      python:                 [ Chef::Resource::Python, Chef::Provider::Script ],
+      remote_directory:       [ Chef::Resource::RemoteDirectory, Chef::Provider::RemoteDirectory ],
+      route:                  [ Chef::Resource::Route, Chef::Provider::Route ],
+      ruby:                   [ Chef::Resource::Ruby, Chef::Provider::Script ],
+      ruby_block:             [ Chef::Resource::RubyBlock, Chef::Provider::RubyBlock ],
+      script:                 [ Chef::Resource::Script, Chef::Provider::Script ],
+      subversion:             [ Chef::Resource::Subversion, Chef::Provider::Subversion ],
+      template:               [ Chef::Resource::Template, Chef::Provider::Template ],
+      timestamped_deploy:     [ Chef::Resource::TimestampedDeploy, Chef::Provider::Deploy::Timestamped ],
+      user:                   [ Chef::Resource::User, Chef::Provider::User::Useradd ],
+      whyrun_safe_ruby_block: [ Chef::Resource::WhyrunSafeRubyBlock, Chef::Provider::WhyrunSafeRubyBlock ],
+
+      # We want to check that these are unsupported:
+      apt_package: nil,
+      bff_package: nil,
+      dpkg_package: nil,
+      dsc_script: nil,
+      ips_package: nil,
+      pacman_package: nil,
+      paludis_package: nil,
+      rpm_package: nil,
+      smartos_package: nil,
+      solaris_package: nil,
+      yum_package: nil,
+      windows_package: nil,
+      windows_service: nil,
+
+      "linux" => {
+        apt_package:     [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+        dpkg_package:    [ Chef::Resource::DpkgPackage, Chef::Provider::Package::Dpkg ],
+        pacman_package:  [ Chef::Resource::PacmanPackage, Chef::Provider::Package::Pacman ],
+        paludis_package: [ Chef::Resource::PaludisPackage, Chef::Provider::Package::Paludis ],
+        rpm_package:     [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+        yum_package:     [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
+
+        "debian" => {
+          ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Debian ],
+          package:  [ Chef::Resource::AptPackage, Chef::Provider::Package::Apt ],
+  #        service: [ Chef::Resource::DebianService, Chef::Provider::Service::Debian ],
+
+          "debian" => {
+            "7.0" => {
+            },
+            "6.0" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+  #            service: [ Chef::Resource::InsservService, Chef::Provider::Service::Insserv ],
+            },
+            "5.0" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ]
+            },
+          },
+          "gcel" => {
+            "3.1.4" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ]
+            }
+          },
+          "linaro" => {
+            "3.1.4" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ]
+            }
+          },
+          "linuxmint" => {
+            "3.1.4" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ],
+  #            service: [ Chef::Resource::UpstartService, Chef::Provider::Service::Upstart ],
+            }
+          },
+          "raspbian" => {
+            "3.1.4" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ]
+            }
+          },
+          "ubuntu" => {
+            "11.10" => {
+            },
+            "10.04" => {
+              ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig ]
+            },
+          },
+        },
+
+        "arch" => {
+          # TODO should be Chef::Resource::PacmanPackage
+          package: [ Chef::Resource::Package, Chef::Provider::Package::Pacman ],
+
+          "arch" => {
+            "3.1.4" => {
+            }
+          },
+        },
+
+        "freebsd" => {
+          group: [ Chef::Resource::Group, Chef::Provider::Group::Pw ],
+          user:  [ Chef::Resource::User, Chef::Provider::User::Pw ],
+
+          "freebsd" => {
+            "3.1.4" => {
+            }
+          },
+        },
+        "suse" => {
+          group: [ Chef::Resource::Group, Chef::Provider::Group::Gpasswd ],
+          "suse" => {
+            "12.0" => {
+            },
+            %w{11.1 11.2 11.3} => {
+              group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ]
+            },
+          },
+          "opensuse" => {
+  #          service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+            package: [ Chef::Resource::ZypperPackage, Chef::Provider::Package::Zypper ],
+            group:   [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+            "12.3" => {
+            },
+            "12.2" => {
+              group: [ Chef::Resource::Group, Chef::Provider::Group::Suse ]
+            },
+          },
+        },
+
+        "gentoo" => {
+          # TODO should be Chef::Resource::PortagePackage
+          package:         [ Chef::Resource::Package, Chef::Provider::Package::Portage ],
+          portage_package: [ Chef::Resource::PortagePackage, Chef::Provider::Package::Portage ],
+  #        service: [ Chef::Resource::GentooService, Chef::Provider::Service::Gentoo ],
+
+          "gentoo" => {
+            "3.1.4" => {
+            }
+          },
+        },
+
+        "rhel" => {
+  #        service: [ Chef::Resource::SystemdService, Chef::Provider::Service::Systemd ],
+          package:  [ Chef::Resource::YumPackage, Chef::Provider::Package::Yum ],
+          ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Redhat ],
+
+          %w{amazon xcp xenserver ibm_powerkvm cloudlinux parallels} => {
+            "3.1.4" => {
+  #            service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+            }
+          },
+          %w{redhat centos scientific oracle} => {
+            "7.0" => {
+            },
+            "6.0" => {
+  #            service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+            },
+          },
+          "fedora" => {
+            "15.0" => {
+            },
+            "14.0" => {
+  #            service: [ Chef::Resource::RedhatService, Chef::Provider::Service::Redhat ],
+            },
+          },
+        },
+
+      },
+
+      "darwin" => {
+        %w{mac_os_x mac_os_x_server} => {
+          group:   [ Chef::Resource::Group, Chef::Provider::Group::Dscl ],
+          package: [ Chef::Resource::HomebrewPackage, Chef::Provider::Package::Homebrew ],
+          osx_profile: [ Chef::Resource::OsxProfile, Chef::Provider::OsxProfile],
+          user:    [ Chef::Resource::User, Chef::Provider::User::Dscl ],
+
+          "mac_os_x" => {
+            "10.9.2" => {
+            }
+          },
+        }
+      },
+
+      "windows" => {
+        batch:             [ Chef::Resource::Batch, Chef::Provider::Batch ],
+        dsc_script:        [ Chef::Resource::DscScript, Chef::Provider::DscScript ],
+        env:               [ Chef::Resource::Env, Chef::Provider::Env::Windows ],
+        group:             [ Chef::Resource::Group, Chef::Provider::Group::Windows ],
+        mount:             [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ],
+        package:           [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+        powershell_script: [ Chef::Resource::PowershellScript, Chef::Provider::PowershellScript ],
+        service:           [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
+        user:              [ Chef::Resource::User, Chef::Provider::User::Windows ],
+        windows_package:   [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
+        windows_service:   [ Chef::Resource::WindowsService, Chef::Provider::Service::Windows ],
+
+        "windows" => {
+          %w{mswin mingw32 windows} => {
+            "10.9.2" => {
+            }
+          }
+        },
+      },
+
+      "aix" => {
+        bff_package: [ Chef::Resource::BffPackage, Chef::Provider::Package::Aix ],
+        cron: [ Chef::Resource::Cron, Chef::Provider::Cron::Aix ],
+        group: [ Chef::Resource::Group, Chef::Provider::Group::Aix ],
+        ifconfig: [ Chef::Resource::Ifconfig, Chef::Provider::Ifconfig::Aix ],
+        mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Aix ],
+        # TODO should be Chef::Resource::BffPackage
+        package: [ Chef::Resource::Package, Chef::Provider::Package::Aix ],
+        rpm_package: [ Chef::Resource::RpmPackage, Chef::Provider::Package::Rpm ],
+        user: [ Chef::Resource::User, Chef::Provider::User::Aix ],
+  #      service: [ Chef::Resource::AixService, Chef::Provider::Service::Aix ],
+
+        "aix" => {
+          "aix" => {
+            "5.6" => {
+            }
+          }
+        },
+      },
+
+      "hpux" => {
+        "hpux" => {
+          "hpux" => {
+            "3.1.4" => {
+              group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ]
+            }
+          }
+        }
+      },
+
+      "netbsd" => {
+        "netbsd" => {
+          "netbsd" => {
+            "3.1.4" => {
+              group: [ Chef::Resource::Group, Chef::Provider::Group::Groupmod ]
+            }
+          }
+        }
+      },
+
+      "openbsd" => {
+        group: [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+        package: [ Chef::Resource::OpenbsdPackage, Chef::Provider::Package::Openbsd ],
+
+        "openbsd" => {
+          "openbsd" => {
+            "3.1.4" => {
+            }
+          }
+        },
+      },
+
+      "solaris2" => {
+        group:           [ Chef::Resource::Group, Chef::Provider::Group::Usermod ],
+        ips_package:     [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ],
+        package:         [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
+        mount:           [ Chef::Resource::Mount, Chef::Provider::Mount::Solaris ],
+        solaris_package: [ Chef::Resource::SolarisPackage, Chef::Provider::Package::Solaris ],
+
+        "smartos" => {
+          smartos_package: [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
+          package:         [ Chef::Resource::SmartosPackage, Chef::Provider::Package::SmartOS ],
+
+          "smartos" => {
+            "3.1.4" => {
+            }
+          },
+        },
+
+        "solaris2" => {
+          "nexentacore" => {
+            "3.1.4" => {
+            }
+          },
+          "omnios" => {
+            "3.1.4" => {
+              user: [ Chef::Resource::User, Chef::Provider::User::Solaris ]
+            }
+          },
+          "openindiana" => {
+            "3.1.4" => {
+            }
+          },
+          "opensolaris" => {
+            "3.1.4" => {
+            }
+          },
+          "solaris2" => {
+            user: [ Chef::Resource::User, Chef::Provider::User::Solaris ],
+            "5.11" => {
+              package: [ Chef::Resource::IpsPackage, Chef::Provider::Package::Ips ]
+            },
+            "5.9" => {
+            },
+          },
+        },
+
+      },
+
+      "solaris" => {
+        "solaris" => {
+          "solaris" => {
+            "3.1.4" => {
+            }
+          }
+        }
+      },
+
+      "exherbo" => {
+        "exherbo" => {
+          "exherbo" => {
+            "3.1.4" => {
+              # TODO should be Chef::Resource::PaludisPackage
+              package: [ Chef::Resource::Package, Chef::Provider::Package::Paludis ]
+            }
+          }
+        }
+      },
+    }
+
+    def self.create_provider_tests(providers, test, expected, filter)
+      expected = expected.merge(providers.select { |key, value| key.is_a?(Symbol) })
+      providers.each do |key, value|
+        if !key.is_a?(Symbol)
+          next_test = test.merge({ filter => key })
+          next_filter =
+            case filter
+            when :os
+              :platform_family
+            when :platform_family
+              :platform
+            when :platform
+              :platform_version
+            when :platform_version
+              nil
+            else
+              raise "Hash too deep; only os, platform_family, platform and platform_version supported"
+            end
+          create_provider_tests(value, next_test, expected, next_filter)
         end
       end
-    end
-  end
-
-  provider_mapping = {
-    "mac_os_x" => {
-      :package => Chef::Provider::Package::Homebrew,
-      :user => Chef::Provider::User::Dscl,
-      :group => Chef::Provider::Group::Dscl,
-    },
-    "mac_os_x_server" => {
-      :package => Chef::Provider::Package::Homebrew,
-      :user => Chef::Provider::User::Dscl,
-      :group => Chef::Provider::Group::Dscl,
-    },
-    "mswin" => {
-      :env =>  Chef::Provider::Env::Windows,
-      :user => Chef::Provider::User::Windows,
-      :group => Chef::Provider::Group::Windows,
-      :mount => Chef::Provider::Mount::Windows,
-      :batch => Chef::Provider::Batch,
-      :powershell_script => Chef::Provider::PowershellScript,
-    },
-    "mingw32" => {
-      :env =>  Chef::Provider::Env::Windows,
-      :user => Chef::Provider::User::Windows,
-      :group => Chef::Provider::Group::Windows,
-      :mount => Chef::Provider::Mount::Windows,
-      :batch => Chef::Provider::Batch,
-      :powershell_script => Chef::Provider::PowershellScript,
-    },
-    "windows" => {
-      :env =>  Chef::Provider::Env::Windows,
-      :user => Chef::Provider::User::Windows,
-      :group => Chef::Provider::Group::Windows,
-      :mount => Chef::Provider::Mount::Windows,
-      :batch => Chef::Provider::Batch,
-      :powershell_script => Chef::Provider::PowershellScript,
-    },
-    "aix" => {
-      :cron => Chef::Provider::Cron::Aix,
-    },
-    "netbsd"=> {
-      :group => Chef::Provider::Group::Groupmod,
-    },
-    "openbsd" => {
-      :group => Chef::Provider::Group::Usermod,
-      :package => Chef::Provider::Package::Openbsd,
-    },
-  }
-
-  def self.do_platform(platform_hash)
-    platform_hash.each do |resource, provider|
-      describe "for #{resource}" do
-        let(:resource_name) { resource }
-
-        it "resolves to a #{provider}" do
-          expect(resolved_provider).to eql(provider)
+      # If there is no filter, we're as deep as we need to go
+      if !filter
+        on_platform test.delete(:platform), test do
+          expect_providers(expected)
         end
       end
     end
-  end
-
-  describe "individual platform mappings" do
-    let(:resource_name) { :user }
-
-    before do
-      expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
-    end
-
-    %w{mac_os_x mac_os_x_server}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "darwin" }
-        let(:platform) { platform }
-        let(:platform_family) { "mac_os_x" }
-        let(:platform_version) { "10.9.2" }
-
-        do_platform(provider_mapping[platform])
-      end
-    end
-
-    %w{mswin mingw32 windows}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { "windows" }
-        let(:platform) { platform }
-        let(:platform_family) { "windows" }
-        let(:platform_version) { "10.9.2" }
 
-        do_platform(provider_mapping[platform])
-      end
-    end
-
-    describe "on AIX" do
-      let(:os) { "aix" }
-      let(:platform) { "aix" }
-      let(:platform_family) { "aix" }
-      let(:platform_version) { "6.2" }
-
-      do_platform(provider_mapping['aix'])
-    end
-
-    %w{netbsd openbsd}.each do |platform|
-      describe "on #{platform}" do
-        let(:os) { platform }
-        let(:platform) { platform }
-        let(:platform_family) { platform }
-        let(:platform_version) { "10.0-RELEASE" }
-
-        do_platform(provider_mapping[platform])
-      end
-    end
-  end
-
-  describe "resolving static providers" do
-    def resource_class(resource)
-      Chef::Resource.const_get(convert_to_class_name(resource.to_s))
-    end
-      static_mapping = {
-        apt_package:  Chef::Provider::Package::Apt,
-        bash: Chef::Provider::Script,
-        bff_package: Chef::Provider::Package::Aix,
-        breakpoint:  Chef::Provider::Breakpoint,
-        chef_gem: Chef::Provider::Package::Rubygems,
-        cookbook_file:  Chef::Provider::CookbookFile,
-        csh:  Chef::Provider::Script,
-        deploy:   Chef::Provider::Deploy::Timestamped,
-        deploy_revision:  Chef::Provider::Deploy::Revision,
-        directory:  Chef::Provider::Directory,
-        dpkg_package: Chef::Provider::Package::Dpkg,
-        dsc_script: Chef::Provider::DscScript,
-        easy_install_package:  Chef::Provider::Package::EasyInstall,
-        erl_call: Chef::Provider::ErlCall,
-        execute:  Chef::Provider::Execute,
-        file: Chef::Provider::File,
-        gem_package: Chef::Provider::Package::Rubygems,
-        git:  Chef::Provider::Git,
-        homebrew_package: Chef::Provider::Package::Homebrew,
-        http_request: Chef::Provider::HttpRequest,
-        ips_package: Chef::Provider::Package::Ips,
-        link:  Chef::Provider::Link,
-        log:  Chef::Provider::Log::ChefLog,
-        macports_package:  Chef::Provider::Package::Macports,
-        mdadm:  Chef::Provider::Mdadm,
-        pacman_package: Chef::Provider::Package::Pacman,
-        paludis_package: Chef::Provider::Package::Paludis,
-        perl: Chef::Provider::Script,
-        portage_package:  Chef::Provider::Package::Portage,
-        python: Chef::Provider::Script,
-        remote_directory: Chef::Provider::RemoteDirectory,
-        route:  Chef::Provider::Route,
-        rpm_package:  Chef::Provider::Package::Rpm,
-        ruby:  Chef::Provider::Script,
-        ruby_block:   Chef::Provider::RubyBlock,
-        script:   Chef::Provider::Script,
-        smartos_package:  Chef::Provider::Package::SmartOS,
-        solaris_package:  Chef::Provider::Package::Solaris,
-        subversion:   Chef::Provider::Subversion,
-        template:   Chef::Provider::Template,
-        timestamped_deploy:  Chef::Provider::Deploy::Timestamped,
-        whyrun_safe_ruby_block:  Chef::Provider::WhyrunSafeRubyBlock,
-        windows_package:  Chef::Provider::Package::Windows,
-        windows_service:  Chef::Provider::Service::Windows,
-        yum_package:  Chef::Provider::Package::Yum,
-      }
-
-    describe "on Ubuntu 14.04" do
-      let(:os) { "linux" }
-      let(:platform) { "ubuntu" }
-      let(:platform_family) { "debian" }
-      let(:platform_version) { "14.04" }
-
-      supported_providers = [
-        :apt_package, :bash, :breakpoint, :chef_gem, :cookbook_file, :csh, :deploy,
-        :deploy_revision, :directory, :dpkg_package, :easy_install_package, :erl_call,
-        :execute, :file, :gem_package, :git, :homebrew_package, :http_request, :link,
-        :log, :macports_package, :pacman_package, :paludis_package, :perl, :python,
-        :remote_directory, :route, :rpm_package, :ruby, :ruby_block, :script, :subversion,
-        :template, :timestamped_deploy, :whyrun_safe_ruby_block, :yum_package,
-      ]
-
-      supported_providers.each do |static_resource|
-        static_provider = static_mapping[static_resource]
-        context "when the resource is a #{static_resource}" do
-          let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
-          let(:action) { :start }  # in reality this doesn't matter much
-          it "should resolve to a #{static_provider} provider" do
-            expect(provider_resolver).not_to receive(:maybe_chef_platform_lookup)
-            expect(resolved_provider).to eql(static_provider)
-          end
-        end
-      end
-
-      unsupported_providers = [
-        :bff_package, :dsc_script, :ips_package, :smartos_package,
-        :solaris_package, :windows_package, :windows_service,
-      ]
-
-      unsupported_providers.each do |static_resource|
-        static_provider = static_mapping[static_resource]
-        context "when the resource is a #{static_resource}" do
-          let(:resource) { double(Chef::Resource, provider: nil, resource_name: static_resource) }
-          let(:action) { :start }  # in reality this doesn't matter much
-          it "should fall back into the old provider mapper code and hooks" do
-            retval = Object.new
-            expect(provider_resolver).to receive(:maybe_chef_platform_lookup).and_return(retval)
-            expect(resolved_provider).to equal(retval)
-          end
-        end
-      end
-    end
+    create_provider_tests(PROVIDERS, {}, {}, :os)
   end
 end
diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb
index 5a21b09..2bc2ae7 100644
--- a/spec/unit/provider_spec.rb
+++ b/spec/unit/provider_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-
+require "spec_helper"
 
 class NoWhyrunDemonstrator < Chef::Provider
   attr_reader :system_state_altered
   def whyrun_supported?
     false
   end
-  def load_current_resource
 
+  def load_current_resource
   end
+
   def action_foo
     @system_state_altered = true
   end
@@ -49,6 +49,12 @@ class ConvergeActionDemonstrator < Chef::Provider
   end
 end
 
+class CheckResourceSemanticsDemonstrator < ConvergeActionDemonstrator
+  def check_resource_semantics!
+    raise Chef::Exceptions::InvalidResourceSpecification.new("check_resource_semantics!")
+  end
+end
+
 describe Chef::Provider do
   before(:each) do
     @cookbook_collection = Chef::CookbookCollection.new([])
@@ -89,6 +95,10 @@ describe Chef::Provider do
     expect(@provider.send(:whyrun_supported?)).to eql(false)
   end
 
+  it "should do nothing for check_resource_semantics! by default" do
+    expect { @provider.check_resource_semantics! }.not_to raise_error
+  end
+
   it "should return true for action_nothing" do
     expect(@provider.action_nothing).to eql(true)
   end
@@ -96,17 +106,15 @@ describe Chef::Provider do
   it "evals embedded recipes with a pristine resource collection" do
     @provider.run_context.instance_variable_set(:@resource_collection, "doesn't matter what this is")
     temporary_collection = nil
-    snitch = Proc.new {temporary_collection = @run_context.resource_collection}
+    snitch = Proc.new { temporary_collection = @run_context.resource_collection }
     @provider.send(:recipe_eval, &snitch)
     expect(temporary_collection).to be_an_instance_of(Chef::ResourceCollection)
     expect(@provider.run_context.instance_variable_get(:@resource_collection)).to eq("doesn't matter what this is")
   end
 
   it "does not re-load recipes when creating the temporary run context" do
-    # we actually want to test that RunContext#load is never called, but we
-    # can't stub all instances of an object with rspec's mocks. :/
-    allow(Chef::RunContext).to receive(:new).and_raise("not supposed to happen")
-    snitch = Proc.new {temporary_collection = @run_context.resource_collection}
+    expect_any_instance_of(Chef::RunContext).not_to receive(:load)
+    snitch = Proc.new { temporary_collection = @run_context.resource_collection }
     @provider.send(:recipe_eval, &snitch)
   end
 
@@ -176,6 +184,15 @@ describe Chef::Provider do
         expect(@resource).not_to be_updated_by_last_action
       end
     end
+
+    describe "and the resource is invalid" do
+      let(:provider) { CheckResourceSemanticsDemonstrator.new(@resource, @run_context) }
+
+      it "fails with InvalidResourceSpecification when run" do
+        expect { provider.run_action(:foo) }.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
+      end
+
+    end
   end
 
 end
diff --git a/spec/unit/pure_application_spec.rb b/spec/unit/pure_application_spec.rb
index 5d879a7..a25acc2 100644
--- a/spec/unit/pure_application_spec.rb
+++ b/spec/unit/pure_application_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@
 # be able to test only Chef::Application.
 # Regression test for CHEF-5169
 
-require 'chef/application'
+require "chef/application"
 
 describe "Chef::Application" do
   let(:app) { Chef::Application.new }
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 7442f44..8f43d0c 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,30 +19,24 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/platform/resource_priority_map'
+require "spec_helper"
+require "chef/platform/resource_priority_map"
 
 describe Chef::Recipe do
 
-  let(:cookbook_repo) { File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks")) }
-
-  let(:cookbook_loader) do
-    loader = Chef::CookbookLoader.new(cookbook_repo)
-    loader.load_cookbooks
-    loader
+  let(:cookbook_collection) do
+    cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks"))
+    cookbook_loader = Chef::CookbookLoader.new(cookbook_repo)
+    cookbook_loader.load_cookbooks
+    Chef::CookbookCollection.new(cookbook_loader)
   end
 
-  let(:cookbook_collection) { Chef::CookbookCollection.new(cookbook_loader) }
-
   let(:node) do
-    Chef::Node.new.tap {|n| n.normal[:tags] = [] }
-  end
-
-  let(:events) do
-    Chef::EventDispatch::Dispatcher.new
+    Chef::Node.new
   end
 
   let(:run_context) do
+    events = Chef::EventDispatch::Dispatcher.new
     Chef::RunContext.new(node, cookbook_collection, events)
   end
 
@@ -83,7 +77,7 @@ describe Chef::Recipe do
       it "should require a name argument" do
         expect {
           recipe.cat
-        }.to raise_error(ArgumentError, "You must supply a name when declaring a cat resource")
+        }.to raise_error(ArgumentError)
       end
 
       it "should allow regular errors (not NameErrors) to pass unchanged" do
@@ -106,7 +100,7 @@ describe Chef::Recipe do
           end
         end
 
-        expect(run_context.resource_collection.map{|r| r.name}).to eql(["monkey", "dog", "cat"])
+        expect(run_context.resource_collection.map { |r| r.name }).to eql(["monkey", "dog", "cat"])
       end
 
       it "should return the new resource after creating it" do
@@ -121,7 +115,8 @@ describe Chef::Recipe do
 
         it "locate resource for particular platform" do
           ShaunTheSheep = Class.new(Chef::Resource)
-          ShaunTheSheep.provides :laughter, :on_platforms => ["television"]
+          ShaunTheSheep.resource_name :shaun_the_sheep
+          ShaunTheSheep.provides :laughter, :platform => ["television"]
           node.automatic[:platform] = "television"
           node.automatic[:platform_version] = "123"
           res = recipe.laughter "timmy"
@@ -131,6 +126,7 @@ describe Chef::Recipe do
 
         it "locate a resource for all platforms" do
           YourMom = Class.new(Chef::Resource)
+          YourMom.resource_name :your_mom
           YourMom.provides :love_and_caring
           res = recipe.love_and_caring "mommy"
           expect(res.name).to eql("mommy")
@@ -141,9 +137,9 @@ describe Chef::Recipe do
           before do
             node.automatic[:platform] = "nbc_sports"
             Sounders = Class.new(Chef::Resource)
-            Sounders.provides :football, platform: "nbc_sports"
+            Sounders.resource_name :sounders
             TottenhamHotspur = Class.new(Chef::Resource)
-            TottenhamHotspur.provides :football, platform: "nbc_sports"
+            TottenhamHotspur.resource_name :tottenham_hotspur
           end
 
           after do
@@ -151,25 +147,20 @@ describe Chef::Recipe do
             Object.send(:remove_const, :TottenhamHotspur)
           end
 
-          it "warns if resolution of the two resources is ambiguous" do
-            expect(Chef::Log).to receive(:warn).at_least(:once).with(/Ambiguous resource precedence/)
-            res1 = recipe.football "club world cup"
-            expect(res1.name).to eql("club world cup")
-            # the class of res1 is not defined.
-          end
+          it "selects the first one alphabetically" do
+            Sounders.provides :football, platform: "nbc_sports"
+            TottenhamHotspur.provides :football, platform: "nbc_sports"
 
-          it "selects one if it is given priority" do
-            expect(Chef::Log).not_to receive(:warn)
-            Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, TottenhamHotspur, platform: "nbc_sports")
             res1 = recipe.football "club world cup"
             expect(res1.name).to eql("club world cup")
-            expect(res1).to be_a_kind_of(TottenhamHotspur)
+            expect(res1).to be_a_kind_of(Sounders)
           end
 
-          it "selects the other one if it is given priority" do
-            expect(Chef::Log).not_to receive(:warn)
-            Chef::Platform::ResourcePriorityMap.instance.send(:priority, :football, Sounders, platform: "nbc_sports")
-            res1 = recipe.football "club world cup"
+          it "selects the first one alphabetically even if the declaration order is reversed" do
+            TottenhamHotspur.provides :football2, platform: "nbc_sports"
+            Sounders.provides :football2, platform: "nbc_sports"
+
+            res1 = recipe.football2 "club world cup"
             expect(res1.name).to eql("club world cup")
             expect(res1).to be_a_kind_of(Sounders)
           end
@@ -279,14 +270,12 @@ describe Chef::Recipe do
 
       it "validating resources via build_resource" do
         expect {recipe.build_resource(:remote_file, "klopp") do
-          source Chef::DelayedEvaluator.new {"http://chef.io"}
+          source Chef::DelayedEvaluator.new { "http://chef.io" }
         end}.to_not raise_error
       end
 
     end
 
-
-
     describe "creating resources via declare_resource" do
       let(:zm_resource) do
         recipe.declare_resource(:zen_master, "klopp") do
@@ -308,6 +297,34 @@ describe Chef::Recipe do
         zm_resource # force let binding evaluation
         expect(run_context.resource_collection.resources(:zen_master => "klopp")).to eq(zm_resource)
       end
+
+      it "will insert another resource if create_if_missing is not set (cloned resource as of Chef-12)" do
+        zm_resource
+        recipe.declare_resource(:zen_master, "klopp")
+        expect(run_context.resource_collection.count).to eql(2)
+      end
+
+      it "does not insert two resources if create_if_missing is used" do
+        zm_resource
+        recipe.declare_resource(:zen_master, "klopp", create_if_missing: true)
+        expect(run_context.resource_collection.count).to eql(1)
+      end
+
+      context "injecting a different run_context" do
+        let(:run_context2) do
+          events = Chef::EventDispatch::Dispatcher.new
+          Chef::RunContext.new(node, cookbook_collection, events)
+        end
+
+        it "should insert resources into the correct run_context" do
+          zm_resource
+          recipe.declare_resource(:zen_master, "klopp2", run_context: run_context2)
+          run_context2.resource_collection.lookup("zen_master[klopp2]")
+          expect { run_context2.resource_collection.lookup("zen_master[klopp]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+          expect { run_context.resource_collection.lookup("zen_master[klopp2]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
+          run_context.resource_collection.lookup("zen_master[klopp]")
+        end
+      end
     end
 
     describe "creating a resource with short name" do
@@ -336,7 +353,6 @@ describe Chef::Recipe do
         end
       end
 
-
       it "defines the resource using the declaration name with long name" do
         resource_zn_follower
         expect(run_context.resource_collection.lookup("zen_follower[srst]")).not_to be_nil
@@ -348,7 +364,7 @@ describe Chef::Recipe do
       it "gives a sane error message when using method_missing" do
         expect do
           recipe.no_such_resource("foo")
-        end.to raise_error(NoMethodError, %q[No resource or method named `no_such_resource' for `Chef::Recipe "test"'])
+        end.to raise_error(NoMethodError, %q{No resource or method named `no_such_resource' for `Chef::Recipe "test"'})
       end
 
       it "gives a sane error message when using method_missing 'bare'" do
@@ -357,7 +373,7 @@ describe Chef::Recipe do
             # Giving an argument will change this from NameError to NoMethodError
             no_such_resource
           end
-        end.to raise_error(NameError, %q[No resource, method, or local variable named `no_such_resource' for `Chef::Recipe "test"'])
+        end.to raise_error(NameError, %q{No resource, method, or local variable named `no_such_resource' for `Chef::Recipe "test"'})
       end
 
       it "gives a sane error message when using build_resource" do
@@ -409,7 +425,7 @@ describe Chef::Recipe do
 
       it "does not copy the action from the first resource" do
         expect(original_resource.action).to eq([:score])
-        expect(duplicated_resource.action).to eq(:nothing)
+        expect(duplicated_resource.action).to eq([:nothing])
       end
 
       it "does not copy the source location of the first resource" do
@@ -577,6 +593,36 @@ describe Chef::Recipe do
       expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
       openldap_recipe.include_recipe "::default"
     end
+
+    it "will not load a recipe twice when called first from an LWRP provider" do
+      openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+      expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+      allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+      expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.include_recipe "::default"
+      expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.openldap_includer("do it").run_action(:run)
+    end
+
+    it "will not load a recipe twice when called last from an LWRP provider" do
+      openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+      expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+      allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+      expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.openldap_includer("do it").run_action(:run)
+      expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.include_recipe "::default"
+    end
+
+    it "will not load a recipe twice when called both times from an LWRP provider" do
+      openldap_recipe = Chef::Recipe.new("openldap", "test", run_context)
+      expect(node).to receive(:loaded_recipe).with(:openldap, "default").exactly(:once)
+      allow(run_context).to receive(:unreachable_cookbook?).with(:openldap).and_return(false)
+      expect(cookbook_collection[:openldap]).to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.openldap_includer("do it").run_action(:run)
+      expect(cookbook_collection[:openldap]).not_to receive(:load_recipe).with("default", run_context)
+      openldap_recipe.openldap_includer("do it").run_action(:run)
+    end
   end
 
   describe "tags" do
@@ -588,21 +634,25 @@ describe Chef::Recipe do
       end
     end
 
+    it "should initialize tags to an empty Array" do
+      expect(node.tags).to eql([])
+    end
+
     it "should set tags via tag" do
       recipe.tag "foo"
-      expect(node[:tags]).to include("foo")
+      expect(node.tags).to include("foo")
     end
 
     it "should set multiple tags via tag" do
       recipe.tag "foo", "bar"
-      expect(node[:tags]).to include("foo")
-      expect(node[:tags]).to include("bar")
+      expect(node.tags).to include("foo")
+      expect(node.tags).to include("bar")
     end
 
     it "should not set the same tag twice via tag" do
       recipe.tag "foo"
       recipe.tag "foo"
-      expect(node[:tags]).to eql([ "foo" ])
+      expect(node.tags).to eql([ "foo" ])
     end
 
     it "should return the current list of tags from tag with no arguments" do
@@ -626,13 +676,13 @@ describe Chef::Recipe do
     it "should remove a tag from the tag list via untag" do
       recipe.tag "foo"
       recipe.untag "foo"
-      expect(node[:tags]).to eql([])
+      expect(node.tags).to eql([])
     end
 
     it "should remove multiple tags from the tag list via untag" do
       recipe.tag "foo", "bar"
       recipe.untag "bar", "foo"
-      expect(node[:tags]).to eql([])
+      expect(node.tags).to eql([])
     end
   end
 
diff --git a/spec/unit/registry_helper_spec.rb b/spec/unit/registry_helper_spec.rb
deleted file mode 100644
index 036a083..0000000
--- a/spec/unit/registry_helper_spec.rb
+++ /dev/null
@@ -1,376 +0,0 @@
-#
-# Author:: Prajakta Purohit (prajakta at opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-
-describe Chef::Provider::RegistryKey do
-
-  let(:value1) { { :name => "one", :type => :string, :data => "1" } }
-  let(:key_path) { 'HKCU\Software\OpscodeNumbers' }
-  let(:key) { 'Software\OpscodeNumbers' }
-  let(:key_parent) { 'Software' }
-  let(:key_to_delete) { 'OpscodeNumbers' }
-  let(:sub_key) {'OpscodePrimes'}
-  let(:missing_key_path) {'HKCU\Software'}
-
-  before(:each) do
-    allow_any_instance_of(Chef::Win32::Registry).to receive(:machine_architecture).and_return(:x86_64)
-    @registry = Chef::Win32::Registry.new()
-
-    #Making the values for registry constants available on unix
-    Object.send(:remove_const, 'Win32') if defined?(Win32)
-    Win32 = Module.new
-    Win32::Registry = Class.new
-    Win32::Registry::KEY_SET_VALUE = 0x0002
-    Win32::Registry::KEY_QUERY_VALUE = 0x0001
-    Win32::Registry::KEY_WRITE = 0x00020000 | 0x0002 | 0x0004
-    Win32::Registry::KEY_READ = 0x00020000 | 0x0001 | 0x0008 | 0x0010
-
-    Win32::Registry::Error = Class.new(RuntimeError)
-
-    @hive_mock = double("::Win32::Registry::HKEY_CURRENT_USER")
-    @reg_mock = double("reg")
-  end
-
-  describe "get_values" do
-    it "gets all values for a key if the key exists" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:map)
-      @registry.get_values(key_path)
-    end
-
-    it "throws an exception if key does not exist" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      expect{@registry.get_values(key_path)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-  end
-
-  describe "set_value" do
-    it "does nothing if key and hive and value exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:data_exists?).with(key_path, value1).and_return(true)
-      @registry.set_value(key_path, value1)
-    end
-
-    it "updates value if key and hive and value exist, but data is different" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:data_exists?).with(key_path, value1).and_return(false)
-      expect(@hive_mock).to receive(:open).with(key, Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry).to receive(:get_type_from_name).with(:string).and_return(1)
-      expect(@reg_mock).to receive(:write).with("one", 1, "1")
-      @registry.set_value(key_path, value1)
-    end
-
-    it "creates value if the key exists and the value does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry).to receive(:get_type_from_name).with(:string).and_return(1)
-      expect(@reg_mock).to receive(:write).with("one", 1, "1")
-      @registry.set_value(key_path, value1)
-    end
-
-    it "should raise an exception if the key does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      expect {@registry.set_value(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-  end
-
-  describe "delete_value" do
-    it "deletes value if value exists" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:delete_value).with("one").and_return(true)
-      @registry.delete_value(key_path, value1)
-    end
-
-    it "raises an exception if the key does not exist" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      @registry.delete_value(key_path, value1)
-    end
-
-    it "does nothing if the value does not exist" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
-      @registry.delete_value(key_path, value1)
-    end
-  end
-
-  describe "create_key" do
-    it "creates key if intermediate keys are missing and recursive is set to true" do
-      expect(@registry).to receive(:keys_missing?).with(key_path).and_return(true)
-      expect(@registry).to receive(:create_missing).with(key_path)
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(false)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture)
-      @registry.create_key(key_path, true)
-    end
-
-    it "raises an exception if intermediate keys are missing and recursive is set to false" do
-      expect(@registry).to receive(:keys_missing?).with(key_path).and_return(true)
-      expect{@registry.create_key(key_path, false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
-    end
-
-    it "does nothing if the key exists" do
-      expect(@registry).to receive(:keys_missing?).with(key_path).and_return(true)
-      expect(@registry).to receive(:create_missing).with(key_path)
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(true)
-      @registry.create_key(key_path, true)
-    end
-
-    it "create key if intermediate keys not missing and recursive is set to false" do
-      expect(@registry).to receive(:keys_missing?).with(key_path).and_return(false)
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(false)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture)
-      @registry.create_key(key_path, false)
-    end
-
-    it "create key if intermediate keys not missing and recursive is set to true" do
-      expect(@registry).to receive(:keys_missing?).with(key_path).and_return(false)
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(false)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture)
-      @registry.create_key(key_path, true)
-    end
-  end
-
-  describe "delete_key", :windows_only do
-    it "deletes key if it has subkeys and recursive is set to true" do
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:has_subkeys?).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_subkeys).with(key_path).and_return([sub_key])
-      expect(@registry).to receive(:key_exists?).with(key_path+"\\"+sub_key).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path+"\\"+sub_key).and_return([@hive_mock, key+"\\"+sub_key])
-      expect(@registry).to receive(:has_subkeys?).with(key_path+"\\"+sub_key).and_return(false)
-      expect(@registry).to receive(:delete_key_ex).twice
-      @registry.delete_key(key_path, true)
-    end
-
-    it "raises an exception if it has subkeys but recursive is set to false" do
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:has_subkeys?).with(key_path).and_return(true)
-      expect{@registry.delete_key(key_path, false)}.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
-    end
-
-    it "deletes key if the key exists and has no subkeys" do
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:has_subkeys?).with(key_path).and_return(false)
-      expect(@registry).to receive(:delete_key_ex)
-      @registry.delete_key(key_path, true)
-    end
-  end
-
-  describe "key_exists?" do
-    it "returns true if key_exists" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry.key_exists?(key_path)).to eq(true)
-    end
-
-    it "returns false if key does not exist" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_raise(::Win32::Registry::Error)
-      expect(@registry.key_exists?(key_path)).to eq(false)
-    end
-  end
-
-  describe "key_exists!" do
-    it "throws an exception if the key_parent does not exist" do
-      expect(@registry).to receive(:key_exists?).with(key_path).and_return(false)
-      expect{@registry.key_exists!(key_path)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-  end
-
-  describe "hive_exists?" do
-    it "returns true if the hive exists" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      @registry.hive_exists?(key_path) == true
-    end
-
-    it "returns false if the hive does not exist" do
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegHiveMissing)
-      @registry.hive_exists?(key_path) == false
-    end
-  end
-
-  describe "has_subkeys?" do
-    it "returns true if the key has subkeys" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:each_key).and_yield(key)
-      @registry.has_subkeys?(key_path) == true
-    end
-
-    it "returns false if the key does not have subkeys" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:each_key).and_return(no_args())
-      expect(@registry.has_subkeys?(key_path)).to eq(false)
-    end
-
-    it "throws an exception if the key does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      expect {@registry.set_value(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-  end
-
-  describe "get_subkeys" do
-    it "returns the subkeys if they exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:each_key).and_yield(sub_key)
-      @registry.get_subkeys(key_path)
-    end
-  end
-
-  describe "value_exists?" do
-    it "throws an exception if the key does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      expect {@registry.value_exists?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "returns true if the value exists" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:any?).and_yield("one")
-      @registry.value_exists?(key_path, value1) == true
-    end
-
-    it "returns false if the value does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:any?).and_yield(no_args())
-      @registry.value_exists?(key_path, value1) == false
-    end
-  end
-
-  describe "data_exists?" do
-    it "throws an exception if the key does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
-      expect {@registry.data_exists?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
-    end
-
-    it "returns true if the data exists" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@registry).to receive(:get_type_from_name).with(:string).and_return(1)
-      expect(@reg_mock).to receive(:each).with(no_args()).and_yield("one", 1, "1")
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry.data_exists?(key_path, value1)).to eq(true)
-    end
-
-    it "returns false if the data does not exist" do
-      expect(@registry).to receive(:key_exists!).with(key_path).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry).to receive(:get_type_from_name).with(:string).and_return(1)
-      expect(@reg_mock).to receive(:each).with(no_args()).and_yield("one", 1, "2")
-      expect(@registry.data_exists?(key_path, value1)).to eq(false)
-    end
-  end
-
-  describe "value_exists!" do
-    it "does nothing if the value exists" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
-      @registry.value_exists!(key_path, value1)
-    end
-
-    it "throws an exception if the value does not exist" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
-      expect{@registry.value_exists!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
-    end
-  end
-
-  describe "data_exists!" do
-    it "does nothing if the data exists" do
-      expect(@registry).to receive(:data_exists?).with(key_path, value1).and_return(true)
-      @registry.data_exists!(key_path, value1)
-    end
-
-    it "throws an exception if the data does not exist" do
-      expect(@registry).to receive(:data_exists?).with(key_path, value1).and_return(false)
-      expect{@registry.data_exists!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegDataMissing)
-    end
-  end
-
-  describe "type_matches?" do
-    it "returns true if type matches" do
-      expect(@registry).to receive(:value_exists!).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@registry).to receive(:get_type_from_name).with(:string).and_return(1)
-      expect(@reg_mock).to receive(:each).and_yield("one", 1)
-      expect(@registry.type_matches?(key_path, value1)).to eq(true)
-    end
-
-    it "returns false if type does not match" do
-      expect(@registry).to receive(:value_exists!).with(key_path, value1).and_return(true)
-      expect(@registry).to receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key])
-      expect(@hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock)
-      expect(@reg_mock).to receive(:each).and_yield("two", 2)
-      expect(@registry.type_matches?(key_path, value1)).to eq(false)
-    end
-
-    it "throws an exception if value does not exist" do
-      expect(@registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
-      expect{@registry.type_matches?(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegValueMissing)
-    end
-  end
-
-  describe "type_matches!" do
-    it "does nothing if the type_matches" do
-      expect(@registry).to receive(:type_matches?).with(key_path, value1).and_return(true)
-      @registry.type_matches!(key_path, value1)
-    end
-
-    it "throws an exception if the type does not match" do
-      expect(@registry).to receive(:type_matches?).with(key_path, value1).and_return(false)
-      expect{@registry.type_matches!(key_path, value1)}.to raise_error(Chef::Exceptions::Win32RegTypesMismatch)
-    end
-  end
-
-  describe "keys_missing?" do
-    it "returns true if the keys are missing" do
-      expect(@registry).to receive(:key_exists?).with(missing_key_path).and_return(false)
-      expect(@registry.keys_missing?(key_path)).to eq(true)
-    end
-
-    it "returns false if no keys in the path are missing" do
-      expect(@registry).to receive(:key_exists?).with(missing_key_path).and_return(true)
-      expect(@registry.keys_missing?(key_path)).to eq(false)
-    end
-  end
-end
diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb
index 3c31f63..41cdb04 100644
--- a/spec/unit/resource/apt_package_spec.rb
+++ b/spec/unit/resource/apt_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::AptPackage, "initialize" do
 
diff --git a/spec/unit/resource/apt_update_spec.rb b/spec/unit/resource/apt_update_spec.rb
new file mode 100644
index 0000000..8015cb0
--- /dev/null
+++ b/spec/unit/resource/apt_update_spec.rb
@@ -0,0 +1,38 @@
+#
+# Author:: Thom May (<thom at chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::AptUpdate do
+
+  let(:resource) { Chef::Resource::AptUpdate.new("update") }
+
+  it "should create a new Chef::Resource::AptUpdate" do
+    expect(resource).to be_a_kind_of(Chef::Resource)
+    expect(resource).to be_a_kind_of(Chef::Resource::AptUpdate)
+  end
+
+  it "the default frequency should be 1 day" do
+    expect(resource.frequency).to eql(86_400)
+  end
+
+  it "the frequency should accept integers" do
+    resource.frequency(400)
+    expect(resource.frequency).to eql(400)
+  end
+end
diff --git a/spec/unit/resource/bash_spec.rb b/spec/unit/resource/bash_spec.rb
index f313900..56c36df 100644
--- a/spec/unit/resource/bash_spec.rb
+++ b/spec/unit/resource/bash_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Bash do
 
diff --git a/spec/unit/resource/batch_spec.rb b/spec/unit/resource/batch_spec.rb
index 4a056b8..e19ea15 100644
--- a/spec/unit/resource/batch_spec.rb
+++ b/spec/unit/resource/batch_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Batch do
 
@@ -25,6 +25,7 @@ describe Chef::Resource::Batch do
 
     node.default["kernel"] = Hash.new
     node.default["kernel"][:machine] = :x86_64.to_s
+    node.automatic[:os] = "windows"
 
     run_context = Chef::RunContext.new(node, nil, nil)
 
@@ -40,7 +41,7 @@ describe Chef::Resource::Batch do
     let(:resource_instance) { @resource }
     let(:resource_instance_name ) { @resource.command }
     let(:resource_name) { :batch }
-    let(:interpreter_file_name) { 'cmd.exe' }
+    let(:interpreter_file_name) { "cmd.exe" }
 
     it_should_behave_like "a Windows script resource"
   end
diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb
index ed1f3eb..585bcad 100644
--- a/spec/unit/resource/breakpoint_spec.rb
+++ b/spec/unit/resource/breakpoint_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::Breakpoint do
 
@@ -37,7 +37,7 @@ describe Chef::Resource::Breakpoint do
   end
 
   it "defaults to the break action" do
-    expect(@breakpoint.action).to eq("break")
+    expect(@breakpoint.action).to eq([:break])
   end
 
   it "names itself after the line number of the file where it's created" do
diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb
index 7352a8f..1b1439d 100644
--- a/spec/unit/resource/chef_gem_spec.rb
+++ b/spec/unit/resource/chef_gem_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
+# Author:: Adam Jacob (<adam at chef.io>)
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2008, 2012 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::ChefGem, "initialize" do
 
@@ -34,16 +34,12 @@ end
 describe Chef::Resource::ChefGem, "gem_binary" do
   let(:resource) { Chef::Resource::ChefGem.new("foo") }
 
-  before(:each) do
-    expect(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin")
-  end
-
   it "should raise an exception when gem_binary is set" do
     expect { resource.gem_binary("/lol/cats/gem") }.to raise_error(ArgumentError)
   end
 
   it "should set the gem_binary based on computing it from RbConfig" do
-    expect(resource.gem_binary).to eql("/opt/chef/embedded/bin/gem")
+    expect(resource.gem_binary).to eql("#{RbConfig::CONFIG['bindir']}/gem")
   end
 
   it "should set the gem_binary based on computing it from RbConfig" do
@@ -52,7 +48,7 @@ describe Chef::Resource::ChefGem, "gem_binary" do
 
   context "when building the resource" do
     let(:node) do
-      Chef::Node.new.tap {|n| n.normal[:tags] = [] }
+      Chef::Node.new
     end
 
     let(:run_context) do
diff --git a/spec/unit/resource/chocolatey_package_spec.rb b/spec/unit/resource/chocolatey_package_spec.rb
new file mode 100644
index 0000000..dfd6a3e
--- /dev/null
+++ b/spec/unit/resource/chocolatey_package_spec.rb
@@ -0,0 +1,67 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::ChocolateyPackage do
+
+  let(:resource) { Chef::Resource::ChocolateyPackage.new("fakey_fakerton") }
+
+  it "should create a new Chef::Resource::ChocolateyPackage" do
+    expect(resource).to be_a_kind_of(Chef::Resource)
+    expect(resource).to be_a_kind_of(Chef::Resource::Package)
+    expect(resource).to be_a_instance_of(Chef::Resource::ChocolateyPackage)
+  end
+
+  it "should have a resource name of :python" do
+    expect(resource.resource_name).to eql(:chocolatey_package)
+  end
+
+  it "should coerce its name to a package_name array" do
+    expect(resource.package_name).to eql(["fakey_fakerton"])
+  end
+
+  it "the package_name setter should coerce to arrays" do
+    resource.package_name("git")
+    expect(resource.package_name).to eql(["git"])
+  end
+
+  it "the package_name setter should accept arrays" do
+    resource.package_name(["git", "unzip"])
+    expect(resource.package_name).to eql(["git", "unzip"])
+  end
+
+  it "the name should accept arrays" do
+    resource = Chef::Resource::ChocolateyPackage.new(["git", "unzip"])
+    expect(resource.package_name).to eql(["git", "unzip"])
+  end
+
+  it "the default version should be nil" do
+    expect(resource.version).to eql(nil)
+  end
+
+  it "the version setter should coerce to arrays" do
+    resource.version("1.2.3")
+    expect(resource.version).to eql(["1.2.3"])
+  end
+
+  it "the version setter should accept arrays" do
+    resource.version(["1.2.3", "4.5.6"])
+    expect(resource.version).to eql(["1.2.3", "4.5.6"])
+  end
+end
diff --git a/spec/unit/resource/conditional_action_not_nothing_spec.rb b/spec/unit/resource/conditional_action_not_nothing_spec.rb
index d140615..d8a6190 100644
--- a/spec/unit/resource/conditional_action_not_nothing_spec.rb
+++ b/spec/unit/resource/conditional_action_not_nothing_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::ConditionalActionNotNothing do
 
diff --git a/spec/unit/resource/conditional_spec.rb b/spec/unit/resource/conditional_spec.rb
index 489c113..b34b420 100644
--- a/spec/unit/resource/conditional_spec.rb
+++ b/spec/unit/resource/conditional_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2011 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2011-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Resource::Conditional do
   before do
@@ -28,7 +28,7 @@ describe Chef::Resource::Conditional do
   end
 
   it "raises an exception when neither a block or command is given" do
-    expect { Chef::Resource::Conditional.send(:new, :always, @parent_resource, nil, {})}.to raise_error(ArgumentError, /requires either a command or a block/)
+    expect { Chef::Resource::Conditional.send(:new, :always, @parent_resource, nil, {}) }.to raise_error(ArgumentError, /requires either a command or a block/)
   end
 
   it "does not evaluate a guard interpreter on initialization of the conditional" do
@@ -89,17 +89,17 @@ describe Chef::Resource::Conditional do
       end
     end
 
-    describe 'after running a command which timed out' do
+    describe "after running a command which timed out" do
       before do
         @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false")
         allow_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:shell_out).and_raise(Chef::Exceptions::CommandTimeout)
       end
 
-      it 'indicates that resource convergence should not continue' do
+      it "indicates that resource convergence should not continue" do
         expect(@conditional.continue?).to be_falsey
       end
 
-      it 'should log a warning' do
+      it "should log a warning" do
         expect(Chef::Log).to receive(:warn).with("Command 'false' timed out")
         @conditional.continue?
       end
@@ -169,17 +169,17 @@ describe Chef::Resource::Conditional do
       end
     end
 
-    describe 'after running a command which timed out' do
+    describe "after running a command which timed out" do
       before do
-        @conditional = Chef::Resource::Conditional.not_if(@parent_resource,  "false")
+        @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false")
         allow_any_instance_of(Chef::GuardInterpreter::DefaultGuardInterpreter).to receive(:shell_out).and_raise(Chef::Exceptions::CommandTimeout)
       end
 
-      it 'indicates that resource convergence should continue' do
+      it "indicates that resource convergence should continue" do
         expect(@conditional.continue?).to be_truthy
       end
 
-      it 'should log a warning' do
+      it "should log a warning" do
         expect(Chef::Log).to receive(:warn).with("Command 'false' timed out")
         @conditional.continue?
       end
diff --git a/spec/unit/resource/cookbook_file_spec.rb b/spec/unit/resource/cookbook_file_spec.rb
index 834e08b..6886ce1 100644
--- a/spec/unit/resource/cookbook_file_spec.rb
+++ b/spec/unit/resource/cookbook_file_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software, Inc.
 #p License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,20 +17,20 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::CookbookFile do
   before do
-    @cookbook_file = Chef::Resource::CookbookFile.new('sourcecode_tarball.tgz')
+    @cookbook_file = Chef::Resource::CookbookFile.new("sourcecode_tarball.tgz")
   end
 
   it "uses the name parameter for the source parameter" do
-    expect(@cookbook_file.name).to eq('sourcecode_tarball.tgz')
+    expect(@cookbook_file.name).to eq("sourcecode_tarball.tgz")
   end
 
   it "has a source parameter" do
-    @cookbook_file.name('config_file.conf')
-    expect(@cookbook_file.name).to eq('config_file.conf')
+    @cookbook_file.name("config_file.conf")
+    expect(@cookbook_file.name).to eq("config_file.conf")
   end
 
   it "defaults to a nil cookbook parameter (current cookbook will be used)" do
@@ -39,7 +39,7 @@ describe Chef::Resource::CookbookFile do
 
   it "has a cookbook parameter" do
     @cookbook_file.cookbook("munin")
-    expect(@cookbook_file.cookbook).to eq('munin')
+    expect(@cookbook_file.cookbook).to eq("munin")
   end
 
   it "sets the provider to Chef::Provider::CookbookFile" do
@@ -48,28 +48,27 @@ describe Chef::Resource::CookbookFile do
 
   describe "when it has a backup number, group, mode, owner, source, checksum, and cookbook on nix or path, rights, deny_rights, checksum on windows" do
     before do
-       if Chef::Platform.windows?
-         @cookbook_file.path("C:/temp/origin/file.txt")
-         @cookbook_file.rights(:read, "Everyone")
-         @cookbook_file.deny_rights(:full_control, "Clumsy_Sam")
-       else
-         @cookbook_file.path("/tmp/origin/file.txt")
-         @cookbook_file.group("wheel")
-         @cookbook_file.mode("0664")
-         @cookbook_file.owner("root")
-         @cookbook_file.source("/tmp/foo.txt")
-         @cookbook_file.cookbook("/tmp/cookbooks/cooked.rb")
-       end
+      if Chef::Platform.windows?
+        @cookbook_file.path("C:/temp/origin/file.txt")
+        @cookbook_file.rights(:read, "Everyone")
+        @cookbook_file.deny_rights(:full_control, "Clumsy_Sam")
+      else
+        @cookbook_file.path("/tmp/origin/file.txt")
+        @cookbook_file.group("wheel")
+        @cookbook_file.mode("0664")
+        @cookbook_file.owner("root")
+        @cookbook_file.source("/tmp/foo.txt")
+        @cookbook_file.cookbook("/tmp/cookbooks/cooked.rb")
+      end
       @cookbook_file.checksum("1" * 64)
     end
 
-
     it "describes the state" do
       state = @cookbook_file.state
       if Chef::Platform.windows?
         puts state
-        expect(state[:rights]).to eq([{:permissions => :read, :principals => "Everyone"}])
-        expect(state[:deny_rights]).to eq([{:permissions => :full_control, :principals => "Clumsy_Sam"}])
+        expect(state[:rights]).to eq([{ :permissions => :read, :principals => "Everyone" }])
+        expect(state[:deny_rights]).to eq([{ :permissions => :full_control, :principals => "Clumsy_Sam" }])
       else
         expect(state[:group]).to eq("wheel")
         expect(state[:mode]).to eq("0664")
diff --git a/spec/unit/resource/cron_spec.rb b/spec/unit/resource/cron_spec.rb
index 743552c..037bbaf 100644
--- a/spec/unit/resource/cron_spec.rb
+++ b/spec/unit/resource/cron_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Cron do
 
@@ -35,7 +35,7 @@ describe Chef::Resource::Cron do
   end
 
   it "should have a default action of 'create'" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   it "should accept create or delete for action" do
@@ -100,7 +100,7 @@ describe Chef::Resource::Cron do
   end
 
   it "should allow you to specify environment variables hash" do
-    env = {"TEST" => "LOL"}
+    env = { "TEST" => "LOL" }
     @resource.environment env
     expect(@resource.environment).to eql(env)
   end
diff --git a/spec/unit/resource/csh_spec.rb b/spec/unit/resource/csh_spec.rb
index 5fb3b00..864175f 100644
--- a/spec/unit/resource/csh_spec.rb
+++ b/spec/unit/resource/csh_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Csh do
 
diff --git a/spec/unit/resource/deploy_revision_spec.rb b/spec/unit/resource/deploy_revision_spec.rb
index d136aa2..4cbae68 100644
--- a/spec/unit/resource/deploy_revision_spec.rb
+++ b/spec/unit/resource/deploy_revision_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::DeployRevision do
 
diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb
index 0403a7b..0eeb51c 100644
--- a/spec/unit/resource/deploy_spec.rb
+++ b/spec/unit/resource/deploy_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::Deploy do
 
@@ -28,18 +28,17 @@ describe Chef::Resource::Deploy do
     action: :deploy,
   )
 
-
   class << self
     def resource_has_a_string_attribute(attr_name)
-      it "has a String attribute for #{attr_name.to_s}" do
+      it "has a String attribute for #{attr_name}" do
         @resource.send(attr_name, "this is a string")
         expect(@resource.send(attr_name)).to eql("this is a string")
-        expect {@resource.send(attr_name, 8675309)}.to raise_error(ArgumentError)
+        expect { @resource.send(attr_name, 8675309) }.to raise_error(ArgumentError)
       end
     end
 
-    def resource_has_a_boolean_attribute(attr_name, opts={:defaults_to=>false})
-      it "has a Boolean attribute for #{attr_name.to_s}" do
+    def resource_has_a_boolean_attribute(attr_name, opts = { :defaults_to => false })
+      it "has a Boolean attribute for #{attr_name}" do
         expect(@resource.send(attr_name)).to eql(opts[:defaults_to])
         @resource.send(attr_name, !opts[:defaults_to])
         expect(@resource.send(attr_name)).to eql( !opts[:defaults_to] )
@@ -49,12 +48,12 @@ describe Chef::Resource::Deploy do
     def resource_has_a_callback_attribute(attr_name)
       it "has a Callback attribute #{attr_name}" do
         callback_block = lambda { :noop }
-        expect {@resource.send(attr_name, &callback_block)}.not_to raise_error
+        expect { @resource.send(attr_name, &callback_block) }.not_to raise_error
         expect(@resource.send(attr_name)).to eq(callback_block)
         callback_file = "path/to/callback.rb"
-        expect {@resource.send(attr_name, callback_file)}.not_to raise_error
+        expect { @resource.send(attr_name, callback_file) }.not_to raise_error
         expect(@resource.send(attr_name)).to eq(callback_file)
-        expect {@resource.send(attr_name, :this_is_fail)}.to raise_error(ArgumentError)
+        expect { @resource.send(attr_name, :this_is_fail) }.to raise_error(ArgumentError)
       end
     end
   end
@@ -80,9 +79,9 @@ describe Chef::Resource::Deploy do
   resource_has_a_string_attribute(:svn_arguments)
   resource_has_a_string_attribute(:svn_info_args)
 
-  resource_has_a_boolean_attribute(:migrate, :defaults_to=>false)
-  resource_has_a_boolean_attribute(:enable_submodules, :defaults_to=>false)
-  resource_has_a_boolean_attribute(:shallow_clone, :defaults_to=>false)
+  resource_has_a_boolean_attribute(:migrate, :defaults_to => false)
+  resource_has_a_boolean_attribute(:enable_submodules, :defaults_to => false)
+  resource_has_a_boolean_attribute(:shallow_clone, :defaults_to => false)
 
   it "uses the first argument as the deploy directory" do
     expect(@resource.deploy_to).to eql("/my/deploy/dir")
@@ -118,17 +117,17 @@ describe Chef::Resource::Deploy do
     expect(@resource.svn_force_export).to be_falsey
     @resource.svn_force_export true
     expect(@resource.svn_force_export).to be_truthy
-    expect {@resource.svn_force_export(10053)}.to raise_error(ArgumentError)
+    expect { @resource.svn_force_export(10053) }.to raise_error(ArgumentError)
   end
 
   it "takes arbitrary environment variables in a hash" do
     @resource.environment "RAILS_ENV" => "production"
-    expect(@resource.environment).to eq({"RAILS_ENV" => "production"})
+    expect(@resource.environment).to eq({ "RAILS_ENV" => "production" })
   end
 
   it "takes string arguments to environment for backwards compat, setting RAILS_ENV, RACK_ENV, and MERB_ENV" do
     @resource.environment "production"
-    expect(@resource.environment).to eq({"RAILS_ENV"=>"production", "RACK_ENV"=>"production","MERB_ENV"=>"production"})
+    expect(@resource.environment).to eq({ "RAILS_ENV" => "production", "RACK_ENV" => "production", "MERB_ENV" => "production" })
   end
 
   it "sets destination to $deploy_to/shared/$repository_cache" do
@@ -148,10 +147,16 @@ describe Chef::Resource::Deploy do
     expect(@resource.current_path).to eql("/my/deploy/dir/current")
   end
 
+  it "allows depth to be set via integer" do
+    expect(@resource.depth).to be_nil
+    @resource.depth 1
+    expect(@resource.depth).to eql(1)
+  end
+
   it "gives #depth as 5 if shallow clone is true, nil otherwise" do
     expect(@resource.depth).to be_nil
     @resource.shallow_clone true
-    expect(@resource.depth).to eql("5")
+    expect(@resource.depth).to eql(5)
   end
 
   it "aliases repo as repository" do
@@ -177,16 +182,16 @@ describe Chef::Resource::Deploy do
   end
 
   it 'has a Hash attribute symlinks, default: {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}' do
-    default = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log"}
+    default = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log" }
     expect(@resource.symlinks).to eq(default)
     @resource.symlinks "foo" => "bar/baz"
-    expect(@resource.symlinks).to eq({"foo" => "bar/baz"})
+    expect(@resource.symlinks).to eq({ "foo" => "bar/baz" })
   end
 
   it 'has a Hash attribute symlink_before_migrate, default "config/database.yml" => "config/database.yml"' do
-    expect(@resource.symlink_before_migrate).to eq({"config/database.yml" => "config/database.yml"})
+    expect(@resource.symlink_before_migrate).to eq({ "config/database.yml" => "config/database.yml" })
     @resource.symlink_before_migrate "wtf?" => "wtf is going on"
-    expect(@resource.symlink_before_migrate).to eq({"wtf?" => "wtf is going on"})
+    expect(@resource.symlink_before_migrate).to eq({ "wtf?" => "wtf is going on" })
   end
 
   resource_has_a_callback_attribute :before_migrate
@@ -200,7 +205,7 @@ describe Chef::Resource::Deploy do
   end
 
   it "takes a block for the restart parameter" do
-    restart_like_this = lambda {p :noop}
+    restart_like_this = lambda { p :noop }
     @resource.restart(&restart_like_this)
     expect(@resource.restart).to eq(restart_like_this)
   end
@@ -258,8 +263,8 @@ describe Chef::Resource::Deploy do
       @resource.group("pokemon")
       @resource.scm_provider(Chef::Provider::Git)
       @resource.repository_cache("cached-copy")
-      @resource.environment({"SUDO" => "TRUE"})
-      @resource.symlinks({"system" => "public/system"})
+      @resource.environment({ "SUDO" => "TRUE" })
+      @resource.symlinks({ "system" => "public/system" })
       @resource.migrate(false)
 
     end
diff --git a/spec/unit/resource/directory_spec.rb b/spec/unit/resource/directory_spec.rb
index c452b2a..cfb3ade 100644
--- a/spec/unit/resource/directory_spec.rb
+++ b/spec/unit/resource/directory_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Directory do
 
@@ -35,7 +35,7 @@ describe Chef::Resource::Directory do
   end
 
   it "should have a default action of 'create'" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   it "should accept create or delete for action" do
diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb
index 931e676..7bfe268 100644
--- a/spec/unit/resource/dpkg_package_spec.rb
+++ b/spec/unit/resource/dpkg_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::DpkgPackage, "initialize" do
 
@@ -26,7 +26,7 @@ describe Chef::Resource::DpkgPackage, "initialize" do
     provider: Chef::Provider::Package::Dpkg,
     name: :dpkg_package,
     action: :install,
-    os: 'linux',
+    os: "linux",
   )
 
 end
diff --git a/spec/unit/resource/dsc_resource_spec.rb b/spec/unit/resource/dsc_resource_spec.rb
index ae15f56..00e667c 100644
--- a/spec/unit/resource/dsc_resource_spec.rb
+++ b/spec/unit/resource/dsc_resource_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,31 +15,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-require 'spec_helper'
-
+require "spec_helper"
 describe Chef::Resource::DscResource do
-  let(:dsc_test_resource_name) { 'DSCTest' }
+  let(:dsc_test_resource_name) { "DSCTest" }
   let(:dsc_test_property_name) { :DSCTestProperty }
-  let(:dsc_test_property_value) { 'DSCTestValue' }
+  let(:dsc_test_property_value) { "DSCTestValue" }
+  let(:dsc_test_reboot_action) { :reboot_now }
+  let(:dsc_test_timeout) { 101 }
 
-  context 'when Powershell supports Dsc' do
+  context "when Powershell supports Dsc" do
     let(:dsc_test_run_context) {
       node = Chef::Node.new
-      node.automatic[:languages][:powershell][:version] = '5.0.10018.0'
+      node.automatic[:languages][:powershell][:version] = "5.0.10018.0"
       empty_events = Chef::EventDispatch::Dispatcher.new
       Chef::RunContext.new(node, {}, empty_events)
     }
+
     let(:dsc_test_resource) {
       Chef::Resource::DscResource.new(dsc_test_resource_name, dsc_test_run_context)
     }
 
     it "has a default action of `:run`" do
-      expect(dsc_test_resource.action).to eq(:run)
+      expect(dsc_test_resource.action).to eq([:run])
     end
 
-    it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
-      expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+    it "has an ed_actions attribute with only the `:run` and `:nothing` attributes" do
+      expect(dsc_test_resource.allowed_actions.to_set).to eq([:run, :nothing].to_set)
     end
 
     it "allows the resource attribute to be set" do
@@ -52,6 +53,16 @@ describe Chef::Resource::DscResource do
       expect(dsc_test_resource.module_name).to eq(dsc_test_resource_name)
     end
 
+    it "allows the reboot_action attribute to be set" do
+      dsc_test_resource.reboot_action(dsc_test_reboot_action)
+      expect(dsc_test_resource.reboot_action).to eq(dsc_test_reboot_action)
+    end
+
+    it "allows the timeout attribute to be set" do
+      dsc_test_resource.timeout(dsc_test_timeout)
+      expect(dsc_test_resource.timeout).to eq(dsc_test_timeout)
+    end
+
     context "when setting a dsc property" do
       it "allows setting a dsc property with a property name of type Symbol" do
         dsc_test_resource.property(dsc_test_property_name, dsc_test_property_value)
@@ -60,8 +71,8 @@ describe Chef::Resource::DscResource do
       end
 
       it "raises a TypeError if property_name is not a symbol" do
-        expect{
-          dsc_test_resource.property('Foo', dsc_test_property_value)
+        expect {
+          dsc_test_resource.property("Foo", dsc_test_property_value)
         }.to raise_error(TypeError)
       end
 
@@ -76,7 +87,7 @@ describe Chef::Resource::DscResource do
       end
     end
 
-    context 'Powershell DSL methods' do
+    context "Powershell DSL methods" do
       it "responds to :ps_credential" do
         expect(dsc_test_resource.respond_to?(:ps_credential)).to be true
       end
diff --git a/spec/unit/resource/dsc_script_spec.rb b/spec/unit/resource/dsc_script_spec.rb
index 71103ea..55473e3 100644
--- a/spec/unit/resource/dsc_script_spec.rb
+++ b/spec/unit/resource/dsc_script_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards (<adamed at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,33 +16,33 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::DscScript do
-  let(:dsc_test_resource_name) { 'DSCTest' }
+  let(:dsc_test_resource_name) { "DSCTest" }
 
-  context 'when Powershell supports Dsc' do
+  context "when Powershell supports Dsc" do
     let(:dsc_test_run_context) {
       node = Chef::Node.new
-      node.automatic[:languages][:powershell][:version] = '4.0'
+      node.automatic[:languages][:powershell][:version] = "4.0"
       empty_events = Chef::EventDispatch::Dispatcher.new
       Chef::RunContext.new(node, {}, empty_events)
     }
     let(:dsc_test_resource) {
-      Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context) 
+      Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context)
     }
-    let(:configuration_code) {'echo "This is supposed to create a configuration document."'}
-    let(:configuration_path) {'c:/myconfigs/formatc.ps1'}
-    let(:configuration_name) { 'formatme' }
+    let(:configuration_code) { 'echo "This is supposed to create a configuration document."' }
+    let(:configuration_path) { "c:/myconfigs/formatc.ps1" }
+    let(:configuration_name) { "formatme" }
     let(:configuration_data) { '@{AllNodes = @( @{ NodeName = "localhost"; PSDscAllowPlainTextPassword = $true })}' }
-    let(:configuration_data_script) { 'c:/myconfigs/data/safedata.psd1' }
+    let(:configuration_data_script) { "c:/myconfigs/data/safedata.psd1" }
 
     it "has a default action of `:run`" do
-      expect(dsc_test_resource.action).to eq(:run)
+      expect(dsc_test_resource.action).to eq([:run])
     end
 
     it "has an allowed_actions attribute with only the `:run` and `:nothing` attributes" do
-      expect(dsc_test_resource.allowed_actions.to_set).to eq([:run,:nothing].to_set)
+      expect(dsc_test_resource.allowed_actions.to_set).to eq([:run, :nothing].to_set)
     end
 
     it "allows the code attribute to be set" do
@@ -70,10 +70,14 @@ describe Chef::Resource::DscScript do
       expect(dsc_test_resource.configuration_data_script).to eq(configuration_data_script)
     end
 
+    it "has the ps_credential helper method" do
+      expect(dsc_test_resource).to respond_to(:ps_credential)
+    end
+
     context "when calling imports" do
-      let(:module_name)   { 'FooModule' }
-      let(:module_name_b)   { 'BarModule' }
-      let(:dsc_resources) { ['ResourceA', 'ResourceB'] }
+      let(:module_name)   { "FooModule" }
+      let(:module_name_b)   { "BarModule" }
+      let(:dsc_resources) { ["ResourceA", "ResourceB"] }
 
       it "allows an arbitrary number of resources to be set for a module to be set" do
         dsc_test_resource.imports module_name, *dsc_resources
@@ -84,7 +88,7 @@ describe Chef::Resource::DscScript do
       it "adds * to the imports when no resources are set for a moudle" do
         dsc_test_resource.imports module_name
         module_imports = dsc_test_resource.imports[module_name]
-        expect(module_imports).to eq(['*'])
+        expect(module_imports).to eq(["*"])
       end
 
       it "allows an arbitrary number of modules" do
diff --git a/spec/unit/resource/easy_install_package_spec.rb b/spec/unit/resource/easy_install_package_spec.rb
index c68b026..9747e57 100644
--- a/spec/unit/resource/easy_install_package_spec.rb
+++ b/spec/unit/resource/easy_install_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::EasyInstallPackage, "initialize" do
 
diff --git a/spec/unit/resource/env_spec.rb b/spec/unit/resource/env_spec.rb
index 566827a..cff862b 100644
--- a/spec/unit/resource/env_spec.rb
+++ b/spec/unit/resource/env_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Doug MacEachern (<dougm at vmware.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2010 VMware, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2010-2016, VMware, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Env do
 
@@ -35,11 +35,11 @@ describe Chef::Resource::Env do
   end
 
   it "should have a default action of 'create'" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
-  { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action,bad_value|
-    it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do
+  { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action, bad_value|
+    it "should #{bad_value ? 'not' : ''} accept #{action}" do
       if bad_value
         expect { @resource.action action }.to raise_error(ArgumentError)
       else
diff --git a/spec/unit/resource/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb
index 8ec1826..6d1f45e 100644
--- a/spec/unit/resource/erl_call_spec.rb
+++ b/spec/unit/resource/erl_call_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::ErlCall do
 
@@ -35,7 +35,7 @@ describe Chef::Resource::ErlCall do
   end
 
   it "should have a default action of run" do
-    expect(@resource.action).to eql("run")
+    expect(@resource.action).to eql([:run])
   end
 
   it "should accept run as an action" do
diff --git a/spec/unit/resource/execute_spec.rb b/spec/unit/resource/execute_spec.rb
index 09160dd..70824e9 100644
--- a/spec/unit/resource/execute_spec.rb
+++ b/spec/unit/resource/execute_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Execute do
   let(:resource_instance_name) { "some command" }
diff --git a/spec/unit/resource/file/verification_spec.rb b/spec/unit/resource/file/verification_spec.rb
index 3609d9d..f55f641 100644
--- a/spec/unit/resource/file/verification_spec.rb
+++ b/spec/unit/resource/file/verification_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Steven Danna (<steve at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc
+# Copyright:: Copyright 2014-2016, Chef Software, Inc
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::File::Verification do
   let(:t_block) { Proc.new { true } }
   let(:f_block) { Proc.new { false } }
-  let(:path_block) { Proc.new { |path| path }}
+  let(:path_block) { Proc.new { |path| path } }
   let(:temp_path) { "/tmp/foobar" }
 
   describe "verification registration" do
@@ -33,7 +33,7 @@ describe Chef::Resource::File::Verification do
     end
 
     it "raises an error if a verification can't be found" do
-      expect{Chef::Resource::File::Verification.lookup(:dne)}.to raise_error(Chef::Exceptions::VerificationNotFound)
+      expect { Chef::Resource::File::Verification.lookup(:dne) }.to raise_error(Chef::Exceptions::VerificationNotFound)
     end
   end
 
@@ -42,13 +42,13 @@ describe Chef::Resource::File::Verification do
 
     it "expects a string argument" do
       v = Chef::Resource::File::Verification.new(parent_resource, nil, {}) {}
-      expect{ v.verify("/foo/bar") }.to_not raise_error
-      expect{ v.verify }.to raise_error
+      expect { v.verify("/foo/bar") }.to_not raise_error
+      expect { v.verify }.to raise_error
     end
 
     it "accepts an options hash" do
       v = Chef::Resource::File::Verification.new(parent_resource, nil, {}) {}
-      expect{ v.verify("/foo/bar", {:future => true}) }.to_not raise_error
+      expect { v.verify("/foo/bar", { :future => true }) }.to_not raise_error
     end
 
     context "with a verification block" do
@@ -69,12 +69,40 @@ describe Chef::Resource::File::Verification do
     end
 
     context "with a verification command(String)" do
+      before(:each) do
+        allow(Chef::Log).to receive(:deprecation).and_return(nil)
+      end
+
+      def platform_specific_verify_command(variable_name)
+        if windows?
+          "if \"#{temp_path}\" == \"%{#{variable_name}}\" (exit 0) else (exit 1)"
+        else
+          "test #{temp_path} = %{#{variable_name}}"
+        end
+      end
+
       it "substitutes \%{file} with the path" do
-        test_command = if windows?
-                         "if \"#{temp_path}\" == \"%{file}\" (exit 0) else (exit 1)"
-                       else
-                         "test #{temp_path} = %{file}"
-                       end
+        test_command = platform_specific_verify_command("file")
+        v = Chef::Resource::File::Verification.new(parent_resource, test_command, {})
+        expect(v.verify(temp_path)).to eq(true)
+      end
+
+      it "warns about deprecation when \%{file} is used" do
+        expect(Chef::Log).to receive(:deprecation).with(/%{file} is deprecated/, /verification_spec\.rb/)
+        test_command = platform_specific_verify_command("file")
+        Chef::Resource::File::Verification.new(parent_resource, test_command, {})
+          .verify(temp_path)
+      end
+
+      it "does not warn about deprecation when \%{file} is not used" do
+        expect(Chef::Log).to_not receive(:deprecation)
+        test_command = platform_specific_verify_command("path")
+        Chef::Resource::File::Verification.new(parent_resource, test_command, {})
+          .verify(temp_path)
+      end
+
+      it "substitutes \%{path} with the path" do
+        test_command = platform_specific_verify_command("path")
         v = Chef::Resource::File::Verification.new(parent_resource, test_command, {})
         expect(v.verify(temp_path)).to eq(true)
       end
diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb
index db52e35..c93a213 100644
--- a/spec/unit/resource/file_spec.rb
+++ b/spec/unit/resource/file_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::File do
 
@@ -29,7 +29,7 @@ describe Chef::Resource::File do
   end
 
   it "should have a default action of 'create'" do
-    expect(@resource.action).to eql("create")
+    expect(@resource.action).to eql([:create])
   end
 
   it "should have a default content of nil" do
@@ -67,11 +67,11 @@ describe Chef::Resource::File do
   end
 
   it "should accept a block, symbol, or string for verify" do
-    expect {@resource.verify {}}.not_to raise_error
-    expect {@resource.verify ""}.not_to raise_error
-    expect {@resource.verify :json}.not_to raise_error
-    expect {@resource.verify true}.to raise_error
-    expect {@resource.verify false}.to raise_error
+    expect { @resource.verify {} }.not_to raise_error
+    expect { @resource.verify "" }.not_to raise_error
+    expect { @resource.verify :json }.not_to raise_error
+    expect { @resource.verify true }.to raise_error
+    expect { @resource.verify false }.to raise_error
   end
 
   it "should accept multiple verify statements" do
@@ -122,8 +122,8 @@ describe Chef::Resource::File do
     end
     it "describes its state including windows ACL attributes" do
       state = @resource.state
-      expect(state[:rights]).to eq([ {:permissions => :read, :principals => "Everyone"},
-                               {:permissions => :full_control, :principals => "DOMAIN\User"} ])
+      expect(state[:rights]).to eq([ { :permissions => :read, :principals => "Everyone" },
+                               { :permissions => :full_control, :principals => "DOMAIN\User" } ])
     end
   end
 
diff --git a/spec/unit/resource/freebsd_package_spec.rb b/spec/unit/resource/freebsd_package_spec.rb
index 7263d3a..0842114 100644
--- a/spec/unit/resource/freebsd_package_spec.rb
+++ b/spec/unit/resource/freebsd_package_spec.rb
@@ -1,8 +1,8 @@
 #
-# Authors:: AJ Christensen (<aj at opscode.com>)
+# Authors:: AJ Christensen (<aj at chef.io>)
 #           Richard Manyanza (<liseki at nyikacraftsmen.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Resource::FreebsdPackage do
   before(:each) do
@@ -29,7 +29,6 @@ describe Chef::Resource::FreebsdPackage do
     @resource = Chef::Resource::FreebsdPackage.new("foo", @run_context)
   end
 
-
   describe "Initialization" do
     it "should return a Chef::Resource::FreebsdPackage" do
       expect(@resource).to be_a_kind_of(Chef::Resource::FreebsdPackage)
@@ -44,11 +43,10 @@ describe Chef::Resource::FreebsdPackage do
     end
   end
 
-
   describe "Assigning provider after creation" do
     describe "if ports specified as source" do
       it "should be Freebsd::Port" do
-        @resource.source('ports')
+        @resource.source("ports")
         @resource.after_created
         expect(@resource.provider).to eq(Chef::Provider::Package::Freebsd::Port)
       end
@@ -87,4 +85,3 @@ describe Chef::Resource::FreebsdPackage do
     end
   end
 end
-
diff --git a/spec/unit/resource/gem_package_spec.rb b/spec/unit/resource/gem_package_spec.rb
index 0f3eae7..de6341d 100644
--- a/spec/unit/resource/gem_package_spec.rb
+++ b/spec/unit/resource/gem_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::GemPackage, "initialize" do
 
diff --git a/spec/unit/resource/git_spec.rb b/spec/unit/resource/git_spec.rb
index 6a39b3d..18d6216 100644
--- a/spec/unit/resource/git_spec.rb
+++ b/spec/unit/resource/git_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::Git do
 
diff --git a/spec/unit/resource/group_spec.rb b/spec/unit/resource/group_spec.rb
index bcf9205..7cfec23 100644
--- a/spec/unit/resource/group_spec.rb
+++ b/spec/unit/resource/group_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>);
-# Copyright:: Copyright (c) 2008 OpsCode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>);
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Group, "initialize" do
   before(:each) do
@@ -50,7 +50,7 @@ describe Chef::Resource::Group, "initialize" do
   end
 
   it "should set action to :create" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   %w{create remove modify manage}.each do |action|
diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb
index bb248d1..dad9573 100644
--- a/spec/unit/resource/homebrew_package_spec.rb
+++ b/spec/unit/resource/homebrew_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Joshua Timberman (<joshua at getchef.com>)
-# Copyright (c) 2014, Chef Software, Inc. <legal at getchef.com>
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Copyright 2014-2016, Chef Software, Inc. <legal at chef.io>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,10 +15,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
-describe Chef::Resource::HomebrewPackage, 'initialize' do
+describe Chef::Resource::HomebrewPackage, "initialize" do
 
   static_provider_resolution(
     resource: Chef::Resource::HomebrewPackage,
@@ -28,22 +28,22 @@ describe Chef::Resource::HomebrewPackage, 'initialize' do
     os: "mac_os_x",
   )
 
-  let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') }
+  let(:resource) { Chef::Resource::HomebrewPackage.new("emacs") }
 
-  shared_examples 'home_brew user set and returned' do
-    it 'returns the configured homebrew_user' do
+  shared_examples "home_brew user set and returned" do
+    it "returns the configured homebrew_user" do
       resource.homebrew_user user
       expect(resource.homebrew_user).to eql(user)
     end
   end
 
-  context 'homebrew_user is set' do
-    let(:user) { 'Captain Picard' }
-    include_examples 'home_brew user set and returned'
+  context "homebrew_user is set" do
+    let(:user) { "Captain Picard" }
+    include_examples "home_brew user set and returned"
 
-    context 'as an integer' do
+    context "as an integer" do
       let(:user) { 1001 }
-      include_examples 'home_brew user set and returned'
+      include_examples "home_brew user set and returned"
     end
   end
 
diff --git a/spec/unit/resource/http_request_spec.rb b/spec/unit/resource/http_request_spec.rb
index aa4ce4d..318a154 100644
--- a/spec/unit/resource/http_request_spec.rb
+++ b/spec/unit/resource/http_request_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::HttpRequest do
 
@@ -48,7 +48,7 @@ describe Chef::Resource::HttpRequest do
     before do
       @resource.url("http://www.trololol.net")
       @resource.message("Get sum post brah.")
-      @resource.headers({"head" => "tail"})
+      @resource.headers({ "head" => "tail" })
     end
 
     it "returns the url as its identity" do
diff --git a/spec/unit/resource/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb
index ea5282a..eceba0c 100644
--- a/spec/unit/resource/ifconfig_spec.rb
+++ b/spec/unit/resource/ifconfig_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Ifconfig do
 
@@ -47,21 +47,23 @@ describe Chef::Resource::Ifconfig do
     end
   end
 
-  shared_examples "being a platform using the default ifconfig provider" do |platform, version|
+  shared_examples "being a platform based on an old Debian" do |platform, version|
     before do
+      @node.automatic_attrs[:os] = "linux"
+      @node.automatic_attrs[:platform_family] = "debian"
       @node.automatic_attrs[:platform] = platform
       @node.automatic_attrs[:platform_version] = version
     end
 
     it "should use an ordinary Provider::Ifconfig as a provider for #{platform} #{version}" do
-      expect(@resource.provider_for_action(:add)).to be_a_kind_of(Chef::Provider::Ifconfig)
-      expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Debian)
-      expect(@resource.provider_for_action(:add)).not_to be_a_kind_of(Chef::Provider::Ifconfig::Redhat)
+      expect(@resource.provider_for_action(:add).class).to eq(Chef::Provider::Ifconfig)
     end
   end
 
   shared_examples "being a platform based on RedHat" do |platform, version|
     before do
+      @node.automatic_attrs[:os] = "linux"
+      @node.automatic_attrs[:platform_family] = "rhel"
       @node.automatic_attrs[:platform] = platform
       @node.automatic_attrs[:platform_version] = version
     end
@@ -73,6 +75,8 @@ describe Chef::Resource::Ifconfig do
 
   shared_examples "being a platform based on a recent Debian" do |platform, version|
     before do
+      @node.automatic_attrs[:os] = "linux"
+      @node.automatic_attrs[:platform_family] = "debian"
       @node.automatic_attrs[:platform] = platform
       @node.automatic_attrs[:platform_version] = version
     end
@@ -87,7 +91,7 @@ describe Chef::Resource::Ifconfig do
   end
 
   describe "when it is an old Debian platform" do
-    it_should_behave_like "being a platform using the default ifconfig provider", "debian", "6.0"
+    it_should_behave_like "being a platform based on an old Debian", "debian", "6.0"
   end
 
   describe "when it is a new Debian platform" do
@@ -95,7 +99,7 @@ describe Chef::Resource::Ifconfig do
   end
 
   describe "when it is an old Ubuntu platform" do
-    it_should_behave_like "being a platform using the default ifconfig provider", "ubuntu", "11.04"
+    it_should_behave_like "being a platform based on an old Debian", "ubuntu", "11.04"
   end
 
   describe "when it is a new Ubuntu platform" do
diff --git a/spec/unit/resource/ips_package_spec.rb b/spec/unit/resource/ips_package_spec.rb
index 126ae00..62656bc 100644
--- a/spec/unit/resource/ips_package_spec.rb
+++ b/spec/unit/resource/ips_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Bryan McLellan <btm at opscode.com>
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Bryan McLellan <btm at chef.io>
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::IpsPackage, "initialize" do
 
diff --git a/spec/unit/resource/ksh_spec.rb b/spec/unit/resource/ksh_spec.rb
new file mode 100644
index 0000000..6c3ba29
--- /dev/null
+++ b/spec/unit/resource/ksh_spec.rb
@@ -0,0 +1,40 @@
+#
+# Author:: Nolan Davidson (<nolan.davidson at gmail.com>)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::Ksh do
+
+  before(:each) do
+    @resource = Chef::Resource::Ksh.new("fakey_fakerton")
+  end
+
+  it "should create a new Chef::Resource::Ksh" do
+    expect(@resource).to be_a_kind_of(Chef::Resource)
+    expect(@resource).to be_a_kind_of(Chef::Resource::Ksh)
+  end
+
+  it "should have a resource name of :ksh" do
+    expect(@resource.resource_name).to eql(:ksh)
+  end
+
+  it "should have an interpreter of ksh" do
+    expect(@resource.interpreter).to eql("ksh")
+  end
+
+end
diff --git a/spec/unit/resource/link_spec.rb b/spec/unit/resource/link_spec.rb
index 51221e0..bd0976d 100644
--- a/spec/unit/resource/link_spec.rb
+++ b/spec/unit/resource/link_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Link do
 
@@ -36,11 +36,11 @@ describe Chef::Resource::Link do
   end
 
   it "should have a default action of 'create'" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
-  { :create => false, :delete => false, :blues => true }.each do |action,bad_value|
-    it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do
+  { :create => false, :delete => false, :blues => true }.each do |action, bad_value|
+    it "should #{bad_value ? 'not' : ''} accept #{action}" do
       if bad_value
         expect { @resource.action action }.to raise_error(ArgumentError)
       else
diff --git a/spec/unit/resource/log_spec.rb b/spec/unit/resource/log_spec.rb
index b2af194..18a1eb6 100644
--- a/spec/unit/resource/log_spec.rb
+++ b/spec/unit/resource/log_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Cary Penniman (<cary at rightscale.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Log do
 
diff --git a/spec/unit/resource/macports_package_spec.rb b/spec/unit/resource/macports_package_spec.rb
index 0a203b2..1aee070 100644
--- a/spec/unit/resource/macports_package_spec.rb
+++ b/spec/unit/resource/macports_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: David Balatero (<dbalatero at gmail.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::MacportsPackage, "initialize" do
 
diff --git a/spec/unit/resource/mdadm_spec.rb b/spec/unit/resource/mdadm_spec.rb
index 866309e..6a446a2 100644
--- a/spec/unit/resource/mdadm_spec.rb
+++ b/spec/unit/resource/mdadm_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Joe Williams (<joe at joetify.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Joe Williams
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Joe Williams
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Mdadm do
 
@@ -35,7 +35,7 @@ describe Chef::Resource::Mdadm do
   end
 
   it "should have a default action of create" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   it "should accept create, assemble, stop as actions" do
diff --git a/spec/unit/resource/mount_spec.rb b/spec/unit/resource/mount_spec.rb
index ad95c06..ea20511 100644
--- a/spec/unit/resource/mount_spec.rb
+++ b/spec/unit/resource/mount_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Joshua Timberman (<joshua at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2009 Opscode, Inc
+# Author:: Joshua Timberman (<joshua at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Mount do
   before(:each) do
@@ -38,7 +38,7 @@ describe Chef::Resource::Mount do
   end
 
   it "should have a default action of mount" do
-    expect(@resource.action).to eql(:mount)
+    expect(@resource.action).to eql([:mount])
   end
 
   it "should accept mount, umount and remount as actions" do
@@ -54,7 +54,7 @@ describe Chef::Resource::Mount do
   end
 
   it "should set fsck_device to '-' by default" do
-    expect(@resource.fsck_device).to eql('-')
+    expect(@resource.fsck_device).to eql("-")
   end
 
   it "should allow you to set the fsck_device attribute" do
@@ -92,12 +92,12 @@ describe Chef::Resource::Mount do
   end
 
   it "should allow options to be sent as a delayed evaluator" do
-    @resource.options Chef::DelayedEvaluator.new {["rw", "noexec"]}
+    @resource.options Chef::DelayedEvaluator.new { ["rw", "noexec"] }
     expect(@resource.options).to eql(["rw", "noexec"])
   end
 
   it "should allow options to be sent as a delayed evaluator, and convert to array" do
-    @resource.options Chef::DelayedEvaluator.new {"rw,noexec"}
+    @resource.options Chef::DelayedEvaluator.new { "rw,noexec" }
     expect(@resource.options).to be_a_kind_of(Array)
     expect(@resource.options).to eql(["rw", "noexec"])
   end
diff --git a/spec/unit/resource/ohai_spec.rb b/spec/unit/resource/ohai_spec.rb
index fe29755..9669ef1 100644
--- a/spec/unit/resource/ohai_spec.rb
+++ b/spec/unit/resource/ohai_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Michael Leinartas (<mleinartas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Michael Leinartas
+# Copyright:: Copyright 2010-2016, Michael Leinartas
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Ohai do
 
@@ -34,7 +34,7 @@ describe Chef::Resource::Ohai do
   end
 
   it "should have a default action of create" do
-    expect(@resource.action).to eql(:reload)
+    expect(@resource.action).to eql([:reload])
   end
 
   it "should allow you to set the plugin attribute" do
@@ -58,5 +58,4 @@ describe Chef::Resource::Ohai do
     end
   end
 
-
 end
diff --git a/spec/unit/resource/openbsd_package_spec.rb b/spec/unit/resource/openbsd_package_spec.rb
index 95921c2..9bdc823 100644
--- a/spec/unit/resource/openbsd_package_spec.rb
+++ b/spec/unit/resource/openbsd_package_spec.rb
@@ -1,9 +1,9 @@
 #
-# Authors:: AJ Christensen (<aj at opscode.com>)
+# Authors:: AJ Christensen (<aj at chef.io>)
 #           Richard Manyanza (<liseki at nyikacraftsmen.com>)
 #           Scott Bonds (<scott at ggr.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2014 Richard Manyanza, Scott Bonds
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2014-2016, Richard Manyanza, Scott Bonds
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Chef::Resource::OpenbsdPackage do
 
@@ -46,4 +46,3 @@ describe Chef::Resource::OpenbsdPackage do
   end
 
 end
-
diff --git a/spec/unit/resource/osx_profile_spec.rb b/spec/unit/resource/osx_profile_spec.rb
new file mode 100644
index 0000000..7bd504d
--- /dev/null
+++ b/spec/unit/resource/osx_profile_spec.rb
@@ -0,0 +1,61 @@
+#
+# Author:: Nate Walck (<nate.walck at gmail.com>)
+# Copyright:: Copyright 2015-2016, Facebook, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::OsxProfile do
+  let(:resource) { Chef::Resource::OsxProfile.new(
+    "Test Profile Resource",
+    run_context)
+  }
+
+  it "should create a new Chef::Resource::OsxProfile" do
+    expect(resource).to be_a_kind_of(Chef::Resource)
+    expect(resource).to be_a_kind_of(Chef::Resource::OsxProfile)
+  end
+
+  it "should have a resource name of profile" do
+    expect(resource.resource_name).to eql(:osx_profile)
+  end
+
+  it "should have a default action of install" do
+    expect(resource.action).to eql([:install])
+  end
+
+  it "should accept install and remove as actions" do
+    expect { resource.action :install }.not_to raise_error
+    expect { resource.action :remove }.not_to raise_error
+  end
+
+  it "should allow you to set the profile attribute" do
+    resource.profile "com.testprofile.screensaver"
+    expect(resource.profile).to eql("com.testprofile.screensaver")
+  end
+
+  it "should allow you to set the profile attribute to a string" do
+    resource.profile "com.testprofile.screensaver"
+    expect(resource.profile).to be_a(String)
+    expect(resource.profile).to eql("com.testprofile.screensaver")
+  end
+
+  it "should allow you to set the profile attribute to a hash" do
+    test_profile = { "profile" => false }
+    resource.profile test_profile
+    expect(resource.profile).to be_a(Hash)
+  end
+end
diff --git a/spec/unit/resource/package_spec.rb b/spec/unit/resource/package_spec.rb
index 449732a..dbd76d2 100644
--- a/spec/unit/resource/package_spec.rb
+++ b/spec/unit/resource/package_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Package do
 
@@ -50,8 +50,8 @@ describe Chef::Resource::Package do
   end
 
   it "should accept a hash for response file template variables" do
-    @resource.response_file_variables({:variables => true})
-    expect(@resource.response_file_variables).to eql({:variables => true})
+    @resource.response_file_variables({ :variables => true })
+    expect(@resource.response_file_variables).to eql({ :variables => true })
   end
 
   it "should accept a string for the source" do
diff --git a/spec/unit/resource/pacman_package_spec.rb b/spec/unit/resource/pacman_package_spec.rb
index 975863d..000470b 100644
--- a/spec/unit/resource/pacman_package_spec.rb
+++ b/spec/unit/resource/pacman_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jan Zimmek (<jan.zimmek at web.de>)
-# Copyright:: Copyright (c) 2010 Jan Zimmek
+# Copyright:: Copyright 2010-2016, Jan Zimmek
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::PacmanPackage, "initialize" do
 
diff --git a/spec/unit/resource/perl_spec.rb b/spec/unit/resource/perl_spec.rb
index 7247cce..417d74a 100644
--- a/spec/unit/resource/perl_spec.rb
+++ b/spec/unit/resource/perl_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Perl do
 
diff --git a/spec/unit/resource/portage_package_spec.rb b/spec/unit/resource/portage_package_spec.rb
index d2ac7ac..d233674 100644
--- a/spec/unit/resource/portage_package_spec.rb
+++ b/spec/unit/resource/portage_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/unit/resource/powershell_script_spec.rb b/spec/unit/resource/powershell_script_spec.rb
new file mode 100644
index 0000000..f1a9215
--- /dev/null
+++ b/spec/unit/resource/powershell_script_spec.rb
@@ -0,0 +1,136 @@
+#
+# Author:: Adam Edwards (<adamed at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::PowershellScript do
+
+  before(:each) do
+    node = Chef::Node.new
+
+    node.default["kernel"] = Hash.new
+    node.default["kernel"][:machine] = :x86_64.to_s
+    node.automatic[:os] = "windows"
+
+    run_context = Chef::RunContext.new(node, nil, nil)
+
+    @resource = Chef::Resource::PowershellScript.new("powershell_unit_test", run_context)
+  end
+
+  it "creates a new Chef::Resource::PowershellScript" do
+    expect(@resource).to be_a_kind_of(Chef::Resource::PowershellScript)
+  end
+
+  it "sets convert_boolean_return to false by default" do
+    expect(@resource.convert_boolean_return).to eq(false)
+  end
+
+  it "returns the value for convert_boolean_return that was set" do
+    @resource.convert_boolean_return true
+    expect(@resource.convert_boolean_return).to eq(true)
+    @resource.convert_boolean_return false
+    expect(@resource.convert_boolean_return).to eq(false)
+  end
+
+  it "raises an error when architecture is i386 on Windows Nano Server" do
+    allow(Chef::Platform).to receive(:windows_nano_server?).and_return(true)
+    expect { @resource.architecture(:i386) }.to raise_error(Chef::Exceptions::Win32ArchitectureIncorrect, "cannot execute script with requested architecture 'i386' on Windows Nano Server")
+  end
+
+  context "when using guards" do
+    let(:resource) { @resource }
+    before(:each) do
+      allow(resource).to receive(:run_action)
+      allow(resource).to receive(:updated).and_return(true)
+    end
+
+    it "inherits exactly the :cwd, :environment, :group, :path, :user, :umask, and :architecture attributes from a parent resource class" do
+      inherited_difference = Chef::Resource::PowershellScript.guard_inherited_attributes -
+                             [:cwd, :environment, :group, :path, :user, :umask, :architecture ]
+
+      expect(inherited_difference).to eq([])
+    end
+
+    it "allows guard interpreter to be set to Chef::Resource::Script" do
+      resource.guard_interpreter(:script)
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
+      resource.only_if("echo hi")
+    end
+
+    it "allows guard interpreter to be set to Chef::Resource::Bash derived from Chef::Resource::Script" do
+      resource.guard_interpreter(:bash)
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
+      resource.only_if("echo hi")
+    end
+
+    it "allows guard interpreter to be set to Chef::Resource::PowershellScript derived indirectly from Chef::Resource::Script" do
+      resource.guard_interpreter(:powershell_script)
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
+      resource.only_if("echo hi")
+    end
+
+    it "enables convert_boolean_return by default for guards in the context of powershell_script when no guard params are specified" do
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
+        { :convert_boolean_return => true, :code => "$true" }).and_return(Proc.new {})
+      resource.only_if("$true")
+    end
+
+    it "enables convert_boolean_return by default for guards in non-Chef::Resource::Script derived resources when no guard params are specified" do
+      node = Chef::Node.new
+      run_context = Chef::RunContext.new(node, nil, nil)
+      file_resource = Chef::Resource::File.new("idontexist", run_context)
+      file_resource.guard_interpreter :powershell_script
+
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
+        { :convert_boolean_return => true, :code => "$true" }).and_return(Proc.new {})
+      resource.only_if("$true")
+    end
+
+    it "enables convert_boolean_return by default for guards in the context of powershell_script when guard params are specified" do
+      guard_parameters = { :cwd => "/etc/chef", :architecture => :x86_64 }
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
+        { :convert_boolean_return => true, :code => "$true" }.merge(guard_parameters)).and_return(Proc.new {})
+      resource.only_if("$true", guard_parameters)
+    end
+
+    it "passes convert_boolean_return as true if it was specified as true in a guard parameter" do
+      guard_parameters = { :cwd => "/etc/chef", :convert_boolean_return => true, :architecture => :x86_64 }
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
+        { :convert_boolean_return => true, :code => "$true" }.merge(guard_parameters)).and_return(Proc.new {})
+      resource.only_if("$true", guard_parameters)
+    end
+
+    it "passes convert_boolean_return as false if it was specified as true in a guard parameter" do
+      other_guard_parameters = { :cwd => "/etc/chef", :architecture => :x86_64 }
+      parameters_with_boolean_disabled = other_guard_parameters.merge({ :convert_boolean_return => false, :code => "$true" })
+      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
+        parameters_with_boolean_disabled).and_return(Proc.new {})
+      resource.only_if("$true", parameters_with_boolean_disabled)
+    end
+  end
+
+  context "as a script running in Windows-based scripting language" do
+    let(:resource_instance) { @resource }
+    let(:resource_instance_name ) { @resource.command }
+    let(:resource_name) { :powershell_script }
+    let(:interpreter_file_name) { "powershell.exe" }
+
+    it_behaves_like "a Windows script resource"
+  end
+end
diff --git a/spec/unit/resource/powershell_spec.rb b/spec/unit/resource/powershell_spec.rb
deleted file mode 100644
index c263172..0000000
--- a/spec/unit/resource/powershell_spec.rb
+++ /dev/null
@@ -1,131 +0,0 @@
-#
-# Author:: Adam Edwards (<adamed at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-
-describe Chef::Resource::PowershellScript do
-
-  before(:each) do
-    node = Chef::Node.new
-
-    node.default["kernel"] = Hash.new
-    node.default["kernel"][:machine] = :x86_64.to_s
-
-    run_context = Chef::RunContext.new(node, nil, nil)
-
-    @resource = Chef::Resource::PowershellScript.new("powershell_unit_test", run_context)
-
-  end
-
-  it "should create a new Chef::Resource::PowershellScript" do
-    expect(@resource).to be_a_kind_of(Chef::Resource::PowershellScript)
-  end
-
-  it "should set convert_boolean_return to false by default" do
-    expect(@resource.convert_boolean_return).to eq(false)
-  end
-
-  it "should return the value for convert_boolean_return that was set" do
-    @resource.convert_boolean_return true
-    expect(@resource.convert_boolean_return).to eq(true)
-    @resource.convert_boolean_return false
-    expect(@resource.convert_boolean_return).to eq(false)
-  end
-
-  context "when using guards" do
-    let(:resource) { @resource }
-    before(:each) do
-      allow(resource).to receive(:run_action)
-      allow(resource).to receive(:updated).and_return(true)
-    end
-
-    it "inherits exactly the :cwd, :environment, :group, :path, :user, :umask, and :architecture attributes from a parent resource class" do
-      inherited_difference = Chef::Resource::PowershellScript.guard_inherited_attributes -
-        [:cwd, :environment, :group, :path, :user, :umask, :architecture ]
-
-      expect(inherited_difference).to eq([])
-    end
-
-    it "should allow guard interpreter to be set to Chef::Resource::Script" do
-      resource.guard_interpreter(:script)
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
-      resource.only_if("echo hi")
-    end
-
-    it "should allow guard interpreter to be set to Chef::Resource::Bash derived from Chef::Resource::Script" do
-      resource.guard_interpreter(:bash)
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
-      resource.only_if("echo hi")
-    end
-
-    it "should allow guard interpreter to be set to Chef::Resource::PowershellScript derived indirectly from Chef::Resource::Script" do
-      resource.guard_interpreter(:powershell_script)
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(false)
-      resource.only_if("echo hi")
-    end
-
-    it "should enable convert_boolean_return by default for guards in the context of powershell_script when no guard params are specified" do
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:evaluate_action).and_return(true)
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
-        {:convert_boolean_return => true, :code => "$true"}).and_return(Proc.new {})
-      resource.only_if("$true")
-    end
-
-    it "should enable convert_boolean_return by default for guards in non-Chef::Resource::Script derived resources when no guard params are specified" do
-      node = Chef::Node.new
-      run_context = Chef::RunContext.new(node, nil, nil)
-      file_resource = Chef::Resource::File.new('idontexist', run_context)
-      file_resource.guard_interpreter :powershell_script
-
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
-        {:convert_boolean_return => true, :code => "$true"}).and_return(Proc.new {})
-      resource.only_if("$true")
-    end
-
-    it "should enable convert_boolean_return by default for guards in the context of powershell_script when guard params are specified" do
-      guard_parameters = {:cwd => '/etc/chef', :architecture => :x86_64}
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
-        {:convert_boolean_return => true, :code => "$true"}.merge(guard_parameters)).and_return(Proc.new {})
-      resource.only_if("$true", guard_parameters)
-    end
-
-    it "should pass convert_boolean_return as true if it was specified as true in a guard parameter" do
-      guard_parameters = {:cwd => '/etc/chef', :convert_boolean_return => true, :architecture => :x86_64}
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
-        {:convert_boolean_return => true, :code => "$true"}.merge(guard_parameters)).and_return(Proc.new {})
-      resource.only_if("$true", guard_parameters)
-    end
-
-    it "should pass convert_boolean_return as false if it was specified as true in a guard parameter" do
-      other_guard_parameters = {:cwd => '/etc/chef', :architecture => :x86_64}
-      parameters_with_boolean_disabled = other_guard_parameters.merge({:convert_boolean_return => false, :code => "$true"})
-      allow_any_instance_of(Chef::GuardInterpreter::ResourceGuardInterpreter).to receive(:block_from_attributes).with(
-        parameters_with_boolean_disabled).and_return(Proc.new {})
-      resource.only_if("$true", parameters_with_boolean_disabled)
-    end
-  end
-
-  context "as a script running in Windows-based scripting language" do
-    let(:resource_instance) { @resource }
-    let(:resource_instance_name ) { @resource.command }
-    let(:resource_name) { :powershell_script }
-    let(:interpreter_file_name) { 'powershell.exe' }
-
-    it_should_behave_like "a Windows script resource"
-  end
-end
diff --git a/spec/unit/resource/python_spec.rb b/spec/unit/resource/python_spec.rb
index 8a3f7e4..aba84c4 100644
--- a/spec/unit/resource/python_spec.rb
+++ b/spec/unit/resource/python_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Python do
 
diff --git a/spec/unit/resource/registry_key_spec.rb b/spec/unit/resource/registry_key_spec.rb
index e2a864d..472c511 100644
--- a/spec/unit/resource/registry_key_spec.rb
+++ b/spec/unit/resource/registry_key_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2012 OpsCode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::RegistryKey, "initialize" do
   before(:each) do
@@ -45,7 +45,7 @@ describe Chef::Resource::RegistryKey, "initialize" do
   end
 
   it "should set action to :create" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   %w{create create_if_missing delete delete_key}.each do |action|
@@ -80,38 +80,38 @@ describe Chef::Resource::RegistryKey, "values" do
   end
 
   it "should allow a single proper hash of registry values" do
-    @resource.values( { :name => 'poosh', :type => :string, :data => 'carmen' } )
-    expect(@resource.values).to eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ])
+    @resource.values( { :name => "poosh", :type => :string, :data => "carmen" } )
+    expect(@resource.values).to eql([ { :name => "poosh", :type => :string, :data => "carmen" } ])
   end
 
   it "should allow an array of proper hashes of registry values" do
-    @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen' } ]
-    expect(@resource.values).to eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ])
+    @resource.values [ { :name => "poosh", :type => :string, :data => "carmen" } ]
+    expect(@resource.values).to eql([ { :name => "poosh", :type => :string, :data => "carmen" } ])
   end
 
   it "should return checksummed data if the type is unsafe" do
-    @resource.values( { :name => 'poosh', :type => :binary, :data => 255.chr * 1 })
-    expect(@resource.values).to eql([ { :name => 'poosh', :type => :binary, :data => "00594fd4f42ba43fc1ca0427a0576295" } ])
+    @resource.values( { :name => "poosh", :type => :binary, :data => 255.chr * 1 })
+    expect(@resource.values).to eql([ { :name => "poosh", :type => :binary, :data => "a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89" } ])
   end
 
   it "should throw an exception if the name field is missing" do
-    expect { @resource.values [ { :type => :string, :data => 'carmen' } ] }.to raise_error(ArgumentError)
+    expect { @resource.values [ { :type => :string, :data => "carmen" } ] }.to raise_error(ArgumentError)
   end
 
   it "should throw an exception if the type field is missing" do
-    expect { @resource.values [ { :name => 'poosh', :data => 'carmen' } ] }.to raise_error(ArgumentError)
+    expect { @resource.values [ { :name => "poosh", :data => "carmen" } ] }.to raise_error(ArgumentError)
   end
 
   it "should throw an exception if the data field is missing" do
-    expect { @resource.values [ { :name => 'poosh', :type => :string } ] }.to raise_error(ArgumentError)
+    expect { @resource.values [ { :name => "poosh", :type => :string } ] }.to raise_error(ArgumentError)
   end
 
   it "should throw an exception if extra fields are present" do
-    expect { @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen', :screwdriver => 'sonic' } ] }.to raise_error(ArgumentError)
+    expect { @resource.values [ { :name => "poosh", :type => :string, :data => "carmen", :screwdriver => "sonic" } ] }.to raise_error(ArgumentError)
   end
 
   it "should not allow a string" do
-    expect { @resource.send(:values, 'souffle') }.to raise_error(ArgumentError)
+    expect { @resource.send(:values, "souffle") }.to raise_error(ArgumentError)
   end
 
   it "should not allow an integer" do
@@ -130,7 +130,7 @@ describe Chef::Resource::RegistryKey, "recursive" do
   end
 
   it "should not allow a hash" do
-    expect { @resource.recursive({:sonic => :screwdriver}) }.to raise_error(ArgumentError)
+    expect { @resource.recursive({ :sonic => :screwdriver }) }.to raise_error(ArgumentError)
   end
 
   it "should not allow an array" do
@@ -138,7 +138,7 @@ describe Chef::Resource::RegistryKey, "recursive" do
   end
 
   it "should not allow a string" do
-    expect { @resource.recursive('souffle') }.to raise_error(ArgumentError)
+    expect { @resource.recursive("souffle") }.to raise_error(ArgumentError)
   end
 
   it "should not allow an integer" do
@@ -159,7 +159,7 @@ describe Chef::Resource::RegistryKey, "architecture" do
   end
 
   it "should not allow a hash" do
-    expect { @resource.architecture({:sonic => :screwdriver}) }.to raise_error(ArgumentError)
+    expect { @resource.architecture({ :sonic => :screwdriver }) }.to raise_error(ArgumentError)
   end
 
   it "should not allow an array" do
@@ -167,7 +167,7 @@ describe Chef::Resource::RegistryKey, "architecture" do
   end
 
   it "should not allow a string" do
-    expect { @resource.architecture('souffle') }.to raise_error(ArgumentError)
+    expect { @resource.architecture("souffle") }.to raise_error(ArgumentError)
   end
 
   it "should not allow an integer" do
@@ -181,7 +181,7 @@ describe Chef::Resource::RegistryKey, ":unscrubbed_values" do
   end
 
   it "should return unsafe data as-is" do
-    key_values = [ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ]
+    key_values = [ { :name => "poosh", :type => :binary, :data => 255.chr * 1 } ]
     @resource.values(key_values)
     expect(@resource.unscrubbed_values).to eql(key_values)
   end
@@ -193,7 +193,7 @@ describe Chef::Resource::RegistryKey, "state" do
   end
 
   it "should return scrubbed values" do
-    @resource.values([ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ])
-    expect(@resource.state).to eql( { :values => [{ :name => 'poosh', :type => :binary, :data => "00594fd4f42ba43fc1ca0427a0576295" }] } )
+    @resource.values([ { :name => "poosh", :type => :binary, :data => 255.chr * 1 } ])
+    expect(@resource.state).to eql( { :values => [{ :name => "poosh", :type => :binary, :data => "a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89" }] } )
   end
 end
diff --git a/spec/unit/resource/remote_directory_spec.rb b/spec/unit/resource/remote_directory_spec.rb
index 1ab7558..cdca214 100644
--- a/spec/unit/resource/remote_directory_spec.rb
+++ b/spec/unit/resource/remote_directory_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::RemoteDirectory do
 
diff --git a/spec/unit/resource/remote_file_spec.rb b/spec/unit/resource/remote_file_spec.rb
index 3731d1a..718129a 100644
--- a/spec/unit/resource/remote_file_spec.rb
+++ b/spec/unit/resource/remote_file_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::RemoteFile do
 
@@ -36,9 +36,14 @@ describe Chef::Resource::RemoteFile do
   it "says its provider is RemoteFile when the source is an absolute URI" do
     @resource.source("http://www.google.com/robots.txt")
     expect(@resource.provider).to eq(Chef::Provider::RemoteFile)
-    expect(Chef::Platform.find_provider(:noplatform, 'noversion', @resource)).to eq(Chef::Provider::RemoteFile)
+    expect(Chef::Platform.find_provider(:noplatform, "noversion", @resource)).to eq(Chef::Provider::RemoteFile)
   end
 
+  it "says its provider is RemoteFile when the source is a network share" do
+    @resource.source("\\\\fakey\\fakerton\\fake.txt")
+    expect(@resource.provider).to eq(Chef::Provider::RemoteFile)
+    expect(Chef::Platform.find_provider(:noplatform, "noversion", @resource)).to eq(Chef::Provider::RemoteFile)
+  end
 
   describe "source" do
     it "does not have a default value for 'source'" do
@@ -50,8 +55,18 @@ describe Chef::Resource::RemoteFile do
       expect(@resource.source).to eql([ "http://opscode.com/" ])
     end
 
+    it "should accept a windows network share source" do
+      @resource.source "\\\\fakey\\fakerton\\fake.txt"
+      expect(@resource.source).to eql([ "\\\\fakey\\fakerton\\fake.txt" ])
+    end
+
+    it "should accept file URIs with spaces" do
+      @resource.source("file:///C:/foo bar")
+      expect(@resource.source).to eql(["file:///C:/foo bar"])
+    end
+
     it "should accept a delayed evalutator (string) for the remote file source" do
-      @resource.source Chef::DelayedEvaluator.new {"http://opscode.com/"}
+      @resource.source Chef::DelayedEvaluator.new { "http://opscode.com/" }
       expect(@resource.source).to eql([ "http://opscode.com/" ])
     end
 
@@ -72,13 +87,13 @@ describe Chef::Resource::RemoteFile do
 
     it "should only accept a single argument if a delayed evalutor is used" do
       expect {
-        @resource.source("http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"})
+        @resource.source("http://opscode.com/", Chef::DelayedEvaluator.new { "http://opscode.com/" })
       }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
     end
 
     it "should only accept a single array item if a delayed evalutor is used" do
       expect {
-        @resource.source(["http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"}])
+        @resource.source(["http://opscode.com/", Chef::DelayedEvaluator.new { "http://opscode.com/" }])
       }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
     end
 
@@ -88,7 +103,7 @@ describe Chef::Resource::RemoteFile do
 
     it "does not accept a non-URI as the source when read from a delayed evaluator" do
       expect {
-        @resource.source(Chef::DelayedEvaluator.new {"not-a-uri"})
+        @resource.source(Chef::DelayedEvaluator.new { "not-a-uri" })
         @resource.source
       }.to raise_error(Chef::Exceptions::InvalidRemoteFileURI)
     end
@@ -164,20 +179,20 @@ describe Chef::Resource::RemoteFile do
         @resource.owner("root")
       end
       @resource.source("https://www.google.com/images/srpr/logo3w.png")
-      @resource.checksum("1"*26)
+      @resource.checksum("1" * 26)
     end
 
     it "describes its state" do
       state = @resource.state
       if Chef::Platform.windows?
         puts state
-        expect(state[:rights]).to eq([{:permissions => :read, :principals => "Everyone"}])
-        expect(state[:deny_rights]).to eq([{:permissions => :full_control, :principals => "Clumsy_Sam"}])
+        expect(state[:rights]).to eq([{ :permissions => :read, :principals => "Everyone" }])
+        expect(state[:deny_rights]).to eq([{ :permissions => :full_control, :principals => "Clumsy_Sam" }])
       else
         expect(state[:group]).to eq("pokemon")
         expect(state[:mode]).to eq("0664")
         expect(state[:owner]).to eq("root")
-        expect(state[:checksum]).to eq("1"*26)
+        expect(state[:checksum]).to eq("1" * 26)
       end
     end
 
diff --git a/spec/unit/resource/resource_notification_spec.rb b/spec/unit/resource/resource_notification_spec.rb
index 7f6b124..5bb3ba9 100644
--- a/spec/unit/resource/resource_notification_spec.rb
+++ b/spec/unit/resource/resource_notification_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Tyler Ball (<tball at chef.io>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,153 +15,152 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
-require 'chef/resource/resource_notification'
+require "spec_helper"
+require "chef/resource/resource_notification"
 
 describe Chef::Resource::Notification do
-  before do
-    @notification = Chef::Resource::Notification.new(:service_apache, :restart, :template_httpd_conf)
-  end
+
+  let(:notification) { Chef::Resource::Notification.new(:service_apache, :restart, :template_httpd_conf) }
 
   it "has a resource to be notified" do
-    expect(@notification.resource).to eq(:service_apache)
+    expect(notification.resource).to eq(:service_apache)
   end
 
   it "has an action to take on the service" do
-    expect(@notification.action).to eq(:restart)
+    expect(notification.action).to eq(:restart)
   end
 
   it "has a notifying resource" do
-    expect(@notification.notifying_resource).to eq(:template_httpd_conf)
+    expect(notification.notifying_resource).to eq(:template_httpd_conf)
   end
 
   it "is a duplicate of another notification with the same target resource and action" do
     other = Chef::Resource::Notification.new(:service_apache, :restart, :sync_web_app_code)
-    expect(@notification.duplicates?(other)).to be_truthy
+    expect(notification.duplicates?(other)).to be_truthy
   end
 
   it "is not a duplicate of another notification if the actions differ" do
     other = Chef::Resource::Notification.new(:service_apache, :enable, :install_apache)
-    expect(@notification.duplicates?(other)).to be_falsey
+    expect(notification.duplicates?(other)).to be_falsey
   end
 
   it "is not a duplicate of another notification if the target resources differ" do
     other = Chef::Resource::Notification.new(:service_sshd, :restart, :template_httpd_conf)
-    expect(@notification.duplicates?(other)).to be_falsey
+    expect(notification.duplicates?(other)).to be_falsey
   end
 
   it "raises an ArgumentError if you try to check a non-ducktype object for duplication" do
-    expect {@notification.duplicates?(:not_a_notification)}.to raise_error(ArgumentError)
+    expect { notification.duplicates?(:not_a_notification) }.to raise_error(ArgumentError)
   end
 
   it "takes no action to resolve a resource reference that doesn't need to be resolved" do
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
-    @notification.resource = @keyboard_cat
+    notification.resource = @keyboard_cat
     @long_cat = Chef::Resource::Cat.new("long_cat")
-    @notification.notifying_resource = @long_cat
+    notification.notifying_resource = @long_cat
     @resource_collection = Chef::ResourceCollection.new
     # would raise an error since the resource is not in the collection
-    @notification.resolve_resource_reference(@resource_collection)
-    expect(@notification.resource).to eq(@keyboard_cat)
+    notification.resolve_resource_reference(@resource_collection)
+    expect(notification.resource).to eq(@keyboard_cat)
   end
 
   it "resolves a lazy reference to a resource" do
-    @notification.resource = {:cat => "keyboard_cat"}
+    notification.resource = { :cat => "keyboard_cat" }
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @keyboard_cat
     @long_cat = Chef::Resource::Cat.new("long_cat")
-    @notification.notifying_resource = @long_cat
-    @notification.resolve_resource_reference(@resource_collection)
-    expect(@notification.resource).to eq(@keyboard_cat)
+    notification.notifying_resource = @long_cat
+    notification.resolve_resource_reference(@resource_collection)
+    expect(notification.resource).to eq(@keyboard_cat)
   end
 
   it "resolves a lazy reference to its notifying resource" do
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
-    @notification.resource = @keyboard_cat
-    @notification.notifying_resource = {:cat => "long_cat"}
+    notification.resource = @keyboard_cat
+    notification.notifying_resource = { :cat => "long_cat" }
     @long_cat = Chef::Resource::Cat.new("long_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @long_cat
-    @notification.resolve_resource_reference(@resource_collection)
-    expect(@notification.notifying_resource).to eq(@long_cat)
+    notification.resolve_resource_reference(@resource_collection)
+    expect(notification.notifying_resource).to eq(@long_cat)
   end
 
   it "resolves lazy references to both its resource and its notifying resource" do
-    @notification.resource = {:cat => "keyboard_cat"}
+    notification.resource = { :cat => "keyboard_cat" }
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @keyboard_cat
-    @notification.notifying_resource = {:cat => "long_cat"}
+    notification.notifying_resource = { :cat => "long_cat" }
     @long_cat = Chef::Resource::Cat.new("long_cat")
     @resource_collection << @long_cat
-    @notification.resolve_resource_reference(@resource_collection)
-    expect(@notification.resource).to eq(@keyboard_cat)
-    expect(@notification.notifying_resource).to eq(@long_cat)
+    notification.resolve_resource_reference(@resource_collection)
+    expect(notification.resource).to eq(@keyboard_cat)
+    expect(notification.notifying_resource).to eq(@long_cat)
   end
 
   it "raises a RuntimeError if you try to reference multiple resources" do
-    @notification.resource = {:cat => ["keyboard_cat", "cheez_cat"]}
+    notification.resource = { :cat => ["keyboard_cat", "cheez_cat"] }
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
     @cheez_cat = Chef::Resource::Cat.new("cheez_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @keyboard_cat
     @resource_collection << @cheez_cat
     @long_cat = Chef::Resource::Cat.new("long_cat")
-    @notification.notifying_resource = @long_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+    notification.notifying_resource = @long_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
   end
 
   it "raises a RuntimeError if you try to reference multiple notifying resources" do
-    @notification.notifying_resource = {:cat => ["long_cat", "cheez_cat"]}
+    notification.notifying_resource = { :cat => ["long_cat", "cheez_cat"] }
     @long_cat = Chef::Resource::Cat.new("long_cat")
     @cheez_cat = Chef::Resource::Cat.new("cheez_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @long_cat
     @resource_collection << @cheez_cat
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
-    @notification.resource = @keyboard_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+    notification.resource = @keyboard_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
   end
 
   it "raises a RuntimeError if it can't find a resource in the resource collection when resolving a lazy reference" do
-    @notification.resource = {:cat => "keyboard_cat"}
+    notification.resource = { :cat => "keyboard_cat" }
     @cheez_cat = Chef::Resource::Cat.new("cheez_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @cheez_cat
     @long_cat = Chef::Resource::Cat.new("long_cat")
-    @notification.notifying_resource = @long_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+    notification.notifying_resource = @long_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
   end
 
   it "raises a RuntimeError if it can't find a notifying resource in the resource collection when resolving a lazy reference" do
-    @notification.notifying_resource = {:cat => "long_cat"}
+    notification.notifying_resource = { :cat => "long_cat" }
     @cheez_cat = Chef::Resource::Cat.new("cheez_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @cheez_cat
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
-    @notification.resource = @keyboard_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(RuntimeError)
+    notification.resource = @keyboard_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(RuntimeError)
   end
 
   it "raises an ArgumentError if improper syntax is used in the lazy reference to its resource" do
-    @notification.resource = "cat => keyboard_cat"
+    notification.resource = "cat => keyboard_cat"
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @keyboard_cat
     @long_cat = Chef::Resource::Cat.new("long_cat")
-    @notification.notifying_resource = @long_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(ArgumentError)
+    notification.notifying_resource = @long_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(ArgumentError)
   end
 
   it "raises an ArgumentError if improper syntax is used in the lazy reference to its notifying resource" do
-    @notification.notifying_resource = "cat => long_cat"
+    notification.notifying_resource = "cat => long_cat"
     @long_cat = Chef::Resource::Cat.new("long_cat")
     @resource_collection = Chef::ResourceCollection.new
     @resource_collection << @long_cat
     @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat")
-    @notification.resource = @keyboard_cat
-    expect {@notification.resolve_resource_reference(@resource_collection)}.to raise_error(ArgumentError)
+    notification.resource = @keyboard_cat
+    expect { notification.resolve_resource_reference(@resource_collection) }.to raise_error(ArgumentError)
   end
 
   # Create test to resolve lazy references to both notifying resource and dest. resource
diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb
index ec1d369..259ccf7 100644
--- a/spec/unit/resource/route_spec.rb
+++ b/spec/unit/resource/route_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Bryan McLellan (btm at loftninjas.org)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Bryan McLellan
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Bryan McLellan
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Route do
 
diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb
index d3b505f..1a0089b 100644
--- a/spec/unit/resource/rpm_package_spec.rb
+++ b/spec/unit/resource/rpm_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::RpmPackage, "initialize" do
 
@@ -27,7 +27,7 @@ describe Chef::Resource::RpmPackage, "initialize" do
       provider: Chef::Provider::Package::Rpm,
       name: :rpm_package,
       action: :install,
-      os: os
+      os: os,
     )
   end
 
diff --git a/spec/unit/resource/ruby_block_spec.rb b/spec/unit/resource/ruby_block_spec.rb
index 9f19fec..f393fbe 100644
--- a/spec/unit/resource/ruby_block_spec.rb
+++ b/spec/unit/resource/ruby_block_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::RubyBlock do
 
@@ -30,8 +30,8 @@ describe Chef::Resource::RubyBlock do
     expect(@resource).to be_a_kind_of(Chef::Resource::RubyBlock)
   end
 
-  it "should have a default action of 'create'" do
-    expect(@resource.action).to eql("run")
+  it "should have a default action of 'run'" do
+    expect(@resource.action).to eql([:run])
   end
 
   it "should have a resource name of :ruby_block" do
diff --git a/spec/unit/resource/ruby_spec.rb b/spec/unit/resource/ruby_spec.rb
index e899810..d7b6759 100644
--- a/spec/unit/resource/ruby_spec.rb
+++ b/spec/unit/resource/ruby_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Ruby do
 
diff --git a/spec/unit/resource/scm_spec.rb b/spec/unit/resource/scm_spec.rb
index 7231927..f393343 100644
--- a/spec/unit/resource/scm_spec.rb
+++ b/spec/unit/resource/scm_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Scm do
 
@@ -101,7 +101,7 @@ describe Chef::Resource::Scm do
   it "takes the depth as an integer for shallow clones" do
     @resource.depth 5
     expect(@resource.depth).to eq(5)
-    expect {@resource.depth "five"}.to raise_error(ArgumentError)
+    expect { @resource.depth "five" }.to raise_error(ArgumentError)
   end
 
   it "defaults to nil depth for a full clone" do
@@ -111,7 +111,7 @@ describe Chef::Resource::Scm do
   it "takes a boolean for #enable_submodules" do
     @resource.enable_submodules true
     expect(@resource.enable_submodules).to be_truthy
-    expect {@resource.enable_submodules "lolz"}.to raise_error(ArgumentError)
+    expect { @resource.enable_submodules "lolz" }.to raise_error(ArgumentError)
   end
 
   it "defaults to not enabling submodules" do
@@ -121,7 +121,7 @@ describe Chef::Resource::Scm do
   it "takes a boolean for #enable_checkout" do
     @resource.enable_checkout true
     expect(@resource.enable_checkout).to be_truthy
-    expect {@resource.enable_checkout "lolz"}.to raise_error(ArgumentError)
+    expect { @resource.enable_checkout "lolz" }.to raise_error(ArgumentError)
   end
 
   it "defaults to enabling checkout" do
@@ -131,7 +131,7 @@ describe Chef::Resource::Scm do
   it "takes a string for the remote" do
     @resource.remote "opscode"
     expect(@resource.remote).to eql("opscode")
-    expect {@resource.remote 1337}.to raise_error(ArgumentError)
+    expect { @resource.remote 1337 }.to raise_error(ArgumentError)
   end
 
   it "defaults to ``origin'' for the remote" do
@@ -184,7 +184,7 @@ describe Chef::Resource::Scm do
   end
 
   describe "when it has a environment attribute" do
-    let(:test_environment) { {'CHEF_ENV' => '/tmp' } }
+    let(:test_environment) { { "CHEF_ENV" => "/tmp" } }
     before { @resource.environment(test_environment) }
     it "stores this environment" do
       expect(@resource.environment).to eq(test_environment)
diff --git a/spec/unit/resource/script_spec.rb b/spec/unit/resource/script_spec.rb
index 4affee8..fca9fb0 100644
--- a/spec/unit/resource/script_spec.rb
+++ b/spec/unit/resource/script_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Script do
   let(:resource_instance_name) { "fakey_fakerton" }
diff --git a/spec/unit/resource/service_spec.rb b/spec/unit/resource/service_spec.rb
index eb6f444..e06f5bc 100644
--- a/spec/unit/resource/service_spec.rb
+++ b/spec/unit/resource/service_spec.rb
@@ -1,7 +1,7 @@
 #
 # Author:: AJ Christensen (<aj at hjksolutions.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Tyler Cloke (<tyler at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Service do
 
@@ -139,14 +139,14 @@ describe Chef::Resource::Service do
       expect { @resource.send(attrib, "poop") }.to raise_error(ArgumentError)
     end
 
-    it "should default all the feature support to false" do
-      support_hash = { :status => false, :restart => false, :reload=> false }
+    it "should default all the feature support to nil" do
+      support_hash = { :status => nil, :restart => nil, :reload => nil }
       expect(@resource.supports).to eq(support_hash)
     end
 
     it "should allow you to set what features this resource supports as a array" do
       support_array = [ :status, :restart ]
-      support_hash = { :status => true, :restart => true, :reload => false }
+      support_hash = { :status => true, :restart => true, :reload => nil }
       @resource.supports(support_array)
       expect(@resource.supports).to eq(support_hash)
     end
@@ -176,5 +176,4 @@ describe Chef::Resource::Service do
     end
   end
 
-
 end
diff --git a/spec/unit/resource/smartos_package_spec.rb b/spec/unit/resource/smartos_package_spec.rb
index c2cf546..8b1fb2e 100644
--- a/spec/unit/resource/smartos_package_spec.rb
+++ b/spec/unit/resource/smartos_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Thomas Bishop (<bishop.thomas at gmail.com>)
-# Copyright:: Copyright (c) 2010 Thomas Bishop
+# Copyright:: Copyright 2010-2016, Thomas Bishop
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::SmartosPackage, "initialize" do
 
diff --git a/spec/unit/resource/solaris_package_spec.rb b/spec/unit/resource/solaris_package_spec.rb
index f5d3e66..80d84c1 100644
--- a/spec/unit/resource/solaris_package_spec.rb
+++ b/spec/unit/resource/solaris_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Prabhu Das (<prabhu.das at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::SolarisPackage, "initialize" do
 
diff --git a/spec/unit/resource/subversion_spec.rb b/spec/unit/resource/subversion_spec.rb
index 5cd5d0d..47b8ddf 100644
--- a/spec/unit/resource/subversion_spec.rb
+++ b/spec/unit/resource/subversion_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::Subversion do
 
@@ -42,7 +42,7 @@ describe Chef::Resource::Subversion do
   end
 
   it "sets svn info arguments to --no-auth-cache by default" do
-    expect(@svn.svn_info_args).to eq('--no-auth-cache')
+    expect(@svn.svn_info_args).to eq("--no-auth-cache")
   end
 
   it "resets svn info arguments to nil when given false in the setter" do
@@ -51,7 +51,11 @@ describe Chef::Resource::Subversion do
   end
 
   it "sets svn arguments to --no-auth-cache by default" do
-    expect(@svn.svn_arguments).to eq('--no-auth-cache')
+    expect(@svn.svn_arguments).to eq("--no-auth-cache")
+  end
+
+  it "sets svn binary to nil by default" do
+    expect(@svn.svn_binary).to be_nil
   end
 
   it "resets svn arguments to nil when given false in the setter" do
diff --git a/spec/unit/resource/template_spec.rb b/spec/unit/resource/template_spec.rb
index df5ca94..9060f02 100644
--- a/spec/unit/resource/template_spec.rb
+++ b/spec/unit/resource/template_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::Template do
 
@@ -98,7 +98,7 @@ describe Chef::Resource::Template do
 
     context "on windows", :windows_only do
       # according to Chef::Resource::File, windows state attributes are rights + deny_rights
-      pending "it describes its state"
+      skip "it describes its state"
     end
 
     it "returns the file path as its identity" do
@@ -127,7 +127,7 @@ describe Chef::Resource::Template do
       modules = @resource.helper_modules
       expect(modules.size).to eq(1)
       o = Object.new
-      modules.each {|m| o.extend(m)}
+      modules.each { |m| o.extend(m) }
       expect(o.example_1).to eq("example_1")
       expect(o.example_2).to eq("example_2")
     end
@@ -136,7 +136,7 @@ describe Chef::Resource::Template do
       @resource.helper(:shout) { |quiet| quiet.upcase }
       modules = @resource.helper_modules
       o = Object.new
-      modules.each {|m| o.extend(m)}
+      modules.each { |m| o.extend(m) }
       expect(o.shout("shout")).to eq("SHOUT")
     end
 
@@ -167,7 +167,7 @@ describe Chef::Resource::Template do
       modules = @resource.helper_modules
       expect(modules.size).to eq(1)
       o = Object.new
-      modules.each {|m| o.extend(m)}
+      modules.each { |m| o.extend(m) }
       expect(o.example_1).to eq("example_1")
     end
 
@@ -199,13 +199,12 @@ describe Chef::Resource::Template do
       expect(@resource.helper_modules.size).to eq(3)
 
       o = Object.new
-      @resource.helper_modules.each {|m| o.extend(m)}
+      @resource.helper_modules.each { |m| o.extend(m) }
       expect(o.static_example).to eq("static_example")
       expect(o.inline_module).to eq("inline_module")
       expect(o.inline_method).to eq("inline_method")
     end
 
-
   end
 
 end
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index eca6c57..ad7ebe7 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,17 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::TimestampedDeploy, "initialize" do
 
   static_provider_resolution(
     resource: Chef::Resource::TimestampedDeploy,
     provider: Chef::Provider::Deploy::Timestamped,
-    name: :deploy,
+    name: :timestamped_deploy,
     action: :deploy,
-    os: 'linux',
-    platform_family: 'rhel',
+    os: "linux",
+    platform_family: "rhel",
   )
 
 end
-
diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb
index f05de94..9648ee1 100644
--- a/spec/unit/resource/user_spec.rb
+++ b/spec/unit/resource/user_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::User, "initialize" do
   before(:each) do
@@ -43,7 +43,7 @@ describe Chef::Resource::User, "initialize" do
   end
 
   it "should set action to :create" do
-    expect(@resource.action).to eql(:create)
+    expect(@resource.action).to eql([:create])
   end
 
   it "should set supports[:manage_home] to false" do
@@ -68,7 +68,7 @@ describe Chef::Resource::User, "initialize" do
     expect { @resource.username "domain\@user" }.not_to raise_error
     expect(@resource.username).to eq("domain\@user")
     expect { @resource.username "domain\\user" }.not_to raise_error
-    expect(@resource.username).to  eq("domain\\user")
+    expect(@resource.username).to eq("domain\\user")
   end
 end
 
diff --git a/spec/unit/resource/windows_package_spec.rb b/spec/unit/resource/windows_package_spec.rb
index 1e02f24..05c40bf 100644
--- a/spec/unit/resource/windows_package_spec.rb
+++ b/spec/unit/resource/windows_package_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::WindowsPackage, "initialize" do
   before(:each) do
@@ -28,7 +28,7 @@ describe Chef::Resource::WindowsPackage, "initialize" do
     provider: Chef::Provider::Package::Windows,
     os: "windows",
     name: :windows_package,
-    action: :start
+    action: :start,
   )
 
   let(:resource) { Chef::Resource::WindowsPackage.new("solitaire.msi") }
@@ -63,9 +63,9 @@ describe Chef::Resource::WindowsPackage, "initialize" do
   end
 
   it "coverts a source to an absolute path" do
-    allow(::File).to receive(:absolute_path).and_return("c:\\Files\\frost.msi")
+    allow(::File).to receive(:absolute_path).and_return("c:\\files\\frost.msi")
     resource.source("frost.msi")
-    expect(resource.source).to eql "c:\\Files\\frost.msi"
+    expect(resource.source).to eql "c:\\files\\frost.msi"
   end
 
   it "converts slashes to backslashes in the source path" do
@@ -78,4 +78,18 @@ describe Chef::Resource::WindowsPackage, "initialize" do
     # it's a little late to stub out File.absolute_path
     expect(resource.source).to include("solitaire.msi")
   end
+
+  it "supports the checksum attribute" do
+    resource.checksum("somechecksum")
+    expect(resource.checksum).to eq("somechecksum")
+  end
+
+  context "when a URL is used" do
+    let(:resource_source) { "https://foo.bar/solitare.msi" }
+    let(:resource) { Chef::Resource::WindowsPackage.new(resource_source) }
+
+    it "should return the source unmodified" do
+      expect(resource.source).to eq(resource_source)
+    end
+  end
 end
diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb
index 45a295c..bb4b91b 100644
--- a/spec/unit/resource/windows_service_spec.rb
+++ b/spec/unit/resource/windows_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Resource::WindowsService, "initialize" do
   static_provider_resolution(
@@ -24,7 +24,7 @@ describe Chef::Resource::WindowsService, "initialize" do
     provider: Chef::Provider::Service::Windows,
     os: "windows",
     name: :windows_service,
-    action: :start
+    action: :start,
   )
 
   let(:resource) { Chef::Resource::WindowsService.new("BITS") }
diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb
index e01b87c..195f8c5 100644
--- a/spec/unit/resource/yum_package_spec.rb
+++ b/spec/unit/resource/yum_package_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: AJ Christensen (<aj at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: AJ Christensen (<aj at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/shared/unit/resource/static_provider_resolution'
+require "spec_helper"
+require "support/shared/unit/resource/static_provider_resolution"
 
 describe Chef::Resource::YumPackage, "initialize" do
 
@@ -26,8 +26,8 @@ describe Chef::Resource::YumPackage, "initialize" do
     provider: Chef::Provider::Package::Yum,
     name: :yum_package,
     action: :install,
-    os: 'linux',
-    platform_family: 'rhel',
+    os: "linux",
+    platform_family: "rhel",
   )
 
 end
@@ -78,3 +78,12 @@ describe Chef::Resource::YumPackage, "allow_downgrade" do
     expect { @resource.allow_downgrade "monkey" }.to raise_error(ArgumentError)
   end
 end
+
+describe Chef::Resource::YumPackage, "yum_binary" do
+  let(:resource) { Chef::Resource::YumPackage.new("foo") }
+
+  it "should allow you to specify the yum_binary" do
+    resource.yum_binary "/usr/bin/yum-something"
+    expect(resource.yum_binary).to eql("/usr/bin/yum-something")
+  end
+end
diff --git a/spec/unit/resource_collection/resource_list_spec.rb b/spec/unit/resource_collection/resource_list_spec.rb
index 1e6c477..dabb8f0 100644
--- a/spec/unit/resource_collection/resource_list_spec.rb
+++ b/spec/unit/resource_collection/resource_list_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::ResourceCollection::ResourceList do
   let(:resource_list) { Chef::ResourceCollection::ResourceList.new() }
@@ -24,7 +24,7 @@ describe Chef::ResourceCollection::ResourceList do
   let(:second_resource) { Chef::Resource::ZenMaster.new("hattori") }
 
   def insert_resource(res)
-    expect{ resource_list.insert(res) }.not_to raise_error
+    expect { resource_list.insert(res) }.not_to raise_error
   end
 
   describe "initialize" do
@@ -47,14 +47,14 @@ describe Chef::ResourceCollection::ResourceList do
     end
 
     it "should raise error when trying to install something other than Chef::Resource" do
-      expect{ resource_list.insert("not a resource") }.to raise_error(ArgumentError)
+      expect { resource_list.insert("not a resource") }.to raise_error(ArgumentError)
     end
   end
 
   describe "accessors" do
     it "should be able to insert with []=" do
-      expect{ resource_list[0] = resource }.not_to raise_error
-      expect{ resource_list[1] = second_resource }.not_to raise_error
+      expect { resource_list[0] = resource }.not_to raise_error
+      expect { resource_list[1] = second_resource }.not_to raise_error
       expect(resource_list[0]).to be(resource)
       expect(resource_list[1]).to be(second_resource)
     end
diff --git a/spec/unit/resource_collection/resource_set_spec.rb b/spec/unit/resource_collection/resource_set_spec.rb
index 0e25934..2f8ba0e 100644
--- a/spec/unit/resource_collection/resource_set_spec.rb
+++ b/spec/unit/resource_collection/resource_set_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Tyler Ball (<tball at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Tyler Ball (<tball at chef.io>)
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::ResourceCollection::ResourceSet do
   let(:collection) { Chef::ResourceCollection::ResourceSet.new }
@@ -78,13 +78,13 @@ describe Chef::ResourceCollection::ResourceSet do
     it "should find a resource by type symbol and array of names" do
       collection.insert_as(zen_master)
       collection.insert_as(zen_master2)
-      check_by_names(collection.find(:zen_master => [zen_master_name,zen_master2_name]), zen_master_name, zen_master2_name)
+      check_by_names(collection.find(:zen_master => [zen_master_name, zen_master2_name]), zen_master_name, zen_master2_name)
     end
 
     it "should find a resource by type symbol and array of names with custom names" do
       collection.insert_as(zen_master, :zzz, "name1")
       collection.insert_as(zen_master2, :zzz, "name2")
-      check_by_names(collection.find( :zzz => ["name1","name2"]), zen_master_name, zen_master2_name)
+      check_by_names(collection.find( :zzz => ["name1", "name2"]), zen_master_name, zen_master2_name)
     end
 
     it "should find resources of multiple kinds (:zen_master => a, :zen_follower => b)" do
@@ -98,7 +98,7 @@ describe Chef::ResourceCollection::ResourceSet do
       collection.insert_as(zen_master, :zzz, "name1")
       collection.insert_as(zen_master2, :zzz, "name2")
       collection.insert_as(zen_follower, :yyy, "name3")
-      check_by_names(collection.find(:zzz => ["name1","name2"], :yyy => ["name3"]),
+      check_by_names(collection.find(:zzz => ["name1", "name2"], :yyy => ["name3"]),
                      zen_master_name, zen_follower_name, zen_master2_name)
     end
 
@@ -138,13 +138,13 @@ describe Chef::ResourceCollection::ResourceSet do
       collection.insert_as(zen_master2, :zzz, "name2")
       collection.insert_as(zen_follower, :yyy, "name3")
       check_by_names(collection.find("zzz[name1,name2]", "yyy[name3]"),
-                     zen_master_name, zen_follower_name,zen_master2_name)
+                     zen_master_name, zen_follower_name, zen_master2_name)
     end
 
     it "should only keep the last copy when multiple instances of a Resource are inserted" do
       collection.insert_as(zen_master)
       expect(collection.find("zen_master[#{zen_master_name}]")).to eq(zen_master)
-      new_zm =zen_master.dup
+      new_zm = zen_master.dup
       new_zm.retries = 10
       expect(new_zm).to_not eq(zen_master)
       collection.insert_as(new_zm)
@@ -192,7 +192,7 @@ describe Chef::ResourceCollection::ResourceSet do
   def check_by_names(results, *names)
     expect(results.size).to eq(names.size)
     names.each do |name|
-      expect(results.detect{|r| r.name == name}).to_not eq(nil)
+      expect(results.detect { |r| r.name == name }).to_not eq(nil)
     end
   end
 
diff --git a/spec/unit/resource_collection/stepable_iterator_spec.rb b/spec/unit/resource_collection/stepable_iterator_spec.rb
index b34b714..6354b1b 100644
--- a/spec/unit/resource_collection/stepable_iterator_spec.rb
+++ b/spec/unit/resource_collection/stepable_iterator_spec.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::ResourceCollection::StepableIterator do
   CRSI = Chef::ResourceCollection::StepableIterator
@@ -26,7 +26,7 @@ describe Chef::ResourceCollection::StepableIterator do
 
   describe "doing basic iteration" do
     before do
-      @simple_collection = [1,2,3,4]
+      @simple_collection = [1, 2, 3, 4]
       @iterator = CRSI.for_collection(@simple_collection)
     end
 
@@ -57,7 +57,7 @@ describe Chef::ResourceCollection::StepableIterator do
       @iterator.each_with_index do |element, index|
         collected[index] = element
       end
-      expect(collected).to eq({0=>1, 1=>2, 2=>3, 3=>4})
+      expect(collected).to eq({ 0 => 1, 1 => 2, 2 => 3, 3 => 4 })
     end
 
   end
@@ -117,7 +117,7 @@ describe Chef::ResourceCollection::StepableIterator do
 
     it "doesn't step if there are no more steps" do
       expect(@iterator.step).to eq(3)
-      expect {@iterator.step}.not_to raise_error
+      expect { @iterator.step }.not_to raise_error
       expect(@iterator.step).to be_nil
     end
 
@@ -131,7 +131,7 @@ describe Chef::ResourceCollection::StepableIterator do
     end
 
     it "should work correctly when elements are added to the collection during iteration" do
-      @collection.insert(2, lambda { @snitch_var = 815})
+      @collection.insert(2, lambda { @snitch_var = 815 })
       @collection.insert(3, lambda { @iterator.pause })
       @iterator.resume
       expect(@snitch_var).to eq(815)
diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb
index b43b012..178d58b 100644
--- a/spec/unit/resource_collection_spec.rb
+++ b/spec/unit/resource_collection_spec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::ResourceCollection do
   let(:rc) { Chef::ResourceCollection.new() }
@@ -65,7 +65,7 @@ describe Chef::ResourceCollection do
     end
 
     it "should accept named arguments in any order" do
-      rc.insert(resource, :instance_name => 'foo', :resource_type =>'bar')
+      rc.insert(resource, :instance_name => "foo", :resource_type => "bar")
       expect(rc[0]).to eq(resource)
     end
 
@@ -211,7 +211,7 @@ describe Chef::ResourceCollection do
     end
 
     it "raises an error when attempting to find a resource that does not exist" do
-      expect {rc.find("script[nonesuch]")}.to raise_error(Chef::Exceptions::ResourceNotFound)
+      expect { rc.find("script[nonesuch]") }.to raise_error(Chef::Exceptions::ResourceNotFound)
     end
 
   end
@@ -225,7 +225,6 @@ describe Chef::ResourceCollection do
       expect(rc.validate_lookup_spec!(:service => "apache2")).to be_truthy
     end
 
-
     it "accepts a chef resource object" do
       res = Chef::Resource.new("foo", nil)
       expect(rc.validate_lookup_spec!(res)).to be_truthy
@@ -252,7 +251,7 @@ describe Chef::ResourceCollection do
       expect(json).to match(/instance_vars/)
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { rc }
     end
   end
@@ -286,13 +285,13 @@ describe Chef::ResourceCollection do
 
   def check_by_names(results, *names)
     names.each do |res_name|
-      expect(results.detect{ |res| res.name == res_name }).not_to eql(nil)
+      expect(results.detect { |res| res.name == res_name }).not_to eql(nil)
     end
   end
 
   def load_up_resources
     %w{dog cat monkey}.each do |n|
-       rc << Chef::Resource::ZenMaster.new(n)
+      rc << Chef::Resource::ZenMaster.new(n)
     end
     rc << Chef::Resource::File.new("something")
   end
diff --git a/spec/unit/resource_definition_spec.rb b/spec/unit/resource_definition_spec.rb
index 1371a8b..45dfaff 100644
--- a/spec/unit/resource_definition_spec.rb
+++ b/spec/unit/resource_definition_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::ResourceDefinition do
   let(:defn) { Chef::ResourceDefinition.new() }
diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb
index 4f3a085..30b5717 100644
--- a/spec/unit/resource_reporter_spec.rb
+++ b/spec/unit/resource_reporter_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Author:: Prajakta Purohit (<prajakta at opscode.com>)
-# Author:: Tyler Cloke (<tyler at opscode.com>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Author:: Prajakta Purohit (<prajakta at chef.io>)
+# Author:: Tyler Cloke (<tyler at chef.io>)
 #
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +20,8 @@
 #
 
 require File.expand_path("../../spec_helper", __FILE__)
-require 'chef/resource_reporter'
-require 'socket'
+require "chef/resource_reporter"
+require "socket"
 
 describe Chef::ResourceReporter do
   before(:all) do
@@ -36,20 +36,23 @@ describe Chef::ResourceReporter do
   before do
     @node = Chef::Node.new
     @node.name("spitfire")
-    @rest_client = double("Chef::REST (mock)")
-    allow(@rest_client).to receive(:post_rest).and_return(true)
+    @rest_client = double("Chef::ServerAPI (mock)")
+    allow(@rest_client).to receive(:post).and_return(true)
     @resource_reporter = Chef::ResourceReporter.new(@rest_client)
     @new_resource      = Chef::Resource::File.new("/tmp/a-file.txt")
     @cookbook_name = "monkey"
     @new_resource.cookbook_name = @cookbook_name
     @cookbook_version = double("Cookbook::Version", :version => "1.2.3")
     allow(@new_resource).to receive(:cookbook_version).and_return(@cookbook_version)
-    @current_resource  = Chef::Resource::File.new("/tmp/a-file.txt")
+    @current_resource = Chef::Resource::File.new("/tmp/a-file.txt")
     @start_time = Time.new
     @end_time = Time.new + 20
     @events = Chef::EventDispatch::Dispatcher.new
     @run_context = Chef::RunContext.new(@node, {}, @events)
     @run_status = Chef::RunStatus.new(@node, @events)
+    @run_list = Chef::RunList.new
+    @run_list << "recipe[lobster]" << "role[rage]" << "recipe[fist]"
+    @expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items)
     @run_id = @run_status.run_id
     allow(Time).to receive(:now).and_return(@start_time, @end_time)
   end
@@ -89,9 +92,8 @@ describe Chef::ResourceReporter do
 
   context "when chef fails" do
     before do
-      allow(@rest_client).to receive(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}");
-      allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
-      allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"});
+      allow(@rest_client).to receive(:raw_request).and_return({ "result" => "ok" });
+      allow(@rest_client).to receive(:post).and_return({ "uri" => "https://example.com/reports/nodes/spitfire/runs/#{@run_id}" });
 
     end
 
@@ -199,13 +201,13 @@ describe Chef::ResourceReporter do
       context "and a nested resource is updated" do
         before do
           @implementation_resource = Chef::Resource::CookbookFile.new("/preseed-file.txt")
-        @resource_reporter.resource_action_start(@implementation_resource , :create)
-        @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource)
-        @resource_reporter.resource_updated(@implementation_resource, :create)
-        @resource_reporter.resource_completed(@implementation_resource)
-        @resource_reporter.resource_updated(@new_resource, :create)
-        @resource_reporter.resource_completed(@new_resource)
-      end
+          @resource_reporter.resource_action_start(@implementation_resource , :create)
+          @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource)
+          @resource_reporter.resource_updated(@implementation_resource, :create)
+          @resource_reporter.resource_completed(@implementation_resource)
+          @resource_reporter.resource_updated(@new_resource, :create)
+          @resource_reporter.resource_completed(@new_resource)
+        end
 
         it "does not collect data about the nested resource" do
           expect(@resource_reporter.updated_resources.size).to eq(1)
@@ -257,9 +259,8 @@ describe Chef::ResourceReporter do
   describe "when generating a report for the server" do
 
     before do
-      allow(@rest_client).to receive(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}");
-      allow(@rest_client).to receive(:raw_http_request).and_return({"result"=>"ok"});
-      allow(@rest_client).to receive(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"});
+      allow(@rest_client).to receive(:raw_request).and_return({ "result" => "ok" });
+      allow(@rest_client).to receive(:post).and_return({ "uri" => "https://example.com/reports/nodes/spitfire/runs/#{@run_id}" });
 
       @resource_reporter.run_started(@run_status)
     end
@@ -270,6 +271,7 @@ describe Chef::ResourceReporter do
           @bad_resource = Chef::Resource::File.new("/tmp/nameless_file.txt")
           allow(@bad_resource).to receive(:name).and_return(nil)
           allow(@bad_resource).to receive(:identity).and_return(nil)
+          allow(@bad_resource).to receive(:path).and_return(nil)
           @resource_reporter.resource_action_start(@bad_resource, :create)
           @resource_reporter.resource_current_state_loaded(@bad_resource, :create, @current_resource)
           @resource_reporter.resource_updated(@bad_resource, :create)
@@ -291,8 +293,9 @@ describe Chef::ResourceReporter do
       context "the new_resource name and id are hashes" do
         before do
           @bad_resource = Chef::Resource::File.new("/tmp/filename_as_hash.txt")
-          allow(@bad_resource).to receive(:name).and_return({:foo=>:bar})
-          allow(@bad_resource).to receive(:identity).and_return({:foo=>:bar})
+          allow(@bad_resource).to receive(:name).and_return({ :foo => :bar })
+          allow(@bad_resource).to receive(:identity).and_return({ :foo => :bar })
+          allow(@bad_resource).to receive(:path).and_return({ :foo => :bar })
           @resource_reporter.resource_action_start(@bad_resource, :create)
           @resource_reporter.resource_current_state_loaded(@bad_resource, :create, @current_resource)
           @resource_reporter.resource_updated(@bad_resource, :create)
@@ -424,6 +427,10 @@ describe Chef::ResourceReporter do
         expect(@report["run_list"]).to eq(Chef::JSONCompat.to_json(@run_status.node.run_list))
       end
 
+      it "includes the expanded_run_list" do
+        expect(@report).to have_key("expanded_run_list")
+      end
+
       it "includes the end_time" do
         expect(@report).to have_key("end_time")
         expect(@report["end_time"]).to eq(@run_status.end_time.to_s)
@@ -441,7 +448,7 @@ describe Chef::ResourceReporter do
     context "when the resource is a RegistryKey with binary data" do
       let(:new_resource) do
         resource = Chef::Resource::RegistryKey.new('Wubba\Lubba\Dub\Dubs')
-        resource.values([ { :name => 'rick', :type => :binary, :data => 255.chr * 1 } ])
+        resource.values([ { :name => "rick", :type => :binary, :data => 255.chr * 1 } ])
         allow(resource).to receive(:cookbook_name).and_return(@cookbook_name)
         allow(resource).to receive(:cookbook_version).and_return(@cookbook_version)
         resource
@@ -449,7 +456,7 @@ describe Chef::ResourceReporter do
 
       let(:current_resource) do
         resource = Chef::Resource::RegistryKey.new('Wubba\Lubba\Dub\Dubs')
-        resource.values([ { :name => 'rick', :type => :binary, :data => 255.chr * 1 } ])
+        resource.values([ { :name => "rick", :type => :binary, :data => 255.chr * 1 } ])
         resource
       end
 
@@ -459,7 +466,7 @@ describe Chef::ResourceReporter do
     context "for an unsuccessful run" do
 
       before do
-        @backtrace = ["foo.rb:1 in `foo!'","bar.rb:2 in `bar!","'baz.rb:3 in `baz!'"]
+        @backtrace = ["foo.rb:1 in `foo!'", "bar.rb:2 in `bar!", "'baz.rb:3 in `baz!'"]
         @node = Chef::Node.new
         @node.name("spitfire")
         @exception = ArgumentError.new
@@ -489,7 +496,7 @@ describe Chef::ResourceReporter do
 
       it "includes the error inspector output in the event data" do
         expect(@report["data"]["exception"]).to have_key("description")
-        expect(@report["data"]["exception"]["description"]).to include({"title"=>"Error expanding the run_list:", "sections"=>[{"Unexpected Error:" => "ArgumentError: Object not found"}]})
+        expect(@report["data"]["exception"]["description"]).to include({ "title" => "Error expanding the run_list:", "sections" => [{ "Unexpected Error:" => "ArgumentError: Object not found" }] })
       end
 
     end
@@ -563,12 +570,12 @@ describe Chef::ResourceReporter do
 
       it "sets before to {} instead of nil" do
         expect(@first_update_report).to have_key("before")
-        expect(@first_update_report['before']).to eq({})
+        expect(@first_update_report["before"]).to eq({})
       end
 
       it "sets after to {} instead of 'Running'" do
         expect(@first_update_report).to have_key("after")
-        expect(@first_update_report['after']).to eq({})
+        expect(@first_update_report["after"]).to eq({})
       end
     end
 
@@ -585,10 +592,10 @@ describe Chef::ResourceReporter do
         # 404 getting the run_id
         @response = Net::HTTPNotFound.new("a response body", "404", "Not Found")
         @error = Net::HTTPServerException.new("404 message", @response)
-        expect(@rest_client).to receive(:post_rest).
-          with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id,
-                                               :start_time => @start_time.to_s},
-               {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+        expect(@rest_client).to receive(:post).
+          with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id,
+                                                :start_time => @start_time.to_s },
+               { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
           and_raise(@error)
       end
 
@@ -599,7 +606,7 @@ describe Chef::ResourceReporter do
 
       it "does not send a resource report to the server" do
         @resource_reporter.run_started(@run_status)
-        expect(@rest_client).not_to receive(:post_rest)
+        expect(@rest_client).not_to receive(:post)
         @resource_reporter.run_completed(@node)
       end
 
@@ -615,9 +622,9 @@ describe Chef::ResourceReporter do
         # 500 getting the run_id
         @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error")
         @error = Net::HTTPServerException.new("500 message", @response)
-        expect(@rest_client).to receive(:post_rest).
-          with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
-               {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+        expect(@rest_client).to receive(:post).
+          with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+               { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
           and_raise(@error)
       end
 
@@ -628,7 +635,7 @@ describe Chef::ResourceReporter do
 
       it "does not send a resource report to the server" do
         @resource_reporter.run_started(@run_status)
-        expect(@rest_client).not_to receive(:post_rest)
+        expect(@rest_client).not_to receive(:post)
         @resource_reporter.run_completed(@node)
       end
 
@@ -645,9 +652,9 @@ describe Chef::ResourceReporter do
         # 500 getting the run_id
         @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error")
         @error = Net::HTTPServerException.new("500 message", @response)
-        expect(@rest_client).to receive(:post_rest).
-          with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
-               {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+        expect(@rest_client).to receive(:post).
+          with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+               { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
           and_raise(@error)
       end
 
@@ -665,10 +672,10 @@ describe Chef::ResourceReporter do
 
     context "after creating the run history document" do
       before do
-        response = {"uri"=>"https://example.com/reports/nodes/spitfire/runs/@run_id"}
-        expect(@rest_client).to receive(:post_rest).
-          with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s},
-               {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}).
+        response = { "uri" => "https://example.com/reports/nodes/spitfire/runs/@run_id" }
+        expect(@rest_client).to receive(:post).
+          with("reports/nodes/spitfire/runs", { :action => :start, :run_id => @run_id, :start_time => @start_time.to_s },
+               { "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION }).
           and_return(response)
         @resource_reporter.run_started(@run_status)
       end
@@ -686,19 +693,13 @@ describe Chef::ResourceReporter do
         allow(@resource_reporter).to receive(:end_time).and_return(@end_time)
         @expected_data = @resource_reporter.prepare_run_data
 
-        post_url = "https://chef_server/example_url"
-        response = {"result"=>"ok"}
+        response = { "result" => "ok" }
 
-        expect(@rest_client).to receive(:create_url).
-          with("reports/nodes/spitfire/runs/#{@run_id}").
-          ordered.
-          and_return(post_url)
-        expect(@rest_client).to receive(:raw_http_request).ordered do |method, url, headers, data|
+        expect(@rest_client).to receive(:raw_request).ordered do |method, url, headers, data|
           expect(method).to eq(:POST)
-          expect(url).to eq(post_url)
-          expect(headers).to eq({'Content-Encoding' => 'gzip',
-                             'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION
-          })
+          expect(headers).to eq({ "Content-Encoding" => "gzip",
+                                  "X-Ops-Reporting-Protocol-Version" => Chef::ResourceReporter::PROTOCOL_VERSION,
+          },)
           data_stream = Zlib::GzipReader.new(StringIO.new(data))
           data = data_stream.read
           expect(data).to eq(Chef::JSONCompat.to_json(@expected_data))
@@ -713,8 +714,6 @@ describe Chef::ResourceReporter do
       before do
         @enable_reporting_url_fatals = Chef::Config[:enable_reporting_url_fatals]
         Chef::Config[:enable_reporting_url_fatals] = true
-        # this call doesn't matter for this context
-        allow(@rest_client).to receive(:create_url)
       end
 
       after do
@@ -724,7 +723,7 @@ describe Chef::ResourceReporter do
       it "should log 4xx errors" do
         response = Net::HTTPClientError.new("forbidden", "403", "Forbidden")
         error = Net::HTTPServerException.new("403 message", response)
-        allow(@rest_client).to receive(:raw_http_request).and_raise(error)
+        allow(@rest_client).to receive(:raw_request).and_raise(error)
         expect(Chef::Log).to receive(:error).with(/403/)
 
         @resource_reporter.post_reporting_data
@@ -733,14 +732,14 @@ describe Chef::ResourceReporter do
       it "should log error 5xx errors" do
         response = Net::HTTPServerError.new("internal error", "500", "Internal Server Error")
         error = Net::HTTPFatalError.new("500 message", response)
-        allow(@rest_client).to receive(:raw_http_request).and_raise(error)
+        allow(@rest_client).to receive(:raw_request).and_raise(error)
         expect(Chef::Log).to receive(:error).with(/500/)
 
         @resource_reporter.post_reporting_data
       end
 
       it "should log if a socket error happens" do
-        allow(@rest_client).to receive(:raw_http_request).and_raise(SocketError.new("test socket error"))
+        allow(@rest_client).to receive(:raw_request).and_raise(SocketError.new("test socket error"))
         expect(Chef::Log).to receive(:error).with(/test socket error/)
 
         @resource_reporter.post_reporting_data
@@ -748,7 +747,7 @@ describe Chef::ResourceReporter do
       end
 
       it "should raise if an unkwown error happens" do
-        allow(@rest_client).to receive(:raw_http_request).and_raise(Exception.new)
+        allow(@rest_client).to receive(:raw_request).and_raise(Exception.new)
 
         expect {
           @resource_reporter.post_reporting_data
diff --git a/spec/unit/resource_resolver_spec.rb b/spec/unit/resource_resolver_spec.rb
new file mode 100644
index 0000000..f3a20ab
--- /dev/null
+++ b/spec/unit/resource_resolver_spec.rb
@@ -0,0 +1,52 @@
+#
+# Author:: Ranjib Dey
+# Copyright:: Copyright 2015-2016, Ranjib Dey <ranjib at linux.com>.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "chef/resource_resolver"
+
+describe Chef::ResourceResolver do
+  it '#resolve' do
+    expect(described_class.resolve(:execute)).to eq(Chef::Resource::Execute)
+  end
+
+  it '#list' do
+    expect(described_class.list(:package)).to_not be_empty
+  end
+
+  context "instance methods" do
+    let(:resolver) do
+      described_class.new(Chef::Node.new, "execute")
+    end
+
+    it '#resolve' do
+      expect(resolver.resolve).to eq Chef::Resource::Execute
+    end
+
+    it '#list' do
+      expect(resolver.list).to eq [ Chef::Resource::Execute ]
+    end
+
+    it '#provided_by? returns true when resource class is in the list' do
+      expect(resolver.provided_by?(Chef::Resource::Execute)).to be_truthy
+    end
+
+    it '#provided_by? returns false when resource class is not in the list' do
+      expect(resolver.provided_by?(Chef::Resource::File)).to be_falsey
+    end
+  end
+end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 6b2d6c8..1297ed6 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Seth Chisamore (<schisamo at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Seth Chisamore (<schisamo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,20 +19,27 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-
-class ResourceTestHarness < Chef::Resource
-  provider_base Chef::Provider::Package
-end
+require "spec_helper"
 
 describe Chef::Resource do
-  before(:each) do
-    @cookbook_repo_path =  File.join(CHEF_SPEC_DATA, 'cookbooks')
-    @cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(@cookbook_repo_path))
-    @node = Chef::Node.new
-    @events = Chef::EventDispatch::Dispatcher.new
-    @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
-    @resource = Chef::Resource.new("funk", @run_context)
+  let(:cookbook_repo_path) { File.join(CHEF_SPEC_DATA, "cookbooks") }
+  let(:cookbook_collection) { Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo_path)) }
+  let(:node) { Chef::Node.new }
+  let(:events) { Chef::EventDispatch::Dispatcher.new }
+  let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
+  let(:resource) { resource_class.new("funk", run_context) }
+  let(:resource_class) { Chef::Resource }
+
+  it "should mixin shell_out" do
+    expect(resource.respond_to?(:shell_out)).to be true
+  end
+
+  it "should mixin shell_out!" do
+    expect(resource.respond_to?(:shell_out!)).to be true
+  end
+
+  it "should mixin shell_out_with_systems_locale" do
+    expect(resource.respond_to?(:shell_out_with_systems_locale)).to be true
   end
 
   describe "when inherited" do
@@ -51,8 +58,8 @@ describe Chef::Resource do
   end
 
   describe "when declaring the identity attribute" do
-    it "has no identity attribute by default" do
-      expect(Chef::Resource.identity_attr).to be_nil
+    it "has :name as identity attribute by default" do
+      expect(Chef::Resource.identity_attr).to eq(:name)
     end
 
     it "sets an identity attribute" do
@@ -78,30 +85,29 @@ describe Chef::Resource do
   end
 
   describe "when no identity attribute has been declared" do
-    before do
-      @resource_sans_id = Chef::Resource.new("my-name")
-    end
+    let(:resource_sans_id) { Chef::Resource.new("my-name") }
 
     # Would rather force identity attributes to be set for everything,
     # but that's not plausible for back compat reasons.
     it "uses the name as the identity" do
-      expect(@resource_sans_id.identity).to eq("my-name")
+      expect(resource_sans_id.identity).to eq("my-name")
     end
   end
 
   describe "when an identity attribute has been declared" do
-    before do
-      @file_resource_class = Class.new(Chef::Resource) do
+    let(:file_resource) {
+      file_resource_class = Class.new(Chef::Resource) do
         identity_attr :path
         attr_accessor :path
       end
 
-      @file_resource = @file_resource_class.new("identity-attr-test")
-      @file_resource.path = "/tmp/foo.txt"
-    end
+      file_resource = file_resource_class.new("identity-attr-test")
+      file_resource.path = "/tmp/foo.txt"
+      file_resource
+    }
 
     it "gives the value of its identity attribute" do
-      expect(@file_resource.identity).to eq("/tmp/foo.txt")
+      expect(file_resource.identity).to eq("/tmp/foo.txt")
     end
   end
 
@@ -134,8 +140,8 @@ describe Chef::Resource do
   end
 
   describe "when a set of state attributes has been declared" do
-    before do
-      @file_resource_class = Class.new(Chef::Resource) do
+    let(:file_resource) {
+      file_resource_class = Class.new(Chef::Resource) do
 
         state_attrs :checksum, :owner, :group, :mode
 
@@ -145,15 +151,16 @@ describe Chef::Resource do
         attr_accessor :mode
       end
 
-      @file_resource = @file_resource_class.new("describe-state-test")
-      @file_resource.checksum = "abc123"
-      @file_resource.owner = "root"
-      @file_resource.group = "wheel"
-      @file_resource.mode = "0644"
-    end
+      file_resource = file_resource_class.new("describe-state-test")
+      file_resource.checksum = "abc123"
+      file_resource.owner = "root"
+      file_resource.group = "wheel"
+      file_resource.mode = "0644"
+      file_resource
+    }
 
     it "describes its state" do
-      resource_state = @file_resource.state
+      resource_state = file_resource.state
       expect(resource_state.keys).to match_array([:checksum, :owner, :group, :mode])
       expect(resource_state[:checksum]).to eq("abc123")
       expect(resource_state[:owner]).to eq("root")
@@ -163,157 +170,160 @@ describe Chef::Resource do
   end
 
   describe "load_from" do
+    let(:prior_resource) {
+      prior_resource = Chef::Resource.new("funk")
+      prior_resource.supports(:funky => true)
+      prior_resource.source_line
+      prior_resource.allowed_actions << :funkytown
+      prior_resource.action(:funkytown)
+      prior_resource
+    }
     before(:each) do
-      @prior_resource = Chef::Resource.new("funk")
-      @prior_resource.supports(:funky => true)
-      @prior_resource.source_line
-      @prior_resource.allowed_actions << :funkytown
-      @prior_resource.action(:funkytown)
-      @resource.allowed_actions << :funkytown
-      @run_context.resource_collection << @prior_resource
+      resource.allowed_actions << :funkytown
+      run_context.resource_collection << prior_resource
     end
 
     it "should load the attributes of a prior resource" do
-      @resource.load_from(@prior_resource)
-      expect(@resource.supports).to eq({ :funky => true })
+      resource.load_from(prior_resource)
+      expect(resource.supports).to eq({ :funky => true })
     end
 
     it "should not inherit the action from the prior resource" do
-      @resource.load_from(@prior_resource)
-      expect(@resource.action).not_to eq(@prior_resource.action)
+      resource.load_from(prior_resource)
+      expect(resource.action).not_to eq(prior_resource.action)
     end
   end
 
   describe "name" do
     it "should have a name" do
-      expect(@resource.name).to eql("funk")
+      expect(resource.name).to eql("funk")
     end
 
     it "should let you set a new name" do
-      @resource.name "monkey"
-      expect(@resource.name).to eql("monkey")
+      resource.name "monkey"
+      expect(resource.name).to eql("monkey")
     end
 
     it "coerces arrays to names" do
-      expect(@resource.name ['a', 'b']).to eql('a, b')
+      expect(resource.name ["a", "b"]).to eql("a, b")
     end
 
     it "should coerce objects to a string" do
-      expect(@resource.name Object.new).to be_a(String)
+      expect(resource.name Object.new).to be_a(String)
     end
   end
 
   describe "noop" do
     it "should accept true or false for noop" do
-      expect { @resource.noop true }.not_to raise_error
-      expect { @resource.noop false }.not_to raise_error
-      expect { @resource.noop "eat it" }.to raise_error(ArgumentError)
+      expect { resource.noop true }.not_to raise_error
+      expect { resource.noop false }.not_to raise_error
+      expect { resource.noop "eat it" }.to raise_error(ArgumentError)
     end
   end
 
   describe "notifies" do
     it "should make notified resources appear in the actions hash" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee")
-      expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee")
+      expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
     end
 
     it "should make notified resources be capable of acting immediately" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :immediate
-      expect(@resource.immediate_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee"), :immediate
+      expect(resource.immediate_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
     end
 
     it "should raise an exception if told to act in other than :delay or :immediate(ly)" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
       expect {
-        @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :someday
+        resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee"), :someday
       }.to raise_error(ArgumentError)
     end
 
     it "should allow multiple notified resources appear in the actions hash" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee")
-      expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee")
+      expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee" && e.action == :reload }).not_to be_nil
 
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("beans")
-      @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "beans")
-      expect(@resource.delayed_notifications.detect{|e| e.resource.name == "beans" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("beans")
+      resource.notifies :reload, run_context.resource_collection.find(:zen_master => "beans")
+      expect(resource.delayed_notifications.detect { |e| e.resource.name == "beans" && e.action == :reload }).not_to be_nil
     end
 
     it "creates a notification for a resource that is not yet in the resource collection" do
-      @resource.notifies(:restart, :service => 'apache')
-      expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
-      expect(@resource.delayed_notifications).to include(expected_notification)
+      resource.notifies(:restart, :service => "apache")
+      expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+      expect(resource.delayed_notifications).to include(expected_notification)
     end
 
     it "notifies another resource immediately" do
-      @resource.notifies_immediately(:restart, :service => 'apache')
-      expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
-      expect(@resource.immediate_notifications).to include(expected_notification)
+      resource.notifies_immediately(:restart, :service => "apache")
+      expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+      expect(resource.immediate_notifications).to include(expected_notification)
     end
 
     it "notifies a resource to take action at the end of the chef run" do
-      @resource.notifies_delayed(:restart, :service => "apache")
-      expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource)
-      expect(@resource.delayed_notifications).to include(expected_notification)
+      resource.notifies_delayed(:restart, :service => "apache")
+      expected_notification = Chef::Resource::Notification.new({ :service => "apache" }, :restart, resource)
+      expect(resource.delayed_notifications).to include(expected_notification)
     end
 
     it "notifies a resource with an array for its name via its prettified string name" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new(["coffee", "tea"])
-      @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee, tea")
-      expect(@resource.delayed_notifications.detect{|e| e.resource.name == "coffee, tea" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new(["coffee", "tea"])
+      resource.notifies :reload, run_context.resource_collection.find(:zen_master => "coffee, tea")
+      expect(resource.delayed_notifications.detect { |e| e.resource.name == "coffee, tea" && e.action == :reload }).not_to be_nil
     end
   end
 
   describe "subscribes" do
     it "should make resources appear in the actions hash of subscribed nodes" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      zr = @run_context.resource_collection.find(:zen_master => "coffee")
-      @resource.subscribes :reload, zr
-      expect(zr.delayed_notifications.detect{|e| e.resource.name == "funk" && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      zr = run_context.resource_collection.find(:zen_master => "coffee")
+      resource.subscribes :reload, zr
+      expect(zr.delayed_notifications.detect { |e| e.resource.name == "funk" && e.action == :reload }).not_to be_nil
     end
 
     it "should make resources appear in the actions hash of subscribed nodes" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      zr = @run_context.resource_collection.find(:zen_master => "coffee")
-      @resource.subscribes :reload, zr
-      expect(zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      zr = run_context.resource_collection.find(:zen_master => "coffee")
+      resource.subscribes :reload, zr
+      expect(zr.delayed_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
 
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("bean")
-      zrb = @run_context.resource_collection.find(:zen_master => "bean")
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("bean")
+      zrb = run_context.resource_collection.find(:zen_master => "bean")
       zrb.subscribes :reload, zr
-      expect(zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+      expect(zr.delayed_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
     end
 
     it "should make subscribed resources be capable of acting immediately" do
-      @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
-      zr = @run_context.resource_collection.find(:zen_master => "coffee")
-      @resource.subscribes :reload, zr, :immediately
-      expect(zr.immediate_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}).not_to be_nil
+      run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee")
+      zr = run_context.resource_collection.find(:zen_master => "coffee")
+      resource.subscribes :reload, zr, :immediately
+      expect(zr.immediate_notifications.detect { |e| e.resource.name == resource.name && e.action == :reload }).not_to be_nil
     end
   end
 
   describe "defined_at" do
     it "should correctly parse source_line on unix-like operating systems" do
-      @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
-      expect(@resource.defined_at).to eq("/some/path/to/file.rb line 80")
+      resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
+      expect(resource.defined_at).to eq("/some/path/to/file.rb line 80")
     end
 
     it "should correctly parse source_line on Windows" do
-      @resource.source_line = "C:/some/path/to/file.rb:80 in 1`wombat_tears'"
-      expect(@resource.defined_at).to eq("C:/some/path/to/file.rb line 80")
+      resource.source_line = "C:/some/path/to/file.rb:80 in 1`wombat_tears'"
+      expect(resource.defined_at).to eq("C:/some/path/to/file.rb line 80")
     end
 
     it "should include the cookbook and recipe when it knows it" do
-      @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
-      @resource.recipe_name = "wombats"
-      @resource.cookbook_name = "animals"
-      expect(@resource.defined_at).to eq("animals::wombats line 80")
+      resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'"
+      resource.recipe_name = "wombats"
+      resource.cookbook_name = "animals"
+      expect(resource.defined_at).to eq("animals::wombats line 80")
     end
 
     it "should recognize dynamically defined resources" do
-      expect(@resource.defined_at).to eq("dynamically defined")
+      expect(resource.defined_at).to eq("dynamically defined")
     end
   end
 
@@ -324,33 +334,126 @@ describe Chef::Resource do
     end
   end
 
+  describe "self.resource_name" do
+    context "When resource_name is not set" do
+      it "and there are no provides lines, resource_name is nil" do
+        c = Class.new(Chef::Resource) do
+        end
+
+        r = c.new("hi")
+        r.declared_type = :d
+        expect(c.resource_name).to be_nil
+        expect(r.resource_name).to be_nil
+        expect(r.declared_type).to eq :d
+      end
+
+      it "and there are no provides lines, resource_name is used" do
+        c = Class.new(Chef::Resource) do
+          def initialize(*args, &block)
+            @resource_name = :blah
+            super
+          end
+        end
+
+        r = c.new("hi")
+        r.declared_type = :d
+        expect(c.resource_name).to be_nil
+        expect(r.resource_name).to eq :blah
+        expect(r.declared_type).to eq :d
+      end
+
+      it "and the resource class gets a late-bound name, resource_name is nil" do
+        c = Class.new(Chef::Resource) do
+          def self.name
+            "ResourceSpecNameTest"
+          end
+        end
+
+        r = c.new("hi")
+        r.declared_type = :d
+        expect(c.resource_name).to be_nil
+        expect(r.resource_name).to be_nil
+        expect(r.declared_type).to eq :d
+      end
+    end
+
+    it "resource_name without provides is honored" do
+      c = Class.new(Chef::Resource) do
+        resource_name "blah"
+      end
+
+      r = c.new("hi")
+      r.declared_type = :d
+      expect(c.resource_name).to eq :blah
+      expect(r.resource_name).to eq :blah
+      expect(r.declared_type).to eq :d
+    end
+    it "setting class.resource_name with 'resource_name = blah' overrides declared_type" do
+      c = Class.new(Chef::Resource) do
+        provides :self_resource_name_test_2
+      end
+      c.resource_name = :blah
+
+      r = c.new("hi")
+      r.declared_type = :d
+      expect(c.resource_name).to eq :blah
+      expect(r.resource_name).to eq :blah
+      expect(r.declared_type).to eq :d
+    end
+    it "setting class.resource_name with 'resource_name blah' overrides declared_type" do
+      c = Class.new(Chef::Resource) do
+        resource_name :blah
+        provides :self_resource_name_test_3
+      end
+
+      r = c.new("hi")
+      r.declared_type = :d
+      expect(c.resource_name).to eq :blah
+      expect(r.resource_name).to eq :blah
+      expect(r.declared_type).to eq :d
+    end
+  end
+
   describe "is" do
     it "should return the arguments passed with 'is'" do
       zm = Chef::Resource::ZenMaster.new("coffee")
-      expect(zm.is("one", "two", "three")).to eq(%w|one two three|)
+      expect(zm.is("one", "two", "three")).to eq(%w{one two three})
     end
 
     it "should allow arguments preceded by is to methods" do
-      @resource.noop(@resource.is(true))
-      expect(@resource.noop).to eql(true)
+      resource.noop(resource.is(true))
+      expect(resource.noop).to eql(true)
     end
   end
 
   describe "to_json" do
     it "should serialize to json" do
-      json = @resource.to_json
+      json = resource.to_json
       expect(json).to match(/json_class/)
       expect(json).to match(/instance_vars/)
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
-      let(:jsonable) { @resource }
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
+      let(:jsonable) { resource }
     end
   end
 
   describe "to_hash" do
+    context "when the resource has a property with a default" do
+      let(:resource_class) { Class.new(Chef::Resource) { property :a, default: 1 } }
+      it "should include the default in the hash" do
+        expect(resource.to_hash.keys.sort).to eq([:a, :allowed_actions, :params, :provider, :updated,
+          :updated_by_last_action, :before, :supports,
+          :noop, :ignore_failure, :name, :source_line,
+          :action, :retries, :retry_delay, :elapsed_time,
+          :default_guard_interpreter, :guard_interpreter, :sensitive].sort)
+        expect(resource.to_hash[:name]).to eq "funk"
+        expect(resource.to_hash[:a]).to eq 1
+      end
+    end
+
     it "should convert to a hash" do
-      hash = @resource.to_hash
+      hash = resource.to_hash
       expected_keys = [ :allowed_actions, :params, :provider, :updated,
         :updated_by_last_action, :before, :supports,
         :noop, :ignore_failure, :name, :source_line,
@@ -364,80 +467,83 @@ describe Chef::Resource do
 
   describe "self.json_create" do
     it "should deserialize itself from json" do
-      json = Chef::JSONCompat.to_json(@resource)
+      json = Chef::JSONCompat.to_json(resource)
       serialized_node = Chef::JSONCompat.from_json(json)
       expect(serialized_node).to be_a_kind_of(Chef::Resource)
-      expect(serialized_node.name).to eql(@resource.name)
+      expect(serialized_node.name).to eql(resource.name)
     end
   end
 
   describe "supports" do
     it "should allow you to set what features this resource supports" do
       support_hash = { :one => :two }
-      @resource.supports(support_hash)
-      expect(@resource.supports).to eql(support_hash)
+      resource.supports(support_hash)
+      expect(resource.supports).to eql(support_hash)
     end
 
     it "should return the current value of supports" do
-      expect(@resource.supports).to eq({})
+      expect(resource.supports).to eq({})
     end
   end
 
   describe "ignore_failure" do
     it "should default to throwing an error if a provider fails for a resource" do
-      expect(@resource.ignore_failure).to eq(false)
+      expect(resource.ignore_failure).to eq(false)
     end
 
     it "should allow you to set whether a provider should throw exceptions with ignore_failure" do
-      @resource.ignore_failure(true)
-      expect(@resource.ignore_failure).to eq(true)
+      resource.ignore_failure(true)
+      expect(resource.ignore_failure).to eq(true)
     end
 
     it "should allow you to epic_fail" do
-      @resource.epic_fail(true)
-      expect(@resource.epic_fail).to eq(true)
+      resource.epic_fail(true)
+      expect(resource.epic_fail).to eq(true)
     end
   end
 
   describe "retries" do
-    before do
-      @retriable_resource = Chef::Resource::Cat.new("precious", @run_context)
-      @retriable_resource.provider = Chef::Provider::SnakeOil
-      @retriable_resource.action = :purr
+    let(:retriable_resource) {
+      retriable_resource = Chef::Resource::Cat.new("precious", run_context)
+      retriable_resource.provider = Chef::Provider::SnakeOil
+      retriable_resource.action = :purr
+      retriable_resource
+    }
 
-      @node.automatic_attrs[:platform] = "fubuntu"
-      @node.automatic_attrs[:platform_version] = '10.04'
+    before do
+      node.automatic_attrs[:platform] = "fubuntu"
+      node.automatic_attrs[:platform_version] = "10.04"
     end
 
     it "should default to not retrying if a provider fails for a resource" do
-      expect(@retriable_resource.retries).to eq(0)
+      expect(retriable_resource.retries).to eq(0)
     end
 
     it "should allow you to set how many retries a provider should attempt after a failure" do
-      @retriable_resource.retries(2)
-      expect(@retriable_resource.retries).to eq(2)
+      retriable_resource.retries(2)
+      expect(retriable_resource.retries).to eq(2)
     end
 
     it "should default to a retry delay of 2 seconds" do
-      expect(@retriable_resource.retry_delay).to eq(2)
+      expect(retriable_resource.retry_delay).to eq(2)
     end
 
     it "should allow you to set the retry delay" do
-      @retriable_resource.retry_delay(10)
-      expect(@retriable_resource.retry_delay).to eq(10)
+      retriable_resource.retry_delay(10)
+      expect(retriable_resource.retry_delay).to eq(10)
     end
 
     it "should keep given value of retries intact after the provider fails for a resource" do
-      @retriable_resource.retries(3)
-      @retriable_resource.retry_delay(0) # No need to wait.
+      retriable_resource.retries(3)
+      retriable_resource.retry_delay(0) # No need to wait.
 
-      provider = Chef::Provider::SnakeOil.new(@retriable_resource, @run_context)
+      provider = Chef::Provider::SnakeOil.new(retriable_resource, run_context)
       allow(Chef::Provider::SnakeOil).to receive(:new).and_return(provider)
       allow(provider).to receive(:action_purr).and_raise
 
-      expect(@retriable_resource).to receive(:sleep).exactly(3).times
-      expect { @retriable_resource.run_action(:purr) }.to raise_error
-      expect(@retriable_resource.retries).to eq(3)
+      expect(retriable_resource).to receive(:sleep).exactly(3).times
+      expect { retriable_resource.run_action(:purr) }.to raise_error
+      expect(retriable_resource.retries).to eq(3)
     end
   end
 
@@ -447,8 +553,21 @@ describe Chef::Resource do
       expect(Chef::Resource.provider_base).to eq(Chef::Provider)
     end
 
-    it "allows the base provider to be overriden by a " do
-      expect(ResourceTestHarness.provider_base).to eq(Chef::Provider::Package)
+    it "allows the base provider to be overridden" do
+      Chef::Config.treat_deprecation_warnings_as_errors(false)
+      class OverrideProviderBaseTest < Chef::Resource
+        provider_base Chef::Provider::Package
+      end
+
+      expect(OverrideProviderBaseTest.provider_base).to eq(Chef::Provider::Package)
+    end
+
+    it "warns when setting provider_base" do
+      expect {
+        class OverrideProviderBaseTest2 < Chef::Resource
+          provider_base Chef::Provider::Package
+        end
+      }.to raise_error(Chef::Exceptions::DeprecatedFeatureError)
     end
 
   end
@@ -459,28 +578,28 @@ describe Chef::Resource do
 
   describe "when updated by a provider" do
     before do
-      @resource.updated_by_last_action(true)
+      resource.updated_by_last_action(true)
     end
 
     it "records that it was updated" do
-      expect(@resource).to be_updated
+      expect(resource).to be_updated
     end
 
     it "records that the last action updated the resource" do
-      expect(@resource).to be_updated_by_last_action
+      expect(resource).to be_updated_by_last_action
     end
 
     describe "and then run again without being updated" do
       before do
-        @resource.updated_by_last_action(false)
+        resource.updated_by_last_action(false)
       end
 
       it "reports that it is updated" do
-        expect(@resource).to be_updated
+        expect(resource).to be_updated
       end
 
       it "reports that it was not updated by the last action" do
-        expect(@resource).not_to be_updated_by_last_action
+        expect(resource).not_to be_updated_by_last_action
       end
 
     end
@@ -488,72 +607,75 @@ describe Chef::Resource do
   end
 
   describe "when invoking its action" do
+    let(:resource) {
+      resource = Chef::Resource.new("provided", run_context)
+      resource.provider = Chef::Provider::SnakeOil
+      resource
+    }
     before do
-      @resource = Chef::Resource.new("provided", @run_context)
-      @resource.provider = Chef::Provider::SnakeOil
-      @node.automatic_attrs[:platform] = "fubuntu"
-      @node.automatic_attrs[:platform_version] = '10.04'
+      node.automatic_attrs[:platform] = "fubuntu"
+      node.automatic_attrs[:platform_version] = "10.04"
     end
 
     it "does not run only_if if no only_if command is given" do
       expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate)
-      @resource.only_if.clear
-      @resource.run_action(:purr)
+      resource.only_if.clear
+      resource.run_action(:purr)
     end
 
     it "runs runs an only_if when one is given" do
       snitch_variable = nil
-      @resource.only_if { snitch_variable = true }
-      expect(@resource.only_if.first.positivity).to eq(:only_if)
+      resource.only_if { snitch_variable = true }
+      expect(resource.only_if.first.positivity).to eq(:only_if)
       #Chef::Mixin::Command.should_receive(:only_if).with(true, {}).and_return(false)
-      @resource.run_action(:purr)
+      resource.run_action(:purr)
       expect(snitch_variable).to be_truthy
     end
 
     it "runs multiple only_if conditionals" do
       snitch_var1, snitch_var2 = nil, nil
-      @resource.only_if { snitch_var1 = 1 }
-      @resource.only_if { snitch_var2 = 2 }
-      @resource.run_action(:purr)
+      resource.only_if { snitch_var1 = 1 }
+      resource.only_if { snitch_var2 = 2 }
+      resource.run_action(:purr)
       expect(snitch_var1).to eq(1)
       expect(snitch_var2).to eq(2)
     end
 
     it "accepts command options for only_if conditionals" do
       expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_command).at_least(1).times
-      @resource.only_if("true", :cwd => '/tmp')
-      expect(@resource.only_if.first.command_opts).to eq({:cwd => '/tmp'})
-      @resource.run_action(:purr)
+      resource.only_if("true", :cwd => "/tmp")
+      expect(resource.only_if.first.command_opts).to eq({ :cwd => "/tmp" })
+      resource.run_action(:purr)
     end
 
     it "runs not_if as a command when it is a string" do
       expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_command).at_least(1).times
-      @resource.not_if "pwd"
-      @resource.run_action(:purr)
+      resource.not_if "pwd"
+      resource.run_action(:purr)
     end
 
     it "runs not_if as a block when it is a ruby block" do
       expect_any_instance_of(Chef::Resource::Conditional).to receive(:evaluate_block).at_least(1).times
-      @resource.not_if { puts 'foo' }
-      @resource.run_action(:purr)
+      resource.not_if { puts "foo" }
+      resource.run_action(:purr)
     end
 
     it "does not run not_if if no not_if command is given" do
       expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:evaluate)
-      @resource.not_if.clear
-      @resource.run_action(:purr)
+      resource.not_if.clear
+      resource.run_action(:purr)
     end
 
     it "accepts command options for not_if conditionals" do
-      @resource.not_if("pwd" , :cwd => '/tmp')
-      expect(@resource.not_if.first.command_opts).to eq({:cwd => '/tmp'})
+      resource.not_if("pwd" , :cwd => "/tmp")
+      expect(resource.not_if.first.command_opts).to eq({ :cwd => "/tmp" })
     end
 
     it "accepts multiple not_if conditionals" do
       snitch_var1, snitch_var2 = true, true
-      @resource.not_if {snitch_var1 = nil}
-      @resource.not_if {snitch_var2 = false}
-      @resource.run_action(:purr)
+      resource.not_if { snitch_var1 = nil }
+      resource.not_if { snitch_var2 = false }
+      resource.run_action(:purr)
       expect(snitch_var1).to be_nil
       expect(snitch_var2).to be_falsey
     end
@@ -561,13 +683,11 @@ describe Chef::Resource do
     it "reports 0 elapsed time if actual elapsed time is < 0" do
       expected = Time.now
       allow(Time).to receive(:now).and_return(expected, expected - 1)
-      @resource.run_action(:purr)
-      expect(@resource.elapsed_time).to eq(0)
+      resource.run_action(:purr)
+      expect(resource.elapsed_time).to eq(0)
     end
 
     describe "guard_interpreter attribute" do
-      let(:resource) { @resource }
-
       it "should be set to :default by default" do
         expect(resource.guard_interpreter).to eq(:default)
       end
@@ -578,7 +698,7 @@ describe Chef::Resource do
       end
 
       it "should raise Chef::Exceptions::ValidationFailed on an attempt to set the guard_interpreter attribute to something other than a Symbol" do
-        expect { resource.guard_interpreter('command_dot_com') }.to raise_error(Chef::Exceptions::ValidationFailed)
+        expect { resource.guard_interpreter("command_dot_com") }.to raise_error(Chef::Exceptions::ValidationFailed)
       end
 
       it "should not raise an exception when setting the guard interpreter attribute to a Symbol" do
@@ -590,106 +710,128 @@ describe Chef::Resource do
 
   describe "should_skip?" do
     before do
-      @resource = Chef::Resource::Cat.new("sugar", @run_context)
+      resource = Chef::Resource::Cat.new("sugar", run_context)
     end
 
     it "should return false by default" do
-      expect(@resource.should_skip?(:purr)).to be_falsey
+      expect(resource.should_skip?(:purr)).to be_falsey
     end
 
     it "should return false when only_if is met" do
-      @resource.only_if { true }
-      expect(@resource.should_skip?(:purr)).to be_falsey
+      resource.only_if { true }
+      expect(resource.should_skip?(:purr)).to be_falsey
     end
 
     it "should return true when only_if is not met" do
-      @resource.only_if { false }
-      expect(@resource.should_skip?(:purr)).to be_truthy
+      resource.only_if { false }
+      expect(resource.should_skip?(:purr)).to be_truthy
     end
 
     it "should return true when not_if is met" do
-      @resource.not_if { true }
-      expect(@resource.should_skip?(:purr)).to be_truthy
+      resource.not_if { true }
+      expect(resource.should_skip?(:purr)).to be_truthy
     end
 
     it "should return false when not_if is not met" do
-      @resource.not_if { false }
-      expect(@resource.should_skip?(:purr)).to be_falsey
+      resource.not_if { false }
+      expect(resource.should_skip?(:purr)).to be_falsey
     end
 
     it "should return true when only_if is met but also not_if is met" do
-      @resource.only_if { true }
-      @resource.not_if { true }
-      expect(@resource.should_skip?(:purr)).to be_truthy
+      resource.only_if { true }
+      resource.not_if { true }
+      expect(resource.should_skip?(:purr)).to be_truthy
+    end
+
+    it "should return false when only_if is met and also not_if is not met" do
+      resource.only_if { true }
+      resource.not_if { false }
+      expect(resource.should_skip?(:purr)).to be_falsey
     end
 
     it "should return true when one of multiple only_if's is not met" do
-      @resource.only_if { true }
-      @resource.only_if { false }
-      @resource.only_if { true }
-      expect(@resource.should_skip?(:purr)).to be_truthy
+      resource.only_if { true }
+      resource.only_if { false }
+      resource.only_if { true }
+      expect(resource.should_skip?(:purr)).to be_truthy
     end
 
     it "should return true when one of multiple not_if's is met" do
-      @resource.not_if { false }
-      @resource.not_if { true }
-      @resource.not_if { false }
-      expect(@resource.should_skip?(:purr)).to be_truthy
+      resource.not_if { false }
+      resource.not_if { true }
+      resource.not_if { false }
+      expect(resource.should_skip?(:purr)).to be_truthy
+    end
+
+    it "should return false when all of multiple only_if's are met" do
+      resource.only_if { true }
+      resource.only_if { true }
+      resource.only_if { true }
+      expect(resource.should_skip?(:purr)).to be_falsey
+    end
+
+    it "should return false when all of multiple not_if's are not met" do
+      resource.not_if { false }
+      resource.not_if { false }
+      resource.not_if { false }
+      expect(resource.should_skip?(:purr)).to be_falsey
     end
 
     it "should return true when action is :nothing" do
-      expect(@resource.should_skip?(:nothing)).to be_truthy
+      expect(resource.should_skip?(:nothing)).to be_truthy
     end
 
     it "should return true when action is :nothing ignoring only_if/not_if conditionals" do
-      @resource.only_if { true }
-      @resource.not_if { false }
-      expect(@resource.should_skip?(:nothing)).to be_truthy
+      resource.only_if { true }
+      resource.not_if { false }
+      expect(resource.should_skip?(:nothing)).to be_truthy
     end
 
     it "should print \"skipped due to action :nothing\" message for doc formatter when action is :nothing" do
       fdoc = Chef::Formatters.new(:doc, STDOUT, STDERR)
-      allow(@run_context).to receive(:events).and_return(fdoc)
+      allow(run_context).to receive(:events).and_return(fdoc)
       expect(fdoc).to receive(:puts).with(" (skipped due to action :nothing)", anything())
-      @resource.should_skip?(:nothing)
+      resource.should_skip?(:nothing)
     end
 
   end
 
   describe "when resource action is :nothing" do
+    let(:resource1) {
+      resource1 = Chef::Resource::Cat.new("sugar", run_context)
+      resource1.action = :nothing
+      resource1
+    }
     before do
-      @resource1 = Chef::Resource::Cat.new("sugar", @run_context)
-      @resource1.action = :nothing
-
-      @node.automatic_attrs[:platform] = "fubuntu"
-      @node.automatic_attrs[:platform_version] = '10.04'
+      node.automatic_attrs[:platform] = "fubuntu"
+      node.automatic_attrs[:platform_version] = "10.04"
     end
 
     it "should not run only_if/not_if conditionals (CHEF-972)" do
       snitch_var1 = 0
-      @resource1.only_if { snitch_var1 = 1 }
-      @resource1.not_if { snitch_var1 = 2 }
-      @resource1.run_action(:nothing)
+      resource1.only_if { snitch_var1 = 1 }
+      resource1.not_if { snitch_var1 = 2 }
+      resource1.run_action(:nothing)
       expect(snitch_var1).to eq(0)
     end
 
     it "should run only_if/not_if conditionals when notified to run another action (CHEF-972)" do
       snitch_var1 = snitch_var2 = 0
-      @runner = Chef::Runner.new(@run_context)
+      runner = Chef::Runner.new(run_context)
       Chef::Platform.set(
         :resource => :cat,
-        :provider => Chef::Provider::SnakeOil
+        :provider => Chef::Provider::SnakeOil,
       )
 
-      @resource1.only_if { snitch_var1 = 1 }
-      @resource1.not_if { snitch_var2 = 2 }
-      @resource2 = Chef::Resource::Cat.new("coffee", @run_context)
-      @resource2.notifies :purr, @resource1
-      @resource2.action = :purr
+      resource1.only_if { snitch_var1 = 1 }
+      resource1.not_if { snitch_var2 = 2 }
+      resource2 = Chef::Resource::Cat.new("coffee", run_context)
+      resource2.notifies :purr, resource1
+      resource2.action = :purr
 
-      @run_context.resource_collection << @resource1
-      @run_context.resource_collection << @resource2
-      @runner.converge
+      run_context.resource_collection << resource1
+      run_context.resource_collection << resource2
+      runner.converge
 
       expect(snitch_var1).to eq(1)
       expect(snitch_var2).to eq(2)
@@ -708,58 +850,73 @@ describe Chef::Resource do
       Chef::Resource.send(:remove_const, :Klz)
     end
 
-    it 'adds mappings for a single platform' do
-      expect(Chef::Resource::Klz.node_map).to receive(:set).with(
-        :dinobot, true, { platform: ['autobots'] }
+    it "adds mappings for a single platform" do
+      expect(Chef.resource_handler_map).to receive(:set).with(
+        :dinobot, Chef::Resource::Klz, { platform: ["autobots"] }
       )
-      klz.provides :dinobot, platform: ['autobots']
+      klz.provides :dinobot, platform: ["autobots"]
     end
 
-    it 'adds mappings for multiple platforms' do
-      expect(Chef::Resource::Klz.node_map).to receive(:set).with(
-        :energy, true, { platform: ['autobots', 'decepticons']}
+    it "adds mappings for multiple platforms" do
+      expect(Chef.resource_handler_map).to receive(:set).with(
+        :energy, Chef::Resource::Klz, { platform: ["autobots", "decepticons"] }
       )
-      klz.provides :energy, platform: ['autobots', 'decepticons']
+      klz.provides :energy, platform: ["autobots", "decepticons"]
     end
 
-    it 'adds mappings for all platforms' do
-      expect(Chef::Resource::Klz.node_map).to receive(:set).with(
-        :tape_deck, true, {}
+    it "adds mappings for all platforms" do
+      expect(Chef.resource_handler_map).to receive(:set).with(
+        :tape_deck, Chef::Resource::Klz, {}
       )
       klz.provides :tape_deck
     end
 
   end
 
-  describe "lookups from the platform map" do
-    let(:klz1) { Class.new(Chef::Resource) }
-    let(:klz2) { Class.new(Chef::Resource) }
+  describe "resource_for_node" do
+    describe "lookups from the platform map" do
+      let(:klz1) { Class.new(Chef::Resource) }
+
+      before(:each) do
+        Chef::Resource::Klz1 = klz1
+        node = Chef::Node.new
+        node.name("bumblebee")
+        node.automatic[:platform] = "autobots"
+        node.automatic[:platform_version] = "6.1"
+        Object.const_set("Soundwave", klz1)
+        klz1.provides :soundwave
+      end
 
-    before(:each) do
-      Chef::Resource::Klz1 = klz1
-      Chef::Resource::Klz2 = klz2
-      @node = Chef::Node.new
-      @node.name("bumblebee")
-      @node.automatic[:platform] = "autobots"
-      @node.automatic[:platform_version] = "6.1"
-      Object.const_set('Soundwave', klz1)
-      klz2.provides :dinobot, :on_platforms => ['autobots']
-      Object.const_set('Grimlock', klz2)
-    end
+      after(:each) do
+        Object.send(:remove_const, :Soundwave)
+        Chef::Resource.send(:remove_const, :Klz1)
+      end
 
-    after(:each) do
-      Object.send(:remove_const, :Soundwave)
-      Object.send(:remove_const, :Grimlock)
-      Chef::Resource.send(:remove_const, :Klz1)
-      Chef::Resource.send(:remove_const, :Klz2)
+      it "returns a resource by short_name if nothing else matches" do
+        expect(Chef::Resource.resource_for_node(:soundwave, node)).to eql(klz1)
+      end
     end
 
-    describe "resource_for_node" do
-      it "returns a resource by short_name and node" do
-        expect(Chef::Resource.resource_for_node(:dinobot, @node)).to eql(Grimlock)
+    describe "lookups from the platform map" do
+      let(:klz2) { Class.new(Chef::Resource) }
+
+      before(:each) do
+        Chef::Resource::Klz2 = klz2
+        node.name("bumblebee")
+        node.automatic[:platform] = "autobots"
+        node.automatic[:platform_version] = "6.1"
+        klz2.provides :dinobot, :platform => ["autobots"]
+        Object.const_set("Grimlock", klz2)
+        klz2.provides :grimlock
       end
-      it "returns a resource by short_name if nothing else matches" do
-        expect(Chef::Resource.resource_for_node(:soundwave, @node)).to eql(Soundwave)
+
+      after(:each) do
+        Object.send(:remove_const, :Grimlock)
+        Chef::Resource.send(:remove_const, :Klz2)
+      end
+
+      it "returns a resource by short_name and node" do
+        expect(Chef::Resource.resource_for_node(:dinobot, node)).to eql(klz2)
       end
     end
 
@@ -770,69 +927,64 @@ describe Chef::Resource do
     describe "with a string resource spec" do
 
       it "creates a delayed notification when timing is not specified" do
-        @resource.notifies(:run, "execute[foo]")
-        expect(@run_context.delayed_notification_collection.size).to eq(1)
+        resource.notifies(:run, "execute[foo]")
+        expect(run_context.delayed_notification_collection.size).to eq(1)
       end
 
       it "creates a delayed notification when :delayed is not specified" do
-        @resource.notifies(:run, "execute[foo]", :delayed)
-        expect(@run_context.delayed_notification_collection.size).to eq(1)
+        resource.notifies(:run, "execute[foo]", :delayed)
+        expect(run_context.delayed_notification_collection.size).to eq(1)
       end
 
       it "creates an immediate notification when :immediate is specified" do
-        @resource.notifies(:run, "execute[foo]", :immediate)
-        expect(@run_context.immediate_notification_collection.size).to eq(1)
+        resource.notifies(:run, "execute[foo]", :immediate)
+        expect(run_context.immediate_notification_collection.size).to eq(1)
       end
 
       it "creates an immediate notification when :immediately is specified" do
-        @resource.notifies(:run, "execute[foo]", :immediately)
-        expect(@run_context.immediate_notification_collection.size).to eq(1)
+        resource.notifies(:run, "execute[foo]", :immediately)
+        expect(run_context.immediate_notification_collection.size).to eq(1)
       end
 
       describe "with a syntax error in the resource spec" do
 
         it "raises an exception immmediately" do
           expect do
-            @resource.notifies(:run, "typo[missing-closing-bracket")
+            resource.notifies(:run, "typo[missing-closing-bracket")
           end.to raise_error(Chef::Exceptions::InvalidResourceSpecification)
         end
       end
     end
 
     describe "with a resource reference" do
-      before do
-        @notified_resource = Chef::Resource.new("punk", @run_context)
-      end
+      let(:notified_resource) { Chef::Resource.new("punk", run_context) }
 
       it "creates a delayed notification when timing is not specified" do
-        @resource.notifies(:run, @notified_resource)
-        expect(@run_context.delayed_notification_collection.size).to eq(1)
+        resource.notifies(:run, notified_resource)
+        expect(run_context.delayed_notification_collection.size).to eq(1)
       end
 
       it "creates a delayed notification when :delayed is not specified" do
-        @resource.notifies(:run, @notified_resource, :delayed)
-        expect(@run_context.delayed_notification_collection.size).to eq(1)
+        resource.notifies(:run, notified_resource, :delayed)
+        expect(run_context.delayed_notification_collection.size).to eq(1)
       end
 
       it "creates an immediate notification when :immediate is specified" do
-        @resource.notifies(:run, @notified_resource, :immediate)
-        expect(@run_context.immediate_notification_collection.size).to eq(1)
+        resource.notifies(:run, notified_resource, :immediate)
+        expect(run_context.immediate_notification_collection.size).to eq(1)
       end
 
       it "creates an immediate notification when :immediately is specified" do
-        @resource.notifies(:run, @notified_resource, :immediately)
-        expect(@run_context.immediate_notification_collection.size).to eq(1)
+        resource.notifies(:run, notified_resource, :immediately)
+        expect(run_context.immediate_notification_collection.size).to eq(1)
       end
     end
 
   end
 
   describe "resource sensitive attribute" do
-
-    before(:each) do
-       @resource_file = Chef::Resource::File.new("/nonexistent/CHEF-5098/file", @run_context)
-       @action = :create
-    end
+    let(:resource_file) { Chef::Resource::File.new("/nonexistent/CHEF-5098/file", run_context) }
+    let(:action) { :create }
 
     def compiled_resource_data(resource, action, err)
       error_inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(resource, action, err)
@@ -843,21 +995,107 @@ describe Chef::Resource do
     end
 
     it "set to false by default" do
-      expect(@resource.sensitive).to be_falsey
+      expect(resource.sensitive).to be_falsey
     end
 
     it "when set to false should show compiled resource for failed resource" do
-      expect { @resource_file.run_action(@action) }.to raise_error { |err|
-            expect(compiled_resource_data(@resource_file, @action, err)).to match 'path "/nonexistent/CHEF-5098/file"'
-          }
+      expect { resource_file.run_action(action) }.to raise_error { |err|
+        expect(compiled_resource_data(resource_file, action, err)).to match 'path "/nonexistent/CHEF-5098/file"'
+      }
     end
 
     it "when set to true should show compiled resource for failed resource" do
-      @resource_file.sensitive true
-      expect { @resource_file.run_action(@action) }.to raise_error { |err|
-            expect(compiled_resource_data(@resource_file, @action, err)).to eql("suppressed sensitive resource output")
-          }
+      resource_file.sensitive true
+      expect { resource_file.run_action(action) }.to raise_error { |err|
+        expect(compiled_resource_data(resource_file, action, err)).to eql("suppressed sensitive resource output")
+      }
     end
 
   end
+
+  describe "#action" do
+    let(:resource_class) do
+      Class.new(described_class) do
+        allowed_actions(%i{one two})
+      end
+    end
+    let(:resource) { resource_class.new("test", nil) }
+    subject { resource.action }
+
+    context "with a no action" do
+      it { is_expected.to eq [:nothing] }
+    end
+
+    context "with a default action" do
+      let(:resource_class) do
+        Class.new(described_class) do
+          default_action(:one)
+        end
+      end
+      it { is_expected.to eq [:one] }
+    end
+
+    context "with a symbol action" do
+      before { resource.action(:one) }
+      it { is_expected.to eq [:one] }
+    end
+
+    context "with a string action" do
+      before { resource.action("two") }
+      it { is_expected.to eq [:two] }
+    end
+
+    context "with an array action" do
+      before { resource.action([:two, :one]) }
+      it { is_expected.to eq [:two, :one] }
+    end
+
+    context "with an assignment" do
+      before { resource.action = :one }
+      it { is_expected.to eq [:one] }
+    end
+
+    context "with an array assignment" do
+      before { resource.action = [:two, :one] }
+      it { is_expected.to eq [:two, :one] }
+    end
+
+    context "with an invalid action" do
+      it { expect { resource.action(:three) }.to raise_error Chef::Exceptions::ValidationFailed }
+    end
+
+    context "with an invalid assignment action" do
+      it { expect { resource.action = :three }.to raise_error Chef::Exceptions::ValidationFailed }
+    end
+  end
+
+  describe ".default_action" do
+    let(:default_action) {}
+    let(:resource_class) do
+      actions = default_action
+      Class.new(described_class) do
+        default_action(actions) if actions
+      end
+    end
+    subject { resource_class.default_action }
+
+    context "with no default actions" do
+      it { is_expected.to eq [:nothing] }
+    end
+
+    context "with a symbol default action" do
+      let(:default_action) { :one }
+      it { is_expected.to eq [:one] }
+    end
+
+    context "with a string default action" do
+      let(:default_action) { "one" }
+      it { is_expected.to eq [:one] }
+    end
+
+    context "with an array default action" do
+      let(:default_action) { [:two, :one] }
+      it { is_expected.to eq [:two, :one] }
+    end
+  end
 end
diff --git a/spec/unit/rest/auth_credentials_spec.rb b/spec/unit/rest/auth_credentials_spec.rb
index 3465156..164c0eb 100644
--- a/spec/unit/rest/auth_credentials_spec.rb
+++ b/spec/unit/rest/auth_credentials_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,44 +19,13 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'uri'
-require 'net/https'
-
-KEY_DOT_PEM=<<-END_RSA_KEY
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh
-8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy
-YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei
-PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A
-O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x
-PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD
-2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk
-WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP
-g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa
-Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ
-I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/
-/RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR
-xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO
-ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy
-bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A
-s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4
-DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz
-dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv
-GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq
-qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8
-OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R
-b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I
-YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12
-2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo
-Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ==
------END RSA PRIVATE KEY-----
-  END_RSA_KEY
-
+require "spec_helper"
+require "uri"
+require "net/https"
 
 describe Chef::REST::AuthCredentials do
   before do
-    @key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key.pem'
+    @key_file_fixture = CHEF_SPEC_DATA + "/ssl/private_key.pem"
     @key = OpenSSL::PKey::RSA.new(IO.read(@key_file_fixture).strip)
     @auth_credentials = Chef::REST::AuthCredentials.new("client-name", @key)
   end
@@ -67,52 +36,51 @@ describe Chef::REST::AuthCredentials do
 
   it "loads the private key when initialized with the path to the key" do
     expect(@auth_credentials.key).to respond_to(:private_encrypt)
-    expect(@auth_credentials.key.to_s).to eq(KEY_DOT_PEM)
+    expect(@auth_credentials.key).to eq(@key)
   end
 
   describe "when loading the private key" do
     it "strips extra whitespace before checking the key" do
-      key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key_with_whitespace.pem'
-      expect {Chef::REST::AuthCredentials.new("client-name", @key_file_fixture)}.not_to raise_error
+      key_file_fixture = CHEF_SPEC_DATA + "/ssl/private_key_with_whitespace.pem"
+      expect { Chef::REST::AuthCredentials.new("client-name", @key_file_fixture) }.not_to raise_error
     end
   end
 
   describe "generating signature headers for a request" do
     before do
       @request_time = Time.at(1270920860)
-      @request_params = {:http_method => :POST, :path => "/clients", :body => '{"some":"json"}', :host => "localhost"}
+      @request_params = { :http_method => :POST, :path => "/clients", :body => '{"some":"json"}', :host => "localhost" }
+      allow(Chef::Config).to(
+        receive(:[]).with(:authentication_protocol_version).and_return(protocol_version))
     end
 
-    it "generates signature headers for the request" do
-      allow(Time).to receive(:now).and_return(@request_time)
-      actual = @auth_credentials.signature_headers(@request_params)
-      expect(actual["HOST"]).to                    eq("localhost")
-      expect(actual["X-OPS-AUTHORIZATION-1"]).to eq("kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/")
-      expect(actual["X-OPS-AUTHORIZATION-2"]).to eq("Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS")
-      expect(actual["X-OPS-AUTHORIZATION-3"]).to eq("yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO")
-      expect(actual["X-OPS-AUTHORIZATION-4"]).to eq("r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ")
-      expect(actual["X-OPS-AUTHORIZATION-5"]).to eq("M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k")
-      expect(actual["X-OPS-AUTHORIZATION-6"]).to eq("qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==")
-      expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
-      expect(actual["X-OPS-SIGN"]).to         match(%r{(version=1\.0)|(algorithm=sha1;version=1.0;)})
-      expect(actual["X-OPS-TIMESTAMP"]).to    eq("2010-04-10T17:34:20Z")
-      expect(actual["X-OPS-USERID"]).to       eq("client-name")
-
-    end
+    context "when configured for version 1.0 of the authn protocol" do
+      let(:protocol_version) { "1.0" }
 
-    describe "when configured for version 1.1 of the authn protocol" do
-      before do
-        Chef::Config[:authentication_protocol_version] = "1.1"
+      it "generates signature headers for the request" do
+        allow(Time).to receive(:now).and_return(@request_time)
+        actual = @auth_credentials.signature_headers(@request_params)
+        expect(actual["HOST"]).to eq("localhost")
+        expect(actual["X-OPS-AUTHORIZATION-1"]).to eq("kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/")
+        expect(actual["X-OPS-AUTHORIZATION-2"]).to eq("Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS")
+        expect(actual["X-OPS-AUTHORIZATION-3"]).to eq("yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO")
+        expect(actual["X-OPS-AUTHORIZATION-4"]).to eq("r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ")
+        expect(actual["X-OPS-AUTHORIZATION-5"]).to eq("M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k")
+        expect(actual["X-OPS-AUTHORIZATION-6"]).to eq("qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==")
+        expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
+        expect(actual["X-OPS-SIGN"]).to         match(%r{(version=1\.0)|(algorithm=sha1;version=1.0;)})
+        expect(actual["X-OPS-TIMESTAMP"]).to    eq("2010-04-10T17:34:20Z")
+        expect(actual["X-OPS-USERID"]).to       eq("client-name")
       end
+    end
 
-      after do
-        Chef::Config[:authentication_protocol_version] = "1.0"
-      end
+    context "when configured for version 1.1 of the authn protocol" do
+      let(:protocol_version) { "1.1" }
 
       it "generates the correct signature for version 1.1" do
         allow(Time).to receive(:now).and_return(@request_time)
         actual = @auth_credentials.signature_headers(@request_params)
-        expect(actual["HOST"]).to                    eq("localhost")
+        expect(actual["HOST"]).to eq("localhost")
         expect(actual["X-OPS-CONTENT-HASH"]).to eq("1tuzs5XKztM1ANrkGNPah6rW9GY=")
         expect(actual["X-OPS-SIGN"]).to         eq("algorithm=sha1;version=1.1;")
         expect(actual["X-OPS-TIMESTAMP"]).to    eq("2010-04-10T17:34:20Z")
@@ -126,17 +94,17 @@ describe Chef::REST::AuthCredentials do
 end
 
 describe Chef::REST::RESTRequest do
-  def new_request(method=nil)
+  def new_request(method = nil)
     method ||= :POST
     Chef::REST::RESTRequest.new(method, @url, @req_body, @headers)
   end
 
   before do
-    @auth_credentials = Chef::REST::AuthCredentials.new("client-name", CHEF_SPEC_DATA + '/ssl/private_key.pem')
+    @auth_credentials = Chef::REST::AuthCredentials.new("client-name", CHEF_SPEC_DATA + "/ssl/private_key.pem")
     @url = URI.parse("http://chef.example.com:4000/?q=chef_is_awesome")
     @req_body = '{"json_data":"as_a_string"}'
-    @headers = { "Content-type" =>"application/json",
-                 "Accept"=>"application/json",
+    @headers = { "Content-type" => "application/json",
+                 "Accept" => "application/json",
                  "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
                  "Host" => "chef.example.com:4000" }
     @request = Chef::REST::RESTRequest.new(:POST, @url, @req_body, @headers)
diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb
index 85c9e3d..9e99a3e 100644
--- a/spec/unit/rest_spec.rb
+++ b/spec/unit/rest_spec.rb
@@ -1,9 +1,9 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Christopher Brown (<cb at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Christopher Brown (<cb at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'uri'
-require 'net/https'
-require 'stringio'
+require "spec_helper"
+require "uri"
+require "net/https"
+require "stringio"
 
-SIGNING_KEY_DOT_PEM="-----BEGIN RSA PRIVATE KEY-----
+SIGNING_KEY_DOT_PEM = "-----BEGIN RSA PRIVATE KEY-----
 MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh
 8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy
 YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei
@@ -59,7 +59,7 @@ describe Chef::REST do
 
   let(:log_stringio) { StringIO.new }
 
-  let(:request_id) {"1234"}
+  let(:request_id) { "1234" }
 
   let(:rest) do
     allow(Chef::REST::CookieJar).to receive(:instance).and_return({})
@@ -69,11 +69,12 @@ describe Chef::REST do
     rest
   end
 
-  let(:standard_read_headers) {{"Accept"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id}}
-  let(:standard_write_headers) {{"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID"=>request_id}}
+  let(:standard_read_headers) { { "Accept" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID" => request_id, "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION } }
+  let(:standard_write_headers) { { "Accept" => "application/json", "Content-Type" => "application/json", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "X-REMOTE-REQUEST-ID" => request_id, "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION } }
 
   before(:each) do
     Chef::Log.init(log_stringio)
+    Chef::Config[:treat_deprecation_warnings_as_errors] = false
   end
 
   it "should have content length validation middleware after compressor middleware" do
@@ -92,7 +93,13 @@ describe Chef::REST do
     Chef::REST.new(base_url, nil, nil, options)
   end
 
-  context 'when created with a chef zero URL' do
+  it "emits a deprecation warning" do
+    Chef::Config[:treat_deprecation_warnings_as_errors] = true
+    expect { Chef::REST.new(base_url) }.to raise_error Chef::Exceptions::DeprecatedFeatureError,
+      /Chef::REST is deprecated. Please use Chef::ServerAPI, or investigate Ridley or ChefAPI./
+  end
+
+  context "when created with a chef zero URL" do
 
     let(:url) { "chefzero://localhost:1" }
 
@@ -113,41 +120,41 @@ describe Chef::REST do
     it "makes a :GET request with the composed url object" do
       expect(rest).to receive(:send_http_request).
         with(:GET, monkey_uri, standard_read_headers, false).
-        and_return([1,2,3])
-      expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.get_rest("monkey")
     end
 
     it "makes a :GET reqest for a streaming download with the composed url" do
-      expect(rest).to receive(:streaming_request).with('monkey', {})
+      expect(rest).to receive(:streaming_request).with("monkey", {})
       rest.get_rest("monkey", true)
     end
 
     it "makes a :DELETE request with the composed url object" do
       expect(rest).to receive(:send_http_request).
         with(:DELETE, monkey_uri, standard_read_headers, false).
-        and_return([1,2,3])
-      expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.delete_rest("monkey")
     end
 
     it "makes a :POST request with the composed url object and data" do
       expect(rest).to receive(:send_http_request).
         with(:POST, monkey_uri, standard_write_headers, "\"data\"").
-        and_return([1,2,3])
-      expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.post_rest("monkey", "data")
     end
 
     it "makes a :PUT request with the composed url object and data" do
       expect(rest).to receive(:send_http_request).
         with(:PUT, monkey_uri, standard_write_headers, "\"data\"").
-        and_return([1,2,3])
-      expect(rest).to receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive(:apply_response_middleware).with(1, 2, 3).and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.put_rest("monkey", "data")
     end
   end
@@ -162,38 +169,37 @@ describe Chef::REST do
       Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem"
     end
 
-    it 'responds to raw_http_request as a public method' do
+    it "responds to raw_http_request as a public method" do
       expect(rest.public_methods.map(&:to_s)).to include("raw_http_request")
     end
 
-    it 'calls the authn middleware' do
+    it "calls the authn middleware" do
       data = "\"secure data\""
 
-      auth_headers = standard_write_headers.merge({"auth_done"=>"yep"})
+      auth_headers = standard_write_headers.merge({ "auth_done" => "yep" })
 
       expect(rest.authenticator).to receive(:handle_request).
         with(:POST, monkey_uri, standard_write_headers, data).
         and_return([:POST, monkey_uri, auth_headers, data])
       expect(rest).to receive(:send_http_request).
         with(:POST, monkey_uri, auth_headers, data).
-        and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
     end
 
-    it 'sets correct authn headers' do
+    it "sets correct authn headers" do
       data = "\"secure data\""
       method, uri, auth_headers, d = rest.authenticator.handle_request(:POST, monkey_uri, standard_write_headers, data)
 
       expect(rest).to receive(:send_http_request).
         with(:POST, monkey_uri, auth_headers, data).
-        and_return([1,2,3])
-      expect(rest).to receive('success_response?'.to_sym).with(1).and_return(true)
+        and_return([1, 2, 3])
+      expect(rest).to receive("success_response?".to_sym).with(1).and_return(true)
       rest.raw_http_request(:POST, monkey_uri, standard_write_headers, data)
     end
   end
 
-
   describe "when configured to authenticate to the Chef server" do
     let(:base_url) { URI.parse("http://chef.example.com:4000") }
 
@@ -227,12 +233,12 @@ describe Chef::REST do
     end
 
     it "raises PrivateKeyMissing when the key file doesn't exist" do
-      expect {Chef::REST.new(base_url, "client-name", "/dev/null/nothing_here")}.to raise_error(Chef::Exceptions::PrivateKeyMissing)
+      expect { Chef::REST.new(base_url, "client-name", "/dev/null/nothing_here") }.to raise_error(Chef::Exceptions::PrivateKeyMissing)
     end
 
     it "raises InvalidPrivateKey when the key file doesnt' look like a key" do
       invalid_key_file = CHEF_SPEC_DATA + "/bad-config.rb"
-      expect {Chef::REST.new(base_url, "client-name", invalid_key_file)}.to raise_error(Chef::Exceptions::InvalidPrivateKey)
+      expect { Chef::REST.new(base_url, "client-name", invalid_key_file) }.to raise_error(Chef::Exceptions::InvalidPrivateKey)
     end
 
     it "can take private key as a sting :raw_key in options during initializaton" do
@@ -240,7 +246,7 @@ describe Chef::REST do
     end
 
     it "raises InvalidPrivateKey when the key passed as string :raw_key in options doesnt' look like a key" do
-      expect {Chef::REST.new(base_url, "client-name", nil, :raw_key => "bad key string")}.to raise_error(Chef::Exceptions::InvalidPrivateKey)
+      expect { Chef::REST.new(base_url, "client-name", nil, :raw_key => "bad key string") }.to raise_error(Chef::Exceptions::InvalidPrivateKey)
     end
 
   end
@@ -277,19 +283,6 @@ describe Chef::REST do
       rest
     end
 
-    let(:base_headers) do
-      {
-        'Accept' => 'application/json',
-        'X-Chef-Version' => Chef::VERSION,
-        'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
-        'X-REMOTE-REQUEST-ID' => request_id
-      }
-    end
-
-    let (:req_with_body_headers) do
-      base_headers.merge("Content-Type" => "application/json", "Content-Length" => '13')
-    end
-
     before(:each) do
       Chef::Config[:ssl_client_cert] = nil
       Chef::Config[:ssl_client_key]  = nil
@@ -298,13 +291,14 @@ describe Chef::REST do
     describe "as JSON API requests" do
       let(:request_mock) { {} }
 
-      let(:base_headers) do  #FIXME: huh?
+      let(:base_headers) do #FIXME: huh?
         {
-          'Accept' => 'application/json',
-          'X-Chef-Version' => Chef::VERSION,
-          'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
-          'Host' => host_header,
-          'X-REMOTE-REQUEST-ID' => request_id
+          "Accept" => "application/json",
+          "X-Chef-Version" => Chef::VERSION,
+          "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+          "Host" => host_header,
+          "X-REMOTE-REQUEST-ID" => request_id,
+          "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
         }
       end
 
@@ -326,7 +320,7 @@ describe Chef::REST do
         # XXX: must reset to default b/c knife changes the UA
         Chef::REST::RESTRequest.user_agent = Chef::REST::RESTRequest::DEFAULT_UA
         rest.request(:GET, url, {})
-        expect(request_mock['User-Agent']).to match(/^Chef Client\/#{Chef::VERSION}/)
+        expect(request_mock["User-Agent"]).to match(/^Chef Client\/#{Chef::VERSION}/)
       end
 
       # CHEF-3140
@@ -352,8 +346,8 @@ describe Chef::REST do
       context "when configured with custom http headers" do
         let(:custom_headers) do
           {
-            'X-Custom-ChefSecret' => 'sharpknives',
-            'X-Custom-RequestPriority' => 'extremely low'
+            "X-Custom-ChefSecret" => "sharpknives",
+            "X-Custom-RequestPriority" => "extremely low",
           }
         end
 
@@ -383,7 +377,7 @@ describe Chef::REST do
         end
 
         it "should set the cookie for this request if one exists for the given host:port" do
-          expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers.merge('Cookie' => "cookie monster")).and_return(request_mock)
+          expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", base_headers.merge("Cookie" => "cookie monster")).and_return(request_mock)
           rest.request(:GET, url, {})
         end
       end
@@ -395,18 +389,18 @@ describe Chef::REST do
 
       it "should build a new HTTP POST request" do
         request = Net::HTTP::Post.new(url.path)
-        expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
+        expected_headers = base_headers.merge("Content-Type" => "application/json", "Content-Length" => "13")
 
         expect(Net::HTTP::Post).to receive(:new).with("/?foo=bar", expected_headers).and_return(request)
-        rest.request(:POST, url, {}, {:one=>:two})
+        rest.request(:POST, url, {}, { :one => :two })
         expect(request.body).to eq('{"one":"two"}')
       end
 
       it "should build a new HTTP PUT request" do
         request = Net::HTTP::Put.new(url.path)
-        expected_headers = base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13')
-        expect(Net::HTTP::Put).to receive(:new).with("/?foo=bar",expected_headers).and_return(request)
-        rest.request(:PUT, url, {}, {:one=>:two})
+        expected_headers = base_headers.merge("Content-Type" => "application/json", "Content-Length" => "13")
+        expect(Net::HTTP::Put).to receive(:new).with("/?foo=bar", expected_headers).and_return(request)
+        rest.request(:PUT, url, {}, { :one => :two })
         expect(request.body).to eq('{"one":"two"}')
       end
 
@@ -431,18 +425,18 @@ describe Chef::REST do
       context "when JSON is returned" do
         let(:body) { '{"ohai2u":"json_api"}' }
         it "should inflate the body as to an object" do
-          http_response.add_field('content-type', "application/json")
-          expect(rest.request(:GET, url, {})).to eq({"ohai2u"=>"json_api"})
+          http_response.add_field("content-type", "application/json")
+          expect(rest.request(:GET, url, {})).to eq({ "ohai2u" => "json_api" })
         end
 
         it "should fail if the response is truncated" do
-          http_response.add_field('content-type', "application/json")
+          http_response.add_field("content-type", "application/json")
           http_response["Content-Length"] = (body.bytesize + 99).to_s
           expect { rest.request(:GET, url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
         end
       end
 
-      %w[ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice ].each do |resp_name|
+      %w{ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice }.each do |resp_name|
         describe "when encountering a #{resp_name} redirect" do
           let(:http_response) do
             resp_cls  = Net.const_get(resp_name)
@@ -497,8 +491,8 @@ describe Chef::REST do
           it "should show the JSON error message" do
             allow(rest).to receive(:sleep)
 
-            expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
-            expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
+            expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
+            expect(log_stringio.string).to match(Regexp.escape("INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four"))
           end
         end
 
@@ -522,13 +516,13 @@ describe Chef::REST do
           end
 
           it "decompresses the JSON error message" do
-            expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
-            expect(log_stringio.string).to match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four'))
+            expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
+            expect(log_stringio.string).to match(Regexp.escape("INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four"))
           end
 
           it "fails when the compressed body is truncated" do
             http_response["Content-Length"] = (body.bytesize + 99).to_s
-            expect {rest.request(:GET, url)}.to raise_error(Chef::Exceptions::ContentLengthMismatch)
+            expect { rest.request(:GET, url) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
           end
         end
 
@@ -542,13 +536,13 @@ describe Chef::REST do
 
           it "retries then throws an exception" do
             allow(rest).to receive(:sleep)
-            expect {rest.request(:GET, url)}.to raise_error(Net::HTTPFatalError)
+            expect { rest.request(:GET, url) }.to raise_error(Net::HTTPFatalError)
             count = Chef::Config[:http_retry_count]
             expect(log_stringio.string).to match(Regexp.escape("ERROR: Server returned error 500 for #{url}, retrying #{count}/#{count}"))
           end
         end
       end
-    end
+    end # as JSON API requests
 
     context "when streaming downloads to a tempfile" do
       let!(:tempfile) {  Tempfile.open("chef-rspec-rest_spec-line-@{__LINE__}--") }
@@ -556,7 +550,7 @@ describe Chef::REST do
       let(:request_mock) { {} }
 
       let(:http_response) do
-        http_response = Net::HTTPSuccess.new("1.1",'200', "it-works")
+        http_response = Net::HTTPSuccess.new("1.1", "200", "it-works")
 
         allow(http_response).to receive(:read_body)
         expect(http_response).not_to receive(:body)
@@ -582,22 +576,24 @@ describe Chef::REST do
       end
 
       it " build a new HTTP GET request without the application/json accept header" do
-        expected_headers = {'Accept' => "*/*",
-                            'X-Chef-Version' => Chef::VERSION,
-                            'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
-                            'Host' => host_header,
-                            'X-REMOTE-REQUEST-ID'=> request_id
+        expected_headers = { "Accept" => "*/*",
+                             "X-Chef-Version" => Chef::VERSION,
+                             "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+                             "Host" => host_header,
+                             "X-REMOTE-REQUEST-ID" => request_id,
+                             "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
                             }
         expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
         rest.streaming_request(url, {})
       end
 
       it "build a new HTTP GET request with the X-Remote-Request-Id header" do
-        expected_headers = {'Accept' => "*/*",
-                            'X-Chef-Version' => Chef::VERSION,
-                            'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
-                            'Host' => host_header,
-                            'X-REMOTE-REQUEST-ID'=> request_id
+        expected_headers = { "Accept" => "*/*",
+                             "X-Chef-Version" => Chef::VERSION,
+                             "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE,
+                             "Host" => host_header,
+                             "X-REMOTE-REQUEST-ID" => request_id,
+                             "X-Ops-Server-API-Version" => Chef::HTTP::Authenticator::DEFAULT_SERVER_API_VERSION,
                             }
         expect(Net::HTTP::Get).to receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock)
         rest.streaming_request(url, {})
@@ -632,13 +628,13 @@ describe Chef::REST do
       end
 
       it "does not raise a divide by zero exception if the content's actual size is 0" do
-        http_response['Content-Length'] = "5"
-        allow(http_response).to receive(:read_body).and_yield('')
+        http_response["Content-Length"] = "5"
+        allow(http_response).to receive(:read_body).and_yield("")
         expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
       end
 
       it "does not raise a divide by zero exception when the Content-Length is 0" do
-        http_response['Content-Length'] = "0"
+        http_response["Content-Length"] = "0"
         allow(http_response).to receive(:read_body).and_yield("ninja")
         expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch)
       end
@@ -664,7 +660,7 @@ describe Chef::REST do
         path = tempfile.path
         expect(path).not_to be_nil
         allow(tempfile).to receive(:write).and_raise(IOError)
-        rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
+        rest.fetch("cookbooks/a_cookbook") { |tmpfile| "shouldn't get here" }
         expect(File.exists?(path)).to be_falsey
       end
 
@@ -679,12 +675,12 @@ describe Chef::REST do
 
         expect(http_client).to receive(:request).and_yield(redirect).and_return(redirect)
         expect(http_client).to receive(:request).and_yield(http_response).and_return(http_response)
-        rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"}
+        rest.fetch("cookbooks/a_cookbook") { |tmpfile| "shouldn't get here" }
       end
 
       it "passes the original block to the redirected request" do
         http_redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today")
-        http_redirect.add_field("location","/that-thing-is-here-now")
+        http_redirect.add_field("location", "/that-thing-is-here-now")
         allow(http_redirect).to receive(:read_body)
 
         block_called = false
@@ -695,7 +691,7 @@ describe Chef::REST do
         expect(block_called).to be_truthy
       end
     end
-  end
+  end # when making REST requests
 
   context "when following redirects" do
     let(:rest) do
@@ -708,8 +704,8 @@ describe Chef::REST do
     end
 
     it "raises a RedirectLimitExceeded when redirected more than 10 times" do
-      redirected = lambda {rest.follow_redirect { redirected.call }}
-      expect {redirected.call}.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
+      redirected = lambda { rest.follow_redirect { redirected.call } }
+      expect { redirected.call }.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
     end
 
     it "does not count redirects from previous calls against the redirect limit" do
@@ -720,9 +716,9 @@ describe Chef::REST do
           redirected.call unless total_redirects >= 9
         end
       end
-      expect {redirected.call}.not_to raise_error
+      expect { redirected.call }.not_to raise_error
       total_redirects = 0
-      expect {redirected.call}.not_to raise_error
+      expect { redirected.call }.not_to raise_error
     end
 
     it "does not sign the redirected request when sign_on_redirect is false" do
@@ -746,11 +742,11 @@ describe Chef::REST do
           redirected.call unless total_redirects >= 9
         end
       end
-      expect {redirected.call}.not_to raise_error
+      expect { redirected.call }.not_to raise_error
 
       total_redirects = 0
       rest.redirect_limit = 3
-      expect {redirected.call}.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
+      expect { redirected.call }.to raise_error(Chef::Exceptions::RedirectLimitExceeded)
     end
 
   end
diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb
index 5421b5a..1ff76d7 100644
--- a/spec/unit/role_spec.rb
+++ b/spec/unit/role_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/role'
+require "spec_helper"
+require "chef/role"
 
 describe Chef::Role do
   before(:each) do
-    allow(Chef::Platform).to receive(:windows?) { false }
+    allow(ChefConfig).to receive(:windows?) { false }
     @role = Chef::Role.new
     @role.name("ops_master")
   end
@@ -44,7 +44,6 @@ describe Chef::Role do
       @role.run_list(%w{ nginx recipe[ree] role[base]})
     end
 
-
     it "returns the run list" do
       expect(@role.run_list).to eq(%w{ nginx recipe[ree] role[base]})
     end
@@ -79,12 +78,11 @@ describe Chef::Role do
 
       it "env_run_lists can only be set with _default run list in it" do
         long_exception_name = Chef::Exceptions::InvalidEnvironmentRunListSpecification
-        expect {@role.env_run_lists({})}.to raise_error(long_exception_name)
+        expect { @role.env_run_lists({}) }.to raise_error(long_exception_name)
       end
 
     end
 
-
     describe "using the old #recipes API" do
       it "should let you set the recipe array" do
         expect(@role.recipes([ "one", "two" ])).to eq([ "one", "two" ])
@@ -104,16 +102,14 @@ describe Chef::Role do
 
   end
 
-
-
   describe "default_attributes" do
     it "should let you set the default attributes hash explicitly" do
-      expect(@role.default_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+      expect(@role.default_attributes({ :one => "two" })).to eq({ :one => "two" })
     end
 
     it "should let you return the default attributes hash" do
-      @role.default_attributes({ :one => 'two' })
-      expect(@role.default_attributes).to eq({ :one => 'two' })
+      @role.default_attributes({ :one => "two" })
+      expect(@role.default_attributes).to eq({ :one => "two" })
     end
 
     it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -123,12 +119,12 @@ describe Chef::Role do
 
   describe "override_attributes" do
     it "should let you set the override attributes hash explicitly" do
-      expect(@role.override_attributes({ :one => 'two' })).to eq({ :one => 'two' })
+      expect(@role.override_attributes({ :one => "two" })).to eq({ :one => "two" })
     end
 
     it "should let you return the override attributes hash" do
-      @role.override_attributes({ :one => 'two' })
-      expect(@role.override_attributes).to eq({ :one => 'two' })
+      @role.override_attributes({ :one => "two" })
+      expect(@role.override_attributes).to eq({ :one => "two" })
     end
 
     it "should throw an ArgumentError if we aren't a kind of hash" do
@@ -138,18 +134,18 @@ describe Chef::Role do
 
   describe "update_from!" do
     before(:each) do
-      @role.name('mars_volta')
-      @role.description('Great band!')
-      @role.run_list('one', 'two', 'role[a]')
-      @role.default_attributes({ :el_groupo => 'nuevo' })
-      @role.override_attributes({ :deloused => 'in the comatorium' })
+      @role.name("mars_volta")
+      @role.description("Great band!")
+      @role.run_list("one", "two", "role[a]")
+      @role.default_attributes({ :el_groupo => "nuevo" })
+      @role.override_attributes({ :deloused => "in the comatorium" })
 
       @example = Chef::Role.new
-      @example.name('newname')
-      @example.description('Really Great band!')
-      @example.run_list('alpha', 'bravo', 'role[alpha]')
-      @example.default_attributes({ :el_groupo => 'nuevo dos' })
-      @example.override_attributes({ :deloused => 'in the comatorium XOXO' })
+      @example.name("newname")
+      @example.description("Really Great band!")
+      @example.run_list("alpha", "bravo", "role[alpha]")
+      @example.default_attributes({ :el_groupo => "nuevo dos" })
+      @example.override_attributes({ :deloused => "in the comatorium XOXO" })
     end
 
     it "should update all fields except for name" do
@@ -164,11 +160,11 @@ describe Chef::Role do
 
   describe "when serialized as JSON", :json => true do
     before(:each) do
-      @role.name('mars_volta')
-      @role.description('Great band!')
-      @role.run_list('one', 'two', 'role[a]')
-      @role.default_attributes({ :el_groupo => 'nuevo' })
-      @role.override_attributes({ :deloused => 'in the comatorium' })
+      @role.name("mars_volta")
+      @role.description("Great band!")
+      @role.run_list("one", "two", "role[a]")
+      @role.default_attributes({ :el_groupo => "nuevo" })
+      @role.override_attributes({ :deloused => "in the comatorium" })
       @serialized_role = Chef::JSONCompat.to_json(@role)
     end
 
@@ -200,14 +196,14 @@ describe Chef::Role do
 
     describe "and it has per-environment run lists" do
       before do
-        @role.env_run_lists("_default" => ['one', 'two', 'role[a]'], "production" => ['role[monitoring]', 'role[auditing]', 'role[apache]'], "dev" => ["role[nginx]"])
-        @serialized_role = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role), :create_additions => false)
+        @role.env_run_lists("_default" => ["one", "two", "role[a]"], "production" => ["role[monitoring]", "role[auditing]", "role[apache]"], "dev" => ["role[nginx]"])
+        @serialized_role = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@role), :create_additions => false)
       end
 
       it "includes the per-environment run lists" do
         #Activesupport messes with Chef json formatting
         #This test should pass with and without activesupport
-        expect(@serialized_role["env_run_lists"]["production"]).to eq(['role[monitoring]', 'role[auditing]', 'role[apache]'])
+        expect(@serialized_role["env_run_lists"]["production"]).to eq(["role[monitoring]", "role[auditing]", "role[apache]"])
         expect(@serialized_role["env_run_lists"]["dev"]).to eq(["role[nginx]"])
       end
 
@@ -217,19 +213,19 @@ describe Chef::Role do
 
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { @role }
     end
   end
 
   describe "when created from JSON", :json => true do
     before(:each) do
-      @role.name('mars_volta')
-      @role.description('Great band!')
-      @role.run_list('one', 'two', 'role[a]')
-      @role.default_attributes({ 'el_groupo' => 'nuevo' })
-      @role.override_attributes({ 'deloused' => 'in the comatorium' })
-      @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role))
+      @role.name("mars_volta")
+      @role.description("Great band!")
+      @role.run_list("one", "two", "role[a]")
+      @role.default_attributes({ "el_groupo" => "nuevo" })
+      @role.override_attributes({ "deloused" => "in the comatorium" })
+      @deserial = Chef::Role.from_hash(Chef::JSONCompat.parse(Chef::JSONCompat.to_json(@role)))
     end
 
     it "should deserialize to a Chef::Role object" do
@@ -249,20 +245,20 @@ describe Chef::Role do
     end
   end
 
-  ROLE_DSL=<<-EOR
+  ROLE_DSL = <<-EOR
 name "ceiling_cat"
 description "like Aliens, but furry"
 EOR
 
   describe "when loading from disk" do
     before do
-      default_cache_path = windows? ? 'C:\chef' : '/var/chef'
+      default_cache_path = windows? ? 'C:\chef' : "/var/chef"
       allow(Chef::Config).to receive(:cache_path).and_return(default_cache_path)
     end
 
     it "should return a Chef::Role object from JSON" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json"])
-      file_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json')
+      file_path = File.join(Chef::Config[:role_path], "memes/lolcat.json")
       expect(File).to receive(:exists?).with(file_path).exactly(1).times.and_return(true)
       expect(IO).to receive(:read).with(file_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
       expect(@role).to be_a_kind_of(Chef::Role)
@@ -271,7 +267,7 @@ EOR
 
     it "should return a Chef::Role object from a Ruby DSL" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.rb"])
-      rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb')
+      rb_path = File.join(Chef::Config[:role_path], "memes/lolcat.rb")
       expect(File).to receive(:exists?).with(rb_path).exactly(2).times.and_return(true)
       expect(File).to receive(:readable?).with(rb_path).exactly(1).times.and_return(true)
       expect(IO).to receive(:read).with(rb_path).and_return(ROLE_DSL)
@@ -281,8 +277,8 @@ EOR
 
     it "should prefer a Chef::Role Object from JSON over one from a Ruby DSL" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes", "#{Chef::Config[:role_path]}/memes/lolcat.json", "#{Chef::Config[:role_path]}/memes/lolcat.rb"])
-      js_path = File.join(Chef::Config[:role_path], 'memes/lolcat.json')
-      rb_path = File.join(Chef::Config[:role_path], 'memes/lolcat.rb')
+      js_path = File.join(Chef::Config[:role_path], "memes/lolcat.json")
+      rb_path = File.join(Chef::Config[:role_path], "memes/lolcat.rb")
       expect(File).to receive(:exists?).with(js_path).exactly(1).times.and_return(true)
       expect(File).not_to receive(:exists?).with(rb_path)
       expect(IO).to receive(:read).with(js_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
@@ -293,69 +289,69 @@ EOR
     it "should raise an exception if the file does not exist" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/meme.rb"])
       expect(File).not_to receive(:exists?)
-      expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::RoleNotFound)
+      expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::RoleNotFound)
     end
 
     it "should raise an exception if two files exist with the same name" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/lolcat.rb"])
       expect(File).not_to receive(:exists?)
-      expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::DuplicateRole)
+      expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::DuplicateRole)
     end
 
     it "should not raise an exception if two files exist with a similar name" do
       expect(Dir).to receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/super_lolcat.rb"])
       expect(File).to receive(:exists?).with("#{Chef::Config[:role_path]}/memes/lolcat.rb").and_return(true)
       allow_any_instance_of(Chef::Role).to receive(:from_file).with("#{Chef::Config[:role_path]}/memes/lolcat.rb")
-      expect{ @role.class.from_disk("lolcat") }.not_to raise_error
+      expect { @role.class.from_disk("lolcat") }.not_to raise_error
     end
   end
 
   describe "when loading from disk and role_path is an array" do
 
     before(:each) do
-      Chef::Config[:role_path] = ['/path1', '/path/path2']
+      Chef::Config[:role_path] = ["/path1", "/path/path2"]
     end
 
     it "should return a Chef::Role object from JSON" do
-      expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.json'])
-      expect(File).to receive(:exists?).with('/path1/lolcat.json').exactly(1).times.and_return(true)
-      expect(IO).to receive(:read).with('/path1/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
+      expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return(["/path1/lolcat.json"])
+      expect(File).to receive(:exists?).with("/path1/lolcat.json").exactly(1).times.and_return(true)
+      expect(IO).to receive(:read).with("/path1/lolcat.json").and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
       expect(@role).to be_a_kind_of(Chef::Role)
       @role.class.from_disk("lolcat")
     end
 
     it "should return a Chef::Role object from JSON when role is in the second path" do
-      expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
-      expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.json'])
-      expect(File).to receive(:exists?).with('/path/path2/lolcat.json').exactly(1).times.and_return(true)
-      expect(IO).to receive(:read).with('/path/path2/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
+      expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+      expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return(["/path/path2/lolcat.json"])
+      expect(File).to receive(:exists?).with("/path/path2/lolcat.json").exactly(1).times.and_return(true)
+      expect(IO).to receive(:read).with("/path/path2/lolcat.json").and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }')
       expect(@role).to be_a_kind_of(Chef::Role)
       @role.class.from_disk("lolcat")
     end
 
     it "should return a Chef::Role object from a Ruby DSL" do
-      expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.rb'])
-      expect(File).to receive(:exists?).with('/path1/lolcat.rb').exactly(2).times.and_return(true)
-      expect(File).to receive(:readable?).with('/path1/lolcat.rb').and_return(true)
-      expect(IO).to receive(:read).with('/path1/lolcat.rb').exactly(1).times.and_return(ROLE_DSL)
+      expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return(["/path1/lolcat.rb"])
+      expect(File).to receive(:exists?).with("/path1/lolcat.rb").exactly(2).times.and_return(true)
+      expect(File).to receive(:readable?).with("/path1/lolcat.rb").and_return(true)
+      expect(IO).to receive(:read).with("/path1/lolcat.rb").exactly(1).times.and_return(ROLE_DSL)
       expect(@role).to be_a_kind_of(Chef::Role)
       @role.class.from_disk("lolcat")
     end
 
     it "should return a Chef::Role object from a Ruby DSL when role is in the second path" do
-      expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
-      expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.rb'])
-      expect(File).to receive(:exists?).with('/path/path2/lolcat.rb').exactly(2).times.and_return(true)
-      expect(File).to receive(:readable?).with('/path/path2/lolcat.rb').and_return(true)
-      expect(IO).to receive(:read).with('/path/path2/lolcat.rb').exactly(1).times.and_return(ROLE_DSL)
+      expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+      expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return(["/path/path2/lolcat.rb"])
+      expect(File).to receive(:exists?).with("/path/path2/lolcat.rb").exactly(2).times.and_return(true)
+      expect(File).to receive(:readable?).with("/path/path2/lolcat.rb").and_return(true)
+      expect(IO).to receive(:read).with("/path/path2/lolcat.rb").exactly(1).times.and_return(ROLE_DSL)
       expect(@role).to be_a_kind_of(Chef::Role)
       @role.class.from_disk("lolcat")
     end
 
     it "should raise an exception if the file does not exist" do
-      expect(Dir).to receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([])
-      expect(Dir).to receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return([])
-      expect {@role.class.from_disk("lolcat")}.to raise_error(Chef::Exceptions::RoleNotFound)
+      expect(Dir).to receive(:glob).with(File.join("/path1", "**", "**")).exactly(1).times.and_return([])
+      expect(Dir).to receive(:glob).with(File.join("/path/path2", "**", "**")).exactly(1).times.and_return([])
+      expect { @role.class.from_disk("lolcat") }.to raise_error(Chef::Exceptions::RoleNotFound)
     end
 
   end
diff --git a/spec/unit/run_context/child_run_context_spec.rb b/spec/unit/run_context/child_run_context_spec.rb
new file mode 100644
index 0000000..13a035c
--- /dev/null
+++ b/spec/unit/run_context/child_run_context_spec.rb
@@ -0,0 +1,133 @@
+#
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "support/lib/library_load_order"
+
+describe Chef::RunContext::ChildRunContext do
+  context "with a run context with stuff in it" do
+    let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) }
+    let(:cookbook_collection) {
+      cl = Chef::CookbookLoader.new(chef_repo_path)
+      cl.load_cookbooks
+      Chef::CookbookCollection.new(cl)
+    }
+    let(:node) {
+      node = Chef::Node.new
+      node.run_list << "test" << "test::one" << "test::two"
+      node
+    }
+    let(:events) { Chef::EventDispatch::Dispatcher.new }
+    let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
+
+    context "and a child run context" do
+      let(:child) { run_context.create_child }
+
+      it "parent_run_context is set to the parent" do
+        expect(child.parent_run_context).to eq run_context
+      end
+
+      it "audits is not the same as the parent" do
+        expect(child.audits.object_id).not_to eq run_context.audits.object_id
+        child.audits["hi"] = "lo"
+        expect(child.audits["hi"]).to eq("lo")
+        expect(run_context.audits["hi"]).not_to eq("lo")
+      end
+
+      it "resource_collection is not the same as the parent" do
+        expect(child.resource_collection.object_id).not_to eq run_context.resource_collection.object_id
+        f = Chef::Resource::File.new("hi", child)
+        child.resource_collection.insert(f)
+        expect(child.resource_collection).to include f
+        expect(run_context.resource_collection).not_to include f
+      end
+
+      it "immediate_notification_collection is not the same as the parent" do
+        expect(child.immediate_notification_collection.object_id).not_to eq run_context.immediate_notification_collection.object_id
+        src = Chef::Resource::File.new("hi", child)
+        dest = Chef::Resource::File.new("argh", child)
+        notification = Chef::Resource::Notification.new(dest, :create, src)
+        child.notifies_immediately(notification)
+        expect(child.immediate_notification_collection["file[hi]"]).to eq([notification])
+        expect(run_context.immediate_notification_collection["file[hi]"]).not_to eq([notification])
+      end
+
+      it "immediate_notifications is not the same as the parent" do
+        src = Chef::Resource::File.new("hi", child)
+        dest = Chef::Resource::File.new("argh", child)
+        notification = Chef::Resource::Notification.new(dest, :create, src)
+        child.notifies_immediately(notification)
+        expect(child.immediate_notifications(src)).to eq([notification])
+        expect(run_context.immediate_notifications(src)).not_to eq([notification])
+      end
+
+      it "delayed_notification_collection is not the same as the parent" do
+        expect(child.delayed_notification_collection.object_id).not_to eq run_context.delayed_notification_collection.object_id
+        src = Chef::Resource::File.new("hi", child)
+        dest = Chef::Resource::File.new("argh", child)
+        notification = Chef::Resource::Notification.new(dest, :create, src)
+        child.notifies_delayed(notification)
+        expect(child.delayed_notification_collection["file[hi]"]).to eq([notification])
+        expect(run_context.delayed_notification_collection["file[hi]"]).not_to eq([notification])
+      end
+
+      it "delayed_notifications is not the same as the parent" do
+        src = Chef::Resource::File.new("hi", child)
+        dest = Chef::Resource::File.new("argh", child)
+        notification = Chef::Resource::Notification.new(dest, :create, src)
+        child.notifies_delayed(notification)
+        expect(child.delayed_notifications(src)).to eq([notification])
+        expect(run_context.delayed_notifications(src)).not_to eq([notification])
+      end
+
+      it "create_child creates a child-of-child" do
+        c = child.create_child
+        expect(c.parent_run_context).to eq child
+      end
+
+      context "after load('include::default')" do
+        before do
+          run_list = Chef::RunList.new("include::default").expand("_default")
+          # TODO not sure why we had to do this to get everything to work ...
+          node.automatic_attrs[:recipes] = []
+          child.load(run_list)
+        end
+
+        it "load_recipe loads into the child" do
+          expect(child.resource_collection).to be_empty
+          child.load_recipe("include::includee")
+          expect(child.resource_collection).not_to be_empty
+        end
+
+        it "include_recipe loads into the child" do
+          expect(child.resource_collection).to be_empty
+          child.include_recipe("include::includee")
+          expect(child.resource_collection).not_to be_empty
+        end
+
+        it "load_recipe_file loads into the child" do
+          expect(child.resource_collection).to be_empty
+          child.load_recipe_file(File.expand_path("include/recipes/includee.rb", chef_repo_path))
+          expect(child.resource_collection).not_to be_empty
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/run_context/cookbook_compiler_spec.rb b/spec/unit/run_context/cookbook_compiler_spec.rb
index 20ec1d2..868bed4 100644
--- a/spec/unit/run_context/cookbook_compiler_spec.rb
+++ b/spec/unit/run_context/cookbook_compiler_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/lib/library_load_order'
+require "spec_helper"
+require "support/lib/library_load_order"
 
 # These tests rely on fixture data in spec/data/run_context/cookbooks.
 #
@@ -45,13 +45,12 @@ describe Chef::RunContext::CookbookCompiler do
   let(:cookbook_collection) { Chef::CookbookCollection.new(cookbook_loader) }
 
   # Lazy evaluation of `expansion` here is used to mutate the run list before expanding it
-  let(:run_list_expansion) { node.run_list.expand('_default') }
+  let(:run_list_expansion) { node.run_list.expand("_default") }
 
   let(:compiler) do
     Chef::RunContext::CookbookCompiler.new(run_context, run_list_expansion, events)
   end
 
-
   describe "loading attribute files" do
 
     # Attribute files in the fixture data will append their
@@ -181,6 +180,5 @@ describe Chef::RunContext::CookbookCompiler do
       expect(compiler.unreachable_cookbook?(:'circular-dep2')).to be_truthy
     end
 
-
   end
 end
diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb
index d656111..33f2f49 100644
--- a/spec/unit/run_context_spec.rb
+++ b/spec/unit/run_context_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Tim Hinderliter (<tim at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Tim Hinderliter (<tim at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'support/lib/library_load_order'
+require "spec_helper"
+require "support/lib/library_load_order"
 
 describe Chef::RunContext do
   let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) }
@@ -53,6 +53,44 @@ describe Chef::RunContext do
     expect(run_context.node).to eq(node)
   end
 
+  it "loads up node[:cookbooks]" do
+    expect(run_context.node[:cookbooks]).to eql(
+      {
+        "circular-dep1" => {
+          "version" => "0.0.0"
+        },
+        "circular-dep2" => {
+          "version" => "0.0.0"
+        },
+        "dependency1" => {
+          "version" => "0.0.0"
+        },
+        "dependency2" => {
+          "version" => "0.0.0"
+        },
+        "include" => {
+          "version" => "0.0.0"
+        },
+        "no-default-attr" => {
+          "version" => "0.0.0"
+        },
+        "test" => {
+          "version" => "0.0.0"
+        },
+        "test-with-circular-deps" => {
+          "version" => "0.0.0"
+        },
+        "test-with-deps" => {
+          "version" => "0.0.0"
+        },
+      },
+    )
+  end
+
+  it "has a nil parent_run_context" do
+    expect(run_context.parent_run_context).to be_nil
+  end
+
   describe "loading cookbooks for a run list" do
     before do
 
@@ -66,7 +104,7 @@ describe Chef::RunContext do
       expect(node).to receive(:loaded_recipe).with(:test, "default")
       expect(node).to receive(:loaded_recipe).with(:test, "one")
       expect(node).to receive(:loaded_recipe).with(:test, "two")
-      run_context.load(node.run_list.expand('_default'))
+      run_context.load(node.run_list.expand("_default"))
     end
 
     it "should load all the definitions in the cookbooks for this node" do
@@ -159,4 +197,45 @@ describe Chef::RunContext do
       expect(run_context.reboot_requested?).to be_falsey
     end
   end
+
+  describe "notifications" do
+    let(:notification) { Chef::Resource::Notification.new(nil, nil, notifying_resource) }
+
+    shared_context "notifying resource is a Chef::Resource" do
+      let(:notifying_resource) { Chef::Resource.new("gerbil") }
+
+      it "should be keyed off the resource name" do
+        run_context.send(setter, notification)
+        expect(run_context.send(getter, notifying_resource)).to eq([notification])
+      end
+    end
+
+    shared_context "notifying resource is a subclass of Chef::Resource" do
+      let(:declared_type) { :alpaca }
+      let(:notifying_resource) {
+        r = Class.new(Chef::Resource).new("guinea pig")
+        r.declared_type = declared_type
+        r
+      }
+
+      it "should be keyed off the resource declared key" do
+        run_context.send(setter, notification)
+        expect(run_context.send(getter, notifying_resource)).to eq([notification])
+      end
+    end
+
+    describe "of the immediate kind" do
+      let(:setter) { :notifies_immediately }
+      let(:getter) { :immediate_notifications }
+      include_context "notifying resource is a Chef::Resource"
+      include_context "notifying resource is a subclass of Chef::Resource"
+    end
+
+    describe "of the delayed kind" do
+      let(:setter) { :notifies_delayed }
+      let(:getter) { :delayed_notifications }
+      include_context "notifying resource is a Chef::Resource"
+      include_context "notifying resource is a subclass of Chef::Resource"
+    end
+  end
 end
diff --git a/spec/unit/run_list/run_list_expansion_spec.rb b/spec/unit/run_list/run_list_expansion_spec.rb
index 859219d..b0cb978 100644
--- a/spec/unit/run_list/run_list_expansion_spec.rb
+++ b/spec/unit/run_list/run_list_expansion_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::RunList::RunListExpansion do
   before do
     @run_list = Chef::RunList.new
-    @run_list << 'recipe[lobster]' << 'role[rage]' << 'recipe[fist]'
+    @run_list << "recipe[lobster::mastercookbook at 0.1.0]" << "role[rage]" << "recipe[fist at 0.1]"
     @expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items)
   end
 
@@ -43,7 +43,7 @@ describe Chef::RunList::RunListExpansion do
     end
 
     it "has not applied its roles" do
-      expect(@expansion.applied_role?('rage')).to be_falsey
+      expect(@expansion.applied_role?("rage")).to be_falsey
     end
   end
 
@@ -51,7 +51,7 @@ describe Chef::RunList::RunListExpansion do
     before do
       @rage_role = Chef::Role.new.tap do |r|
         r.name("rage")
-        r.env_run_lists('_default' => [], "prod" => ["recipe[prod-only]"])
+        r.env_run_lists("_default" => [], "prod" => ["recipe[prod-only]"])
       end
       @expansion = Chef::RunList::RunListExpansion.new("prod", @run_list.run_list_items)
       expect(@expansion).to receive(:fetch_role).and_return(@rage_role)
@@ -59,7 +59,7 @@ describe Chef::RunList::RunListExpansion do
     end
 
     it "has the correct list of recipes for the given environment" do
-      expect(@expansion.recipes).to eq(["lobster", "prod-only", "fist"])
+      expect(@expansion.recipes).to eq(["lobster::mastercookbook", "prod-only", "fist"])
     end
 
   end
@@ -67,51 +67,66 @@ describe Chef::RunList::RunListExpansion do
   describe "after applying a role" do
     before do
       allow(@expansion).to receive(:fetch_role).and_return(Chef::Role.new)
-      @expansion.inflate_role('rage', "role[base]")
+      @expansion.inflate_role("rage", "role[base]")
     end
 
     it "tracks the applied role" do
-      expect(@expansion.applied_role?('rage')).to be_truthy
+      expect(@expansion.applied_role?("rage")).to be_truthy
     end
 
     it "does not inflate the role again" do
-      expect(@expansion.inflate_role('rage', "role[base]")).to be_falsey
+      expect(@expansion.inflate_role("rage", "role[base]")).to be_falsey
     end
   end
 
   describe "after expanding a run list" do
     before do
       @first_role = Chef::Role.new
-      @first_role.run_list('role[mollusk]')
-      @first_role.default_attributes({'foo' => 'bar'})
-      @first_role.override_attributes({'baz' => 'qux'})
+      @first_role.name("rage")
+      @first_role.run_list("role[mollusk]")
+      @first_role.default_attributes({ "foo" => "bar" })
+      @first_role.override_attributes({ "baz" => "qux" })
       @second_role = Chef::Role.new
-      @second_role.run_list('recipe[crabrevenge]')
-      @second_role.default_attributes({'foo' => 'boo'})
-      @second_role.override_attributes({'baz' => 'bux'})
+      @second_role.name("rage")
+      @second_role.run_list("recipe[crabrevenge]")
+      @second_role.default_attributes({ "foo" => "boo" })
+      @second_role.override_attributes({ "baz" => "bux" })
       allow(@expansion).to receive(:fetch_role).and_return(@first_role, @second_role)
       @expansion.expand
+      @json = '{"id":"_default","run_list":[{"type":"recipe","name":"lobster::mastercookbook","version":"0.1.0",'
+              .concat(
+'"skipped":false},{"type":"role","name":"rage","children":[{"type":"role","name":"mollusk","children":[],"missing":null,'
+      .concat(
+'"error":null,"skipped":null},{"type":"recipe","name":"crabrevenge","version":null,"skipped":false}],"missing":null,'
+      .concat(
+'"error":null,"skipped":null},{"type":"recipe","name":"fist","version":"0.1","skipped":false}]}')))
+
+    end
+
+    it "produces json tree upon tracing expansion" do
+      jsonRunList = @expansion.to_json
+      expect(jsonRunList).to eq(@json)
     end
 
     it "has the ordered list of recipes" do
-      expect(@expansion.recipes).to eq(['lobster', 'crabrevenge', 'fist'])
+      expect(@expansion.recipes).to eq(["lobster::mastercookbook", "crabrevenge", "fist"])
     end
 
     it "has the merged attributes from the roles with outer roles overriding inner" do
-      expect(@expansion.default_attrs).to eq({'foo' => 'bar'})
-      expect(@expansion.override_attrs).to eq({'baz' => 'qux'})
+      expect(@expansion.default_attrs).to eq({ "foo" => "bar" })
+      expect(@expansion.override_attrs).to eq({ "baz" => "qux" })
     end
 
     it "has the list of all roles applied" do
       # this is the correct order, but 1.8 hash order is not stable
-      expect(@expansion.roles).to match_array(['rage', 'mollusk'])
+      expect(@expansion.roles).to match_array(["rage", "mollusk"])
     end
 
   end
 
   describe "after expanding a run list with a non existent role" do
     before do
-      allow(@expansion).to receive(:fetch_role) { @expansion.role_not_found('crabrevenge', "role[base]") }
+      allow(@expansion).to receive(:fetch_role) { @expansion.role_not_found("crabrevenge", "role[base]") }
       @expansion.expand
     end
 
@@ -121,7 +136,7 @@ describe Chef::RunList::RunListExpansion do
     end
 
     it "has a list of invalid role names" do
-      expect(@expansion.errors).to include('crabrevenge')
+      expect(@expansion.errors).to include("crabrevenge")
     end
 
   end
diff --git a/spec/unit/run_list/run_list_item_spec.rb b/spec/unit/run_list/run_list_item_spec.rb
index 16832c1..3f8fd2a 100644
--- a/spec/unit/run_list/run_list_item_spec.rb
+++ b/spec/unit/run_list/run_list_item_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,22 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::RunList::RunListItem do
 
   describe "when creating from a Hash" do
     it "raises an exception when the hash doesn't have a :type key" do
-      expect {Chef::RunList::RunListItem.new(:name => "tatft")}.to raise_error(ArgumentError)
+      expect { Chef::RunList::RunListItem.new(:name => "tatft") }.to raise_error(ArgumentError)
     end
 
     it "raises an exception when the hash doesn't have an :name key" do
-      expect {Chef::RunList::RunListItem.new(:type => 'R') }.to raise_error(ArgumentError)
+      expect { Chef::RunList::RunListItem.new(:type => "R") }.to raise_error(ArgumentError)
     end
 
     it "sets the name and type as given in the hash" do
-      item = Chef::RunList::RunListItem.new(:type => 'fuuu', :name => 'uuuu')
-      expect(item.to_s).to eq('fuuu[uuuu]')
+      item = Chef::RunList::RunListItem.new(:type => "fuuu", :name => "uuuu")
+      expect(item.to_s).to eq("fuuu[uuuu]")
     end
 
   end
@@ -41,77 +41,77 @@ describe Chef::RunList::RunListItem do
       item = Chef::RunList::RunListItem.new("recipe[rage]")
       expect(item).to be_a_recipe
       expect(item).not_to be_a_role
-      expect(item.to_s).to eq('recipe[rage]')
-      expect(item.name).to eq('rage')
+      expect(item.to_s).to eq("recipe[rage]")
+      expect(item.name).to eq("rage")
     end
 
     it "parses a qualified recipe with a version" do
       item = Chef::RunList::RunListItem.new("recipe[rage at 0.1.0]")
       expect(item).to be_a_recipe
       expect(item).not_to be_a_role
-      expect(item.to_s).to eq('recipe[rage at 0.1.0]')
-      expect(item.name).to eq('rage')
-      expect(item.version).to eq('0.1.0')
+      expect(item.to_s).to eq("recipe[rage at 0.1.0]")
+      expect(item.name).to eq("rage")
+      expect(item.version).to eq("0.1.0")
     end
 
     it "parses a qualified role" do
       item = Chef::RunList::RunListItem.new("role[fist]")
       expect(item).to be_a_role
       expect(item).not_to be_a_recipe
-      expect(item.to_s).to eq('role[fist]')
-      expect(item.name).to eq('fist')
+      expect(item.to_s).to eq("role[fist]")
+      expect(item.name).to eq("fist")
     end
 
     it "parses an unqualified recipe" do
       item = Chef::RunList::RunListItem.new("lobster")
       expect(item).to be_a_recipe
       expect(item).not_to be_a_role
-      expect(item.to_s).to eq('recipe[lobster]')
-      expect(item.name).to eq('lobster')
+      expect(item.to_s).to eq("recipe[lobster]")
+      expect(item.name).to eq("lobster")
     end
 
     it "raises an exception when the string has typo on the type part" do
-      expect {Chef::RunList::RunListItem.new("Recipe[lobster]") }.to raise_error(ArgumentError)
+      expect { Chef::RunList::RunListItem.new("Recipe[lobster]") }.to raise_error(ArgumentError)
     end
 
     it "raises an exception when the string has extra space between the type and the name" do
-      expect {Chef::RunList::RunListItem.new("recipe [lobster]") }.to raise_error(ArgumentError)
+      expect { Chef::RunList::RunListItem.new("recipe [lobster]") }.to raise_error(ArgumentError)
     end
 
     it "raises an exception when the string does not close the bracket" do
-      expect {Chef::RunList::RunListItem.new("recipe[lobster") }.to raise_error(ArgumentError)
+      expect { Chef::RunList::RunListItem.new("recipe[lobster") }.to raise_error(ArgumentError)
     end
   end
 
   describe "comparing to other run list items" do
     it "is equal to another run list item that has the same name and type" do
-      item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
-      item2 = Chef::RunList::RunListItem.new('recipe[lrf]')
+      item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+      item2 = Chef::RunList::RunListItem.new("recipe[lrf]")
       expect(item1).to eq(item2)
     end
 
     it "is not equal to another run list item with the same name and different type" do
-      item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
-      item2 = Chef::RunList::RunListItem.new('role[lrf]')
+      item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+      item2 = Chef::RunList::RunListItem.new("role[lrf]")
       expect(item1).not_to eq(item2)
     end
 
     it "is not equal to another run list item with the same type and different name" do
-      item1 = Chef::RunList::RunListItem.new('recipe[lrf]')
-      item2 = Chef::RunList::RunListItem.new('recipe[lobsterragefist]')
+      item1 = Chef::RunList::RunListItem.new("recipe[lrf]")
+      item2 = Chef::RunList::RunListItem.new("recipe[lobsterragefist]")
       expect(item1).not_to eq(item2)
     end
 
     it "is not equal to another run list item with the same name and type but different version" do
-      item1 = Chef::RunList::RunListItem.new('recipe[lrf,0.1.0]')
-      item2 = Chef::RunList::RunListItem.new('recipe[lrf,0.2.0]')
+      item1 = Chef::RunList::RunListItem.new("recipe[lrf,0.1.0]")
+      item2 = Chef::RunList::RunListItem.new("recipe[lrf,0.2.0]")
       expect(item1).not_to eq(item2)
     end
   end
 
   describe "comparing to strings" do
     it "is equal to a string if that string matches its to_s representation" do
-      expect(Chef::RunList::RunListItem.new('recipe[lrf]')).to eq('recipe[lrf]')
+      expect(Chef::RunList::RunListItem.new("recipe[lrf]")).to eq("recipe[lrf]")
     end
   end
 end
diff --git a/spec/unit/run_list/versioned_recipe_list_spec.rb b/spec/unit/run_list/versioned_recipe_list_spec.rb
index 209ac37..2b1c6ed 100644
--- a/spec/unit/run_list/versioned_recipe_list_spec.rb
+++ b/spec/unit/run_list/versioned_recipe_list_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Stephen Delano (<stephen at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Stephen Delano (<stephen at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::RunList::VersionedRecipeList do
 
@@ -26,98 +26,169 @@ describe Chef::RunList::VersionedRecipeList do
     end
   end
 
+  let(:list) { described_class.new }
+
+  let(:versioned_recipes) { [] }
+
+  let(:recipes) { [] }
+
+  before do
+    recipes.each { |r| list << r }
+    versioned_recipes.each { |r| list.add_recipe r[:name], r[:version] }
+  end
+
   describe "add_recipe" do
-    before(:each) do
-      @list = Chef::RunList::VersionedRecipeList.new
-      @list << "apt"
-      @list << "god"
-      @list << "apache2"
-    end
+
+    let(:recipes) { %w{ apt god apache2 } }
 
     it "should append the recipe to the end of the list" do
-      @list.add_recipe "rails"
-      expect(@list).to eq(["apt", "god", "apache2", "rails"])
+      list.add_recipe "rails"
+      expect(list).to eq(["apt", "god", "apache2", "rails"])
     end
 
     it "should not duplicate entries" do
-      @list.add_recipe "apt"
-      expect(@list).to eq(["apt", "god", "apache2"])
+      list.add_recipe "apt"
+      expect(list).to eq(["apt", "god", "apache2"])
     end
 
     it "should allow you to specify a version" do
-      @list.add_recipe "rails", "1.0.0"
-      expect(@list).to eq(["apt", "god", "apache2", "rails"])
-      expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+      list.add_recipe "rails", "1.0.0"
+      expect(list).to eq(["apt", "god", "apache2", "rails"])
+      expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
     end
 
     it "should allow you to specify a version for a recipe that already exists" do
-      @list.add_recipe "apt", "1.2.3"
-      expect(@list).to eq(["apt", "god", "apache2"])
-      expect(@list.with_versions).to include({:name => "apt", :version => "1.2.3"})
+      list.add_recipe "apt", "1.2.3"
+      expect(list).to eq(["apt", "god", "apache2"])
+      expect(list.with_versions).to include({ :name => "apt", :version => "1.2.3" })
     end
 
     it "should allow you to specify the same version of a recipe twice" do
-      @list.add_recipe "rails", "1.0.0"
-      @list.add_recipe "rails", "1.0.0"
-      expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+      list.add_recipe "rails", "1.0.0"
+      list.add_recipe "rails", "1.0.0"
+      expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
     end
 
     it "should allow you to spcify no version, even when a version already exists" do
-      @list.add_recipe "rails", "1.0.0"
-      @list.add_recipe "rails"
-      expect(@list.with_versions).to include({:name => "rails", :version => "1.0.0"})
+      list.add_recipe "rails", "1.0.0"
+      list.add_recipe "rails"
+      expect(list.with_versions).to include({ :name => "rails", :version => "1.0.0" })
     end
 
     it "should not allow multiple versions of the same recipe" do
-      @list.add_recipe "rails", "1.0.0"
-      expect {@list.add_recipe "rails", "0.1.0"}.to raise_error Chef::Exceptions::CookbookVersionConflict
+      list.add_recipe "rails", "1.0.0"
+      expect { list.add_recipe "rails", "0.1.0" }.to raise_error Chef::Exceptions::CookbookVersionConflict
     end
   end
 
   describe "with_versions" do
-    before(:each) do
-      @recipes = [
-        {:name => "apt", :version => "1.0.0"},
-        {:name => "god", :version => nil},
-        {:name => "apache2", :version => "0.0.1"}
+
+    let(:versioned_recipes) do
+      [
+        { :name => "apt", :version => "1.0.0" },
+        { :name => "god", :version => nil },
+        { :name => "apache2", :version => "0.0.1" },
       ]
-      @list = Chef::RunList::VersionedRecipeList.new
-      @recipes.each {|i| @list.add_recipe i[:name], i[:version]}
     end
-
     it "should return an array of hashes with :name and :version" do
-      expect(@list.with_versions).to eq(@recipes)
+      expect(list.with_versions).to eq(versioned_recipes)
     end
 
     it "should retain the same order as the version-less list" do
-      with_versions = @list.with_versions
-      @list.each_with_index do |item, index|
+      with_versions = list.with_versions
+      list.each_with_index do |item, index|
         expect(with_versions[index][:name]).to eq(item)
       end
     end
   end
 
   describe "with_version_constraints" do
-    before(:each) do
-      @recipes = [
-                  {:name => "apt", :version => "~> 1.2.0"},
-                  {:name => "god", :version => nil},
-                  {:name => "apache2", :version => "0.0.1"}
-                 ]
-      @list = Chef::RunList::VersionedRecipeList.new
-      @recipes.each {|i| @list.add_recipe i[:name], i[:version]}
-      @constraints = @recipes.map do |x|
-        { :name => x[:name],
-          :version_constraint => Chef::VersionConstraint.new(x[:version])
-        }
-      end
+
+    let(:versioned_recipes) do
+      [
+        { :name => "apt", :version => "~> 1.2.0" },
+        { :name => "god", :version => nil },
+        { :name => "apache2", :version => "0.0.1" },
+      ]
     end
 
     it "should return an array of hashes with :name and :version_constraint" do
-      @list.with_version_constraints.each do |x|
-        expect(x).to have_key :name
-        expect(x[:version_constraint]).not_to be nil
+      list.with_version_constraints.each_with_index do |recipe_spec, i|
+
+        expected_recipe = versioned_recipes[i]
+
+        expect(recipe_spec[:name]).to eq(expected_recipe[:name])
+        expect(recipe_spec[:version_constraint]).to eq(Chef::VersionConstraint.new(expected_recipe[:version]))
+      end
+    end
+  end
+
+  describe "with_fully_qualified_names_and_version_constraints" do
+
+    let(:fq_names) { list.with_fully_qualified_names_and_version_constraints }
+
+    context "with bare cookbook names" do
+
+      let(:recipes) { %w{ apache2 } }
+
+      it "gives $cookbook_name::default" do
+        expect(fq_names).to eq( %w{ apache2::default } )
+      end
+
+    end
+
+    context "with qualified recipe names but no versions" do
+
+      let(:recipes) { %w{ mysql::server } }
+
+      it "returns the qualified recipe names" do
+        expect(fq_names).to eq( %w{ mysql::server } )
       end
+
+    end
+
+    context "with unqualified names that have version constraints" do
+
+      let(:versioned_recipes) do
+        [
+          { :name => "apt", :version => "~> 1.2.0" },
+        ]
+      end
+
+      it "gives qualified names with their versions" do
+        expect(fq_names).to eq([ "apt::default@~> 1.2.0" ])
+      end
+
+      it "does not mutate the recipe name" do
+        expect(fq_names).to eq([ "apt::default@~> 1.2.0" ])
+        expect(list).to eq( [ "apt" ] )
+      end
+
+    end
+
+    context "with fully qualified names that have version constraints" do
+
+      let(:versioned_recipes) do
+        [
+          { :name => "apt::cacher", :version => "~> 1.2.0" },
+        ]
+      end
+
+      it "gives qualified names with their versions" do
+        expect(fq_names).to eq([ "apt::cacher@~> 1.2.0" ])
+      end
+
+      it "does not mutate the recipe name" do
+        expect(fq_names).to eq([ "apt::cacher@~> 1.2.0" ])
+        expect(list).to eq( [ "apt::cacher" ] )
+      end
+
+    end
+  end
+
+  context "with duplicated names", :chef_gte_13_only do
+    it "should fail in Chef 13" do
+      expect(list).to_not respond_to(:with_duplicate_names)
     end
   end
 end
diff --git a/spec/unit/run_list_spec.rb b/spec/unit/run_list_spec.rb
index bf996de..6d17e65 100644
--- a/spec/unit/run_list_spec.rb
+++ b/spec/unit/run_list_spec.rb
@@ -1,8 +1,8 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Author:: Christopher Walters (<cw at opscode.com>)
-# Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Seth Falcon (<seth at chef.io>)
+# Author:: Christopher Walters (<cw at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,10 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
-require 'chef/version_class'
-require 'chef/version_constraint'
+require "chef/version_class"
+require "chef/version_constraint"
 
 describe Chef::RunList do
   before(:each) do
@@ -30,21 +30,21 @@ describe Chef::RunList do
 
   describe "<<" do
     it "should add a recipe to the run list and recipe list with the fully qualified name" do
-      @run_list << 'recipe[needy]'
-      expect(@run_list).to include('recipe[needy]')
+      @run_list << "recipe[needy]"
+      expect(@run_list).to include("recipe[needy]")
       expect(@run_list.recipes).to include("needy")
     end
 
     it "should add a role to the run list and role list with the fully qualified name" do
       @run_list << "role[woot]"
-      expect(@run_list).to include('role[woot]')
-      expect(@run_list.roles).to include('woot')
+      expect(@run_list).to include("role[woot]")
+      expect(@run_list.roles).to include("woot")
     end
 
     it "should accept recipes that are unqualified" do
       @run_list << "needy"
-      expect(@run_list).to include('recipe[needy]')
-      expect(@run_list.recipes.include?('needy')).to eq(true)
+      expect(@run_list).to include("recipe[needy]")
+      expect(@run_list.recipes.include?("needy")).to eq(true)
     end
 
     it "should not allow duplicates" do
@@ -59,7 +59,7 @@ describe Chef::RunList do
       @run_list << "recipe[needy at 0.1.0]"
       expect(@run_list.run_list.length).to eq(2)
       expect(@run_list.recipes.length).to eq(2)
-      expect(@run_list.recipes.include?('needy')).to eq(true)
+      expect(@run_list.recipes.include?("needy")).to eq(true)
     end
 
     it "should not allow duplicate versions of a recipe" do
@@ -74,13 +74,13 @@ describe Chef::RunList do
     # Testing only the basic functionality here
     # since full behavior is tested above.
     it "should add a recipe to the run_list" do
-      @run_list.add 'recipe[needy]'
-      expect(@run_list).to include('recipe[needy]')
+      @run_list.add "recipe[needy]"
+      expect(@run_list).to include("recipe[needy]")
     end
 
     it "should add a role to the run_list" do
-      @run_list.add 'role[needy]'
-      expect(@run_list).to include('role[needy]')
+      @run_list.add "role[needy]"
+      expect(@run_list).to include("role[needy]")
     end
   end
 
@@ -112,20 +112,20 @@ describe Chef::RunList do
 
   describe "[]" do
     it "should let you look up a member in the run list by position" do
-      @run_list << 'recipe[loulou]'
-      expect(@run_list[0]).to eq('recipe[loulou]')
+      @run_list << "recipe[loulou]"
+      expect(@run_list[0]).to eq("recipe[loulou]")
     end
   end
 
   describe "[]=" do
     it "should let you set a member of the run list by position" do
-      @run_list[0] = 'recipe[loulou]'
-      expect(@run_list[0]).to eq('recipe[loulou]')
+      @run_list[0] = "recipe[loulou]"
+      expect(@run_list[0]).to eq("recipe[loulou]")
     end
 
     it "should properly expand a member of the run list given by position" do
-      @run_list[0] = 'loulou'
-      expect(@run_list[0]).to eq('recipe[loulou]')
+      @run_list[0] = "loulou"
+      expect(@run_list[0]).to eq("recipe[loulou]")
     end
   end
 
@@ -172,10 +172,11 @@ describe Chef::RunList do
       @role.run_list "one", "two"
       @role.default_attributes :one => :two
       @role.override_attributes :three => :four
+      @role.env_run_list["production"] = Chef::RunList.new( "one", "two", "five")
 
       allow(Chef::Role).to receive(:load).and_return(@role)
-      @rest = double("Chef::REST", { :get_rest => @role, :url => "/" })
-      allow(Chef::REST).to receive(:new).and_return(@rest)
+      @rest = double("Chef::ServerAPI", { :get => @role.to_hash, :url => "/" })
+      allow(Chef::ServerAPI).to receive(:new).and_return(@rest)
 
       @run_list << "role[stubby]"
       @run_list << "kitty"
@@ -196,21 +197,17 @@ describe Chef::RunList do
 
     describe "from the chef server" do
       it "should load the role from the chef server" do
-        #@rest.should_receive(:get_rest).with("roles/stubby")
+        #@rest.should_receive(:get).with("roles/stubby")
         expansion = @run_list.expand("_default", "server")
-        expect(expansion.recipes).to eq(['one', 'two', 'kitty'])
+        expect(expansion.recipes).to eq(["one", "two", "kitty"])
       end
 
       it "should default to expanding from the server" do
-        expect(@rest).to receive(:get_rest).with("roles/stubby")
+        expect(@rest).to receive(:get).with("roles/stubby")
         @run_list.expand("_default")
       end
 
       describe "with an environment set" do
-        before do
-          @role.env_run_list["production"] = Chef::RunList.new( "one", "two", "five")
-        end
-
         it "expands the run list using the environment specific run list" do
           expansion = @run_list.expand("production", "server")
           expect(expansion.recipes).to eq(%w{one two five kitty})
@@ -218,7 +215,7 @@ describe Chef::RunList do
 
         describe "and multiply nested roles" do
           before do
-            @multiple_rest_requests = double("Chef::REST")
+            @multiple_rest_requests = double("Chef::ServerAPI")
 
             @role.env_run_list["production"] << "role[prod-base]"
 
@@ -226,17 +223,16 @@ describe Chef::RunList do
             @role_prod_base.name("prod-base")
             @role_prod_base.env_run_list["production"] = Chef::RunList.new("role[nested-deeper]")
 
-
             @role_nested_deeper = Chef::Role.new
             @role_nested_deeper.name("nested-deeper")
             @role_nested_deeper.env_run_list["production"] = Chef::RunList.new("recipe[prod-secret-sauce]")
           end
 
           it "expands the run list using the specified environment for all nested roles" do
-            allow(Chef::REST).to receive(:new).and_return(@multiple_rest_requests)
-            expect(@multiple_rest_requests).to receive(:get_rest).with("roles/stubby").and_return(@role)
-            expect(@multiple_rest_requests).to receive(:get_rest).with("roles/prod-base").and_return(@role_prod_base)
-            expect(@multiple_rest_requests).to receive(:get_rest).with("roles/nested-deeper").and_return(@role_nested_deeper)
+            allow(Chef::ServerAPI).to receive(:new).and_return(@multiple_rest_requests)
+            expect(@multiple_rest_requests).to receive(:get).with("roles/stubby").and_return(@role.to_hash)
+            expect(@multiple_rest_requests).to receive(:get).with("roles/prod-base").and_return(@role_prod_base.to_hash)
+            expect(@multiple_rest_requests).to receive(:get).with("roles/nested-deeper").and_return(@role_nested_deeper.to_hash)
 
             expansion = @run_list.expand("production", "server")
             expect(expansion.recipes).to eq(%w{one two five prod-secret-sauce kitty})
@@ -273,7 +269,7 @@ describe Chef::RunList do
       allow(Chef::Role).to receive(:from_disk).with("stubby").and_return(@role)
       allow(Chef::Role).to receive(:from_disk).with("dog").and_return(dog)
 
-      expansion = @run_list.expand("_default", 'disk')
+      expansion = @run_list.expand("_default", "disk")
       expect(expansion.recipes[2]).to eq("three")
       expect(expansion.default_attrs[:seven]).to eq(:nine)
     end
@@ -287,7 +283,7 @@ describe Chef::RunList do
       allow(Chef::Role).to receive(:from_disk).with("stubby").and_return(@role)
       expect(Chef::Role).to receive(:from_disk).with("dog").once.and_return(dog)
 
-      expansion = @run_list.expand("_default", 'disk')
+      expansion = @run_list.expand("_default", "disk")
       expect(expansion.recipes[2]).to eq("three")
       expect(expansion.recipes[3]).to eq("kitty")
       expect(expansion.default_attrs[:seven]).to eq(:nine)
@@ -307,7 +303,7 @@ describe Chef::RunList do
       expect(Chef::JSONCompat.to_json(@run_list)).to eq(Chef::JSONCompat.to_json(["recipe[nagios::client]", "role[production]", "recipe[apache2]"]))
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { @run_list }
     end
 
diff --git a/spec/unit/run_lock_spec.rb b/spec/unit/run_lock_spec.rb
index 51e6ba1..350a0b2 100644
--- a/spec/unit/run_lock_spec.rb
+++ b/spec/unit/run_lock_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +15,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require File.expand_path('../../spec_helper', __FILE__)
-require 'chef/client'
+require File.expand_path("../../spec_helper", __FILE__)
+require "chef/client"
 
 describe Chef::RunLock do
 
-  default_cache_path = windows? ? 'C:\chef' : '/var/chef'
-  default_pid_location = windows? ? 'C:\chef\cache\chef-client-running.pid' : '/var/chef/cache/chef-client-running.pid'
+  default_cache_path = windows? ? 'C:\chef' : "/var/chef"
+  default_pid_location = windows? ? 'C:\chef\cache\chef-client-running.pid' : "/var/chef/cache/chef-client-running.pid"
 
   describe "when first created" do
     it "locates the lockfile in the file cache path by default" do
@@ -91,7 +91,7 @@ describe Chef::RunLock do
         it "should raise Chef::Exceptions::RunLockTimeout" do
           stub_blocked_run(0.001)
           expect(runlock).not_to receive(:wait)
-          expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
+          expect { runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
         end
       end
     end
@@ -118,9 +118,9 @@ describe Chef::RunLock do
       describe "and the lockfile is locked by another client run" do
         describe "and the lock is released before the timeout expires" do
           it "should acquire the lock" do
-            stub_blocked_run(@timeout/2.0)
+            stub_blocked_run(@timeout / 2.0)
             expect(runlock).to receive(:wait)
-            expect{ runlock.acquire }.not_to raise_error
+            expect { runlock.acquire }.not_to raise_error
           end
         end
 
@@ -128,7 +128,7 @@ describe Chef::RunLock do
           it "should raise a RunLockTimeout exception" do
             stub_blocked_run(2.0)
             expect(runlock).to receive(:wait)
-            expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
+            expect { runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout)
           end
         end
       end
diff --git a/spec/unit/run_status_spec.rb b/spec/unit/run_status_spec.rb
index d658cb5..6305b74 100644
--- a/spec/unit/run_status_spec.rb
+++ b/spec/unit/run_status_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::RunStatus do
   before do
@@ -82,7 +81,7 @@ describe Chef::RunStatus do
 
     describe "with resources in the resource_collection" do
       before do
-        @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new('dtz')]
+        @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new("dtz")]
         @run_context.resource_collection.all_resources.replace(@all_resources)
       end
 
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index b30f818..300d512 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -1,6 +1,6 @@
 
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 class SnitchyProvider < Chef::Provider
   def self.all_actions_called
@@ -104,7 +104,7 @@ describe Chef::Runner do
       # set up old Chef::Platform resolution instead of provider_resolver
       Chef::Platform.set(
         :resource => :cat,
-        :provider => Chef::Provider::SnakeOil
+        :provider => Chef::Provider::SnakeOil,
       )
       allow(Chef::ProviderResolver).to receive(:new).and_return(provider_resolver)
       allow(provider_resolver).to receive(:maybe_dynamic_provider_resolution).with(first_resource, anything()).and_return(nil)
@@ -239,7 +239,7 @@ describe Chef::Runner do
       second_resource.notifies(:fail, third_resource, :delayed)
       second_resource.notifies(:purr, first_resource, :delayed)
 
-      expect {runner.converge}.to raise_error(FailureProvider::ChefClientFail)
+      expect { runner.converge }.to raise_error(FailureProvider::ChefClientFail)
 
       expect(first_resource).to be_updated
     end
@@ -271,7 +271,7 @@ describe Chef::Runner do
       end
       expect(exception).to be_a(Chef::Exceptions::MultipleFailures)
 
-      expected_message =<<-E
+      expected_message = <<-E
 Multiple failures occurred:
 * FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
 * FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort
@@ -372,10 +372,10 @@ Multiple failures occurred:
       first_resource.action = :buy
 
       only_if_called_times = 0
-      first_resource.only_if {only_if_called_times += 1; true}
+      first_resource.only_if { only_if_called_times += 1; true }
 
       not_if_called_times = 0
-      first_resource.not_if {not_if_called_times += 1; false}
+      first_resource.not_if { not_if_called_times += 1; false }
 
       second_resource = Chef::Resource::Cat.new("carmel", run_context)
       run_context.resource_collection << second_resource
diff --git a/spec/unit/scan_access_control_spec.rb b/spec/unit/scan_access_control_spec.rb
index 8cf681e..c747f6c 100644
--- a/spec/unit/scan_access_control_spec.rb
+++ b/spec/unit/scan_access_control_spec.rb
@@ -1,5 +1,5 @@
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2012 Opscode, inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 #
 
 require File.expand_path("../../spec_helper", __FILE__)
-require 'chef/scan_access_control'
+require "chef/scan_access_control"
 
 describe Chef::ScanAccessControl do
 
@@ -33,7 +33,7 @@ describe Chef::ScanAccessControl do
       @new_resource.tap do |f|
         f.owner("root")
         f.group("root")
-        f.mode('0755')
+        f.mode("0755")
       end
       @scanner.set_all!
     end
@@ -181,4 +181,3 @@ describe Chef::ScanAccessControl do
     end
   end
 end
-
diff --git a/spec/unit/search/query_spec.rb b/spec/unit/search/query_spec.rb
index 59ac80f..9652d69 100644
--- a/spec/unit/search/query_spec.rb
+++ b/spec/unit/search/query_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Copyright:: Copyright (c) 2009,2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Copyright:: Copyright 2009-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,11 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'chef/search/query'
+require "spec_helper"
+require "chef/search/query"
 
 describe Chef::Search::Query do
-  let(:rest) { double("Chef::REST") }
+  let(:rest) { double("Chef::ServerAPI") }
   let(:query) { Chef::Search::Query.new }
 
   shared_context "filtered search" do
@@ -29,8 +29,8 @@ describe Chef::Search::Query do
     let(:args) { { filter_key => filter_hash } }
     let(:filter_hash) {
       {
-        'env' => [ 'chef_environment' ],
-        'ruby_plat' => [ 'languages', 'ruby', 'platform' ]
+        "env" => [ "chef_environment" ],
+        "ruby_plat" => [ "languages", "ruby", "platform" ],
       }
     }
     let(:response) {
@@ -39,108 +39,114 @@ describe Chef::Search::Query do
           { "url" => "#{server_url}/my-name-is-node",
             "data" => {
               "env" => "elysium",
-              "ruby_plat" => "nudibranch"
-            }
+              "ruby_plat" => "nudibranch",
+            },
           },
           { "url" => "#{server_url}/my-name-is-jonas",
             "data" => {
               "env" => "hades",
-              "ruby_plat" => "i386-mingw32"
-            }
+              "ruby_plat" => "i386-mingw32",
+            },
           },
           { "url" => "#{server_url}/my-name-is-flipper",
             "data" => {
               "env" => "elysium",
-              "ruby_plat" => "centos"
-            }
+              "ruby_plat" => "centos",
+            },
           },
           { "url" => "#{server_url}/my-name-is-butters",
             "data" => {
               "env" => "moon",
               "ruby_plat" => "solaris2",
-            }
-          }
+            },
+          },
         ],
         "start" => 0,
-        "total" => 4
+        "total" => 4,
       }
     }
     let(:response_rows) {
       [
         { "env" => "elysium", "ruby_plat" => "nudibranch" },
-        { "env" => "hades", "ruby_plat" => "i386-mingw32"},
-        { "env" => "elysium", "ruby_plat" => "centos"},
-        { "env" => "moon", "ruby_plat" => "solaris2"}
+        { "env" => "hades", "ruby_plat" => "i386-mingw32" },
+        { "env" => "elysium", "ruby_plat" => "centos" },
+        { "env" => "moon", "ruby_plat" => "solaris2" },
       ]
     }
   end
 
   before(:each) do
-    allow(Chef::REST).to receive(:new).and_return(rest)
-    allow(rest).to receive(:get_rest).and_return(response)
+    allow(Chef::ServerAPI).to receive(:new).and_return(rest)
+    allow(rest).to receive(:get).and_return(response)
   end
 
   describe "search" do
     let(:query_string) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0" }
     let(:query_string_continue) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=4" }
+    let(:query_string_with_rows) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=4" }
+    let(:query_string_continue_with_rows) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=4&rows=4" }
 
     let(:response) { {
       "rows" => [
         { "name" => "my-name-is-node",
           "chef_environment" => "elysium",
           "platform" => "rhel",
+          "run_list" => [],
           "automatic" => {
             "languages" => {
               "ruby" => {
                 "platform" => "nudibranch",
                 "version" => "1.9.3",
-                "target" => "ming-the-merciless"
+                "target" => "ming-the-merciless",
               }
             }
-          }
+          },
         },
         { "name" => "my-name-is-jonas",
           "chef_environment" => "hades",
           "platform" => "rhel",
+          "run_list" => [],
           "automatic" => {
             "languages" => {
               "ruby" => {
                 "platform" => "i386-mingw32",
                 "version" => "1.9.3",
-                "target" => "bilbo"
+                "target" => "bilbo",
               }
             }
-          }
+          },
         },
         { "name" => "my-name-is-flipper",
           "chef_environment" => "elysium",
           "platform" => "rhel",
+          "run_list" => [],
           "automatic" => {
             "languages" => {
               "ruby" => {
                 "platform" => "centos",
                 "version" => "2.0.0",
-                "target" => "uno"
+                "target" => "uno",
               }
             }
-          }
+          },
         },
         { "name" => "my-name-is-butters",
           "chef_environment" => "moon",
           "platform" => "rhel",
+          "run_list" => [],
           "automatic" => {
             "languages" => {
               "ruby" => {
                 "platform" => "solaris2",
                 "version" => "2.1.2",
-                "target" => "random"
+                "target" => "random",
               }
             }
-          }
+          },
         },
       ],
       "start" => 0,
-      "total" => 4
+      "total" => 4,
     } }
 
     let(:big_response) {
@@ -149,6 +155,14 @@ describe Chef::Search::Query do
       r
     }
 
+    let(:big_response_empty) {
+      {
+        "start" => 0,
+        "total" => 8,
+        "rows" => [],
+      }
+    }
+
     let(:big_response_end) {
       r = response.dup
       r["start"] = 4
@@ -163,27 +177,27 @@ describe Chef::Search::Query do
     end
 
     it "queries for every object of a type by default" do
-      expect(rest).to receive(:get_rest).with("search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
+      expect(rest).to receive(:get).with("search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
       query.search(:node)
     end
 
     it "allows a custom query" do
-      expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
+      expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0").and_return(response)
       query.search(:node, "platform:rhel")
     end
 
     it "lets you set a sort order" do
-      expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=id%20desc&start=0").and_return(response)
+      expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=id%20desc&start=0").and_return(response)
       query.search(:node, "platform:rhel", sort: "id desc")
     end
 
     it "lets you set a starting object" do
-      expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=2").and_return(response)
+      expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=2").and_return(response)
       query.search(:node, "platform:rhel", start: 2)
     end
 
     it "lets you set how many rows to return" do
-      expect(rest).to receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=40").and_return(response)
+      expect(rest).to receive(:get).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=40").and_return(response)
       query.search(:node, "platform:rhel", rows: 40)
     end
 
@@ -201,40 +215,48 @@ describe Chef::Search::Query do
 
     it "calls a block for each object in the response" do
       @call_me = double("blocky")
-      response["rows"].each { |r| expect(@call_me).to receive(:do).with(r) }
+      response["rows"].each { |r| expect(@call_me).to receive(:do).with(Chef::Node.from_hash(r)) }
       query.search(:node) { |r| @call_me.do(r) }
     end
 
     it "pages through the responses" do
       @call_me = double("blocky")
-      response["rows"].each { |r| expect(@call_me).to receive(:do).with(r) }
-      query.search(:node, "*:*", sort: nil, start: 0, rows: 1) { |r| @call_me.do(r) }
+      response["rows"].each { |r| expect(@call_me).to receive(:do).with(Chef::Node.from_hash(r)) }
+      query.search(:node, "*:*", sort: nil, start: 0, rows: 4) { |r| @call_me.do(r) }
     end
 
     it "sends multiple API requests when the server indicates there is more data" do
-      expect(rest).to receive(:get_rest).with(query_string).and_return(big_response)
-      expect(rest).to receive(:get_rest).with(query_string_continue).and_return(big_response_end)
+      expect(rest).to receive(:get).with(query_string).and_return(big_response)
+      expect(rest).to receive(:get).with(query_string_continue).and_return(big_response_end)
       query.search(:node, "platform:rhel") do |r|
         nil
       end
     end
 
+    it "paginates correctly in the face of filtered nodes" do
+      expect(rest).to receive(:get).with(query_string_with_rows).and_return(big_response_empty)
+      expect(rest).to receive(:get).with(query_string_continue_with_rows).and_return(big_response_end)
+      query.search(:node, "platform:rhel", rows: 4) do |r|
+        nil
+      end
+    end
+
     context "when :filter_result is provided as a result" do
       include_context "filtered search" do
         let(:filter_key) { :filter_result }
 
         before(:each) do
-          expect(rest).to receive(:post_rest).with(query_string, args[filter_key]).and_return(response)
+          expect(rest).to receive(:post).with(query_string, args[filter_key]).and_return(response)
         end
 
         it "returns start" do
           start = query.search(:node, "platform:rhel", args)[1]
-          expect(start).to eq(response['start'])
+          expect(start).to eq(response["start"])
         end
 
         it "returns total" do
           total = query.search(:node, "platform:rhel", args)[2]
-          expect(total).to eq(response['total'])
+          expect(total).to eq(response["total"])
         end
 
         it "returns rows with the filter applied" do
@@ -258,7 +280,7 @@ describe Chef::Search::Query do
       end
 
       it "returns an array of filtered hashes" do
-        expect(rest).to receive(:post_rest).with(query_string, args[filter_key]).and_return(response)
+        expect(rest).to receive(:post).with(query_string, args[filter_key]).and_return(response)
         results = query.partial_search(:node, "platform:rhel", args)
         expect(results[0]).to match_array(response_rows)
       end
diff --git a/spec/unit/shell/model_wrapper_spec.rb b/spec/unit/shell/model_wrapper_spec.rb
index d6da2dc..00425f2 100644
--- a/spec/unit/shell/model_wrapper_spec.rb
+++ b/spec/unit/shell/model_wrapper_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,18 +16,18 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'ostruct'
+require "spec_helper"
+require "ostruct"
 
 describe Shell::ModelWrapper do
   before do
-    @model = OpenStruct.new(:name=>"Chef::Node")
+    @model = OpenStruct.new(:name => "Chef::Node")
     @wrapper = Shell::ModelWrapper.new(@model)
   end
 
   describe "when created with an explicit model_symbol" do
     before do
-      @model = OpenStruct.new(:name=>"Chef::ApiClient")
+      @model = OpenStruct.new(:name => "Chef::ApiClient")
       @wrapper = Shell::ModelWrapper.new(@model, :client)
     end
 
@@ -46,7 +46,7 @@ describe Shell::ModelWrapper do
       @node_1.name("sammich")
       @node_2 = Chef::Node.new
       @node_2.name("yummy")
-      @server_response = {:node_1 => @node_1, :node_2 => @node_2}
+      @server_response = { :node_1 => @node_1, :node_2 => @node_2 }
       @wrapper = Shell::ModelWrapper.new(Chef::Node)
       allow(Chef::Node).to receive(:list).and_return(@server_response)
     end
@@ -57,7 +57,7 @@ describe Shell::ModelWrapper do
     end
 
     it "maps the listed nodes when given a block" do
-      expect(@wrapper.all {|n| n.name }.sort.reverse).to eq(%w{yummy sammich})
+      expect(@wrapper.all { |n| n.name }.sort.reverse).to eq(%w{yummy sammich})
     end
   end
 
@@ -67,7 +67,7 @@ describe Shell::ModelWrapper do
       @node_1.name("sammich")
       @node_2 = Chef::Node.new
       @node_2.name("yummy")
-      @server_response = {:node_1 => @node_1, :node_2 => @node_2}
+      @server_response = { :node_1 => @node_1, :node_2 => @node_2 }
       @wrapper = Shell::ModelWrapper.new(Chef::Node)
 
       # Creating a Chef::Search::Query object tries to read the private key...
@@ -81,17 +81,16 @@ describe Shell::ModelWrapper do
     end
 
     it "searches for objects using the given query string" do
-      expect(@searcher).to receive(:search).with(:node, 'name:app*').and_yield(@node_1).and_yield(@node_2)
+      expect(@searcher).to receive(:search).with(:node, "name:app*").and_yield(@node_1).and_yield(@node_2)
       expect(@wrapper.find("name:app*")).to include(@node_1, @node_2)
     end
 
     it "creates a 'AND'-joined query string from a HASH" do
       # Hash order woes
-      expect(@searcher).to receive(:search).with(:node, 'name:app* AND name:app*').and_yield(@node_1).and_yield(@node_2)
-      expect(@wrapper.find(:name=>"app*",'name'=>"app*")).to include(@node_1, @node_2)
+      expect(@searcher).to receive(:search).with(:node, "name:app* AND name:app*").and_yield(@node_1).and_yield(@node_2)
+      expect(@wrapper.find(:name => "app*", "name" => "app*")).to include(@node_1, @node_2)
     end
 
   end
 
-
 end
diff --git a/spec/unit/shell/shell_ext_spec.rb b/spec/unit/shell/shell_ext_spec.rb
index 9521ae6..0afa1f6 100644
--- a/spec/unit/shell/shell_ext_spec.rb
+++ b/spec/unit/shell/shell_ext_spec.rb
@@ -1,6 +1,6 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 
 describe Shell::Extensions do
   describe "extending object for top level methods" do
@@ -92,9 +92,9 @@ describe Shell::Extensions do
     end
 
     it "prints node attributes" do
-      node = double("node", :attribute => {:foo => :bar})
+      node = double("node", :attribute => { :foo => :bar })
       @shell_client.node = node
-      expect(@root_context).to receive(:pp).with({:foo => :bar})
+      expect(@root_context).to receive(:pp).with({ :foo => :bar })
       @root_context.ohai
       expect(@root_context).to receive(:pp).with(:bar)
       @root_context.ohai(:foo)
diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb
index d72e3fa..22f3dc6 100644
--- a/spec/unit/shell/shell_session_spec.rb
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,10 +15,9 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 require "ostruct"
 
-
 class TestableShellSession < Shell::ShellSession
 
   def rebuild_node
@@ -49,8 +48,8 @@ end
 
 describe Shell::ClientSession do
   before do
-    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
-    @chef_rest = double("Chef::REST")
+    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
+    @chef_rest = double("Chef::ServerAPI")
     @session = Shell::ClientSession.instance
     @node = Chef::Node.build("foo")
     @session.node = @node
@@ -67,7 +66,7 @@ describe Shell::ClientSession do
     @expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, [])
 
     expect(@node.run_list).to receive(:expand).with(@node.chef_environment).and_return(@expansion)
-    expect(Chef::REST).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
+    expect(Chef::ServerAPI).to receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest)
     @session.rebuild_context
   end
 
@@ -80,7 +79,7 @@ end
 
 describe Shell::StandAloneSession do
   before do
-    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
     @session = Shell::StandAloneSession.instance
     @node = @session.node = Chef::Node.new
     @events = Chef::EventDispatch::Dispatcher.new
@@ -131,7 +130,7 @@ end
 
 describe Shell::SoloSession do
   before do
-    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] }
+    Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new("shell::override")] }
     Chef::Config[:shell_solo] = true
     @session = Shell::SoloSession.instance
     @node = Chef::Node.new
@@ -158,7 +157,7 @@ describe Shell::SoloSession do
   end
 
   it "keeps json attribs and passes them to the node for consumption" do
-    @session.node_attributes = {"besnard_lakes" => "are_the_dark_horse"}
+    @session.node_attributes = { "besnard_lakes" => "are_the_dark_horse" }
     expect(@session.node.besnard_lakes).to eq("are_the_dark_horse")
     #pending "1) keep attribs in an ivar 2) pass them to the node 3) feed them to the node on reset"
   end
diff --git a/spec/unit/shell_out_spec.rb b/spec/unit/shell_out_spec.rb
index 50b0b61..35844f4 100644
--- a/spec/unit/shell_out_spec.rb
+++ b/spec/unit/shell_out_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../spec_helper', __FILE__)
+require File.expand_path("../../spec_helper", __FILE__)
 
 describe "Chef::ShellOut deprecation notices" do
   it "logs a warning when initializing a new Chef::ShellOut object" do
diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb
index acbb189..8ba1afa 100644
--- a/spec/unit/shell_spec.rb
+++ b/spec/unit/shell_spec.rb
@@ -1,5 +1,5 @@
 # Author:: Daniel DeLeo (<dan at kallistec.com>)
-# Copyright:: Copyright (c) 2009 Daniel DeLeo
+# Copyright:: Copyright 2009-2016, Daniel DeLeo
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+require "spec_helper"
 require "ostruct"
 
 ObjectTestHarness = Proc.new do
@@ -43,8 +43,8 @@ describe Shell do
   before do
     Shell.irb_conf = {}
     allow(Shell::ShellSession.instance).to receive(:reset!)
-    allow(Chef::Platform).to receive(:windows?).and_return(false)
-    allow(Chef::Util::PathHelper).to receive(:home).and_return('/home/foo')
+    allow(ChefConfig).to receive(:windows?).and_return(false)
+    allow(Chef::Util::PathHelper).to receive(:home).and_return("/home/foo")
   end
 
   describe "reporting its status" do
@@ -58,7 +58,7 @@ describe Shell do
   describe "configuring IRB" do
     it "configures irb history" do
       Shell.configure_irb
-      expect(Shell.irb_conf[:HISTORY_FILE]).to eq(Chef::Util::PathHelper.home('.chef', 'chef_shell_history'))
+      expect(Shell.irb_conf[:HISTORY_FILE]).to eq(Chef::Util::PathHelper.home(".chef", "chef_shell_history"))
       expect(Shell.irb_conf[:SAVE_HISTORY]).to eq(1000)
     end
 
@@ -71,7 +71,7 @@ describe Shell do
       Shell.irb_conf[:IRB_RC].call(conf)
       expect(conf.prompt_c).to      eq("chef > ")
       expect(conf.return_format).to eq(" => %s \n")
-      expect(conf.prompt_i).to      eq("chef > ")
+      expect(conf.prompt_i).to      eq("chef (#{Chef::VERSION})> ")
       expect(conf.prompt_n).to      eq("chef ?> ")
       expect(conf.prompt_s).to      eq("chef%l> ")
       expect(conf.use_tracer).to    eq(false)
@@ -82,10 +82,10 @@ describe Shell do
 
       conf = OpenStruct.new
       events = Chef::EventDispatch::Dispatcher.new
-      conf.main = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, events))
+      conf.main = Chef::Recipe.new(nil, nil, Chef::RunContext.new(Chef::Node.new, {}, events))
       Shell.irb_conf[:IRB_RC].call(conf)
       expect(conf.prompt_c).to      eq("chef:recipe > ")
-      expect(conf.prompt_i).to      eq("chef:recipe > ")
+      expect(conf.prompt_i).to      eq("chef:recipe (#{Chef::VERSION})> ")
       expect(conf.prompt_n).to      eq("chef:recipe ?> ")
       expect(conf.prompt_s).to      eq("chef:recipe%l> ")
     end
@@ -97,7 +97,7 @@ describe Shell do
       conf.main = Chef::Node.new
       Shell.irb_conf[:IRB_RC].call(conf)
       expect(conf.prompt_c).to      eq("chef:attributes > ")
-      expect(conf.prompt_i).to      eq("chef:attributes > ")
+      expect(conf.prompt_i).to      eq("chef:attributes (#{Chef::VERSION})> ")
       expect(conf.prompt_n).to      eq("chef:attributes ?> ")
       expect(conf.prompt_s).to      eq("chef:attributes%l> ")
     end
@@ -116,7 +116,7 @@ describe Shell do
     end
 
     it "adds help text when a new method is described then defined" do
-      describe_define =<<-EVAL
+      describe_define = <<-EVAL
         desc "foo2the Bar"
         def baz
         end
@@ -127,7 +127,7 @@ describe Shell do
     end
 
     it "adds help text for subcommands" do
-      describe_define =<<-EVAL
+      describe_define = <<-EVAL
         subcommands :baz_obj_command => "something you can do with baz.baz_obj_command"
         def baz
         end
@@ -139,7 +139,7 @@ describe Shell do
     end
 
     it "doesn't add previous subcommand help to commands defined afterward" do
-      describe_define =<<-EVAL
+      describe_define = <<-EVAL
         desc "swingFromTree"
         def monkey_time
         end
@@ -150,7 +150,7 @@ describe Shell do
       EVAL
       @chef_object.instance_eval describe_define
       expect(@chef_object.help_descriptions.size).to eq(2)
-      expect(@chef_object.help_descriptions.select {|h| h.cmd == "super_monkey_time" }).to be_empty
+      expect(@chef_object.help_descriptions.select { |h| h.cmd == "super_monkey_time" }).to be_empty
     end
 
     it "creates a help banner with the command descriptions" do
diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb
index d451531..a1806db 100644
--- a/spec/unit/user_spec.rb
+++ b/spec/unit/user_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Steven Danna (steve at opscode.com)
-# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,15 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
+# DEPRECATION NOTE
+# This code only remains to support users still	operating with
+# Open Source Chef Server 11 and should be removed once support
+# for OSC 11 ends. New development should occur in user_spec.rb.
 
-require 'chef/user'
-require 'tempfile'
+require "spec_helper"
+
+require "chef/user"
+require "tempfile"
 
 describe Chef::User do
   before(:each) do
@@ -55,7 +60,6 @@ describe Chef::User do
       expect { @user.name "foo&" }.to raise_error(ArgumentError)
     end
 
-
     it "should not accept spaces" do
       expect { @user.name "ops master" }.to raise_error(ArgumentError)
     end
@@ -155,7 +159,7 @@ describe Chef::User do
       expect(@json).not_to include("password")
     end
 
-    include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
       let(:jsonable) { @user }
     end
   end
@@ -163,10 +167,10 @@ describe Chef::User do
   describe "when deserializing from JSON" do
     before(:each) do
       user = { "name" => "mr_spinks",
-        "public_key" => "turtles",
-        "private_key" => "pandas",
-        "password" => "password",
-        "admin" => true }
+               "public_key" => "turtles",
+               "private_key" => "pandas",
+               "password" => "password",
+               "admin" => true }
       @user = Chef::User.from_json(Chef::JSONCompat.to_json(user))
     end
 
@@ -200,38 +204,38 @@ describe Chef::User do
     before (:each) do
       @user = Chef::User.new
       @user.name "foobar"
-      @http_client = double("Chef::REST mock")
-      allow(Chef::REST).to receive(:new).and_return(@http_client)
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
     end
 
     describe "list" do
       before(:each) do
         Chef::Config[:chef_server_url] = "http://www.example.com"
-        @osc_response = { "admin" => "http://www.example.com/users/admin"}
-        @ohc_response = [ { "user" => { "username" => "admin" }} ]
+        @osc_response = { "admin" => "http://www.example.com/users/admin" }
+        @ohc_response = [ { "user" => { "username" => "admin" } } ]
         allow(Chef::User).to receive(:load).with("admin").and_return(@user)
         @osc_inflated_response = { "admin" => @user }
       end
 
       it "lists all clients on an OSC server" do
-        allow(@http_client).to receive(:get_rest).with("users").and_return(@osc_response)
+        allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
         expect(Chef::User.list).to eq(@osc_response)
       end
 
       it "inflate all clients on an OSC server" do
-        allow(@http_client).to receive(:get_rest).with("users").and_return(@osc_response)
+        allow(@http_client).to receive(:get).with("users").and_return(@osc_response)
         expect(Chef::User.list(true)).to eq(@osc_inflated_response)
       end
 
       it "lists all clients on an OHC/OPC server" do
-        allow(@http_client).to receive(:get_rest).with("users").and_return(@ohc_response)
+        allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
         # We expect that Chef::User.list will give a consistent response
         # so OHC API responses should be transformed to OSC-style output.
         expect(Chef::User.list).to eq(@osc_response)
       end
 
       it "inflate all clients on an OHC/OPC server" do
-        allow(@http_client).to receive(:get_rest).with("users").and_return(@ohc_response)
+        allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
         expect(Chef::User.list(true)).to eq(@osc_inflated_response)
       end
     end
@@ -239,14 +243,14 @@ describe Chef::User do
     describe "create" do
       it "creates a new user via the API" do
         @user.password "password"
-        expect(@http_client).to receive(:post_rest).with("users", {:name => "foobar", :admin => false, :password => "password"}).and_return({})
+        expect(@http_client).to receive(:post).with("users", { :name => "foobar", :admin => false, :password => "password" }).and_return({})
         @user.create
       end
     end
 
     describe "read" do
       it "loads a named user from the API" do
-        expect(@http_client).to receive(:get_rest).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"})
+        expect(@http_client).to receive(:get).with("users/foobar").and_return({ "name" => "foobar", "admin" => true, "public_key" => "pubkey" })
         user = Chef::User.load("foobar")
         expect(user.name).to eq("foobar")
         expect(user.admin).to eq(true)
@@ -256,14 +260,14 @@ describe Chef::User do
 
     describe "update" do
       it "updates an existing user on via the API" do
-        expect(@http_client).to receive(:put_rest).with("users/foobar", {:name => "foobar", :admin => false}).and_return({})
+        expect(@http_client).to receive(:put).with("users/foobar", { :name => "foobar", :admin => false }).and_return({})
         @user.update
       end
     end
 
     describe "destroy" do
       it "deletes the specified user via the API" do
-        expect(@http_client).to receive(:delete_rest).with("users/foobar")
+        expect(@http_client).to receive(:delete).with("users/foobar")
         @user.destroy
       end
     end
diff --git a/spec/unit/user_v1_spec.rb b/spec/unit/user_v1_spec.rb
new file mode 100644
index 0000000..dd02502
--- /dev/null
+++ b/spec/unit/user_v1_spec.rb
@@ -0,0 +1,583 @@
+#
+# Author:: Steven Danna (steve at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+require "chef/user_v1"
+require "tempfile"
+
+describe Chef::UserV1 do
+  before(:each) do
+    @user = Chef::UserV1.new
+  end
+
+  shared_examples_for "string fields with no contraints" do
+    it "should let you set the public key" do
+      expect(@user.send(method, "some_string")).to eq("some_string")
+    end
+
+    it "should return the current public key" do
+      @user.send(method, "some_string")
+      expect(@user.send(method)).to eq("some_string")
+    end
+
+    it "should throw an ArgumentError if you feed it something lame" do
+      expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError)
+    end
+  end
+
+  shared_examples_for "boolean fields with no constraints" do
+    it "should let you set the field" do
+      expect(@user.send(method, true)).to eq(true)
+    end
+
+    it "should return the current field value" do
+      @user.send(method, true)
+      expect(@user.send(method)).to eq(true)
+    end
+
+    it "should return the false value when false" do
+      @user.send(method, false)
+      expect(@user.send(method)).to eq(false)
+    end
+
+    it "should throw an ArgumentError if you feed it anything but true or false" do
+      expect { @user.send(method, Hash.new) }.to raise_error(ArgumentError)
+    end
+  end
+
+  describe "initialize" do
+    it "should be a Chef::UserV1" do
+      expect(@user).to be_a_kind_of(Chef::UserV1)
+    end
+  end
+
+  describe "username" do
+    it "should let you set the username to a string" do
+      expect(@user.username("ops_master")).to eq("ops_master")
+    end
+
+    it "should return the current username" do
+      @user.username "ops_master"
+      expect(@user.username).to eq("ops_master")
+    end
+
+    # It is not feasible to check all invalid characters.  Here are a few
+    # that we probably care about.
+    it "should not accept invalid characters" do
+      # capital letters
+      expect { @user.username "Bar" }.to raise_error(ArgumentError)
+      # slashes
+      expect { @user.username "foo/bar" }.to raise_error(ArgumentError)
+      # ?
+      expect { @user.username "foo?" }.to raise_error(ArgumentError)
+      # &
+      expect { @user.username "foo&" }.to raise_error(ArgumentError)
+    end
+
+    it "should not accept spaces" do
+      expect { @user.username "ops master" }.to raise_error(ArgumentError)
+    end
+
+    it "should throw an ArgumentError if you feed it anything but a string" do
+      expect { @user.username Hash.new }.to raise_error(ArgumentError)
+    end
+  end
+
+  describe "boolean fields" do
+    describe "create_key" do
+      it_should_behave_like "boolean fields with no constraints" do
+        let(:method) { :create_key }
+      end
+    end
+  end
+
+  describe "string fields" do
+    describe "public_key" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :public_key }
+      end
+    end
+
+    describe "private_key" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :private_key }
+      end
+    end
+
+    describe "display_name" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :display_name }
+      end
+    end
+
+    describe "first_name" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :first_name }
+      end
+    end
+
+    describe "middle_name" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :middle_name }
+      end
+    end
+
+    describe "last_name" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :last_name }
+      end
+    end
+
+    describe "email" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :email }
+      end
+    end
+
+    describe "password" do
+      it_should_behave_like "string fields with no contraints" do
+        let(:method) { :password }
+      end
+    end
+  end
+
+  describe "when serializing to JSON" do
+    before(:each) do
+      @user.username("black")
+      @json = @user.to_json
+    end
+
+    it "serializes as a JSON object" do
+      expect(@json).to match(/^\{.+\}$/)
+    end
+
+    it "includes the username value" do
+      expect(@json).to include(%q{"username":"black"})
+    end
+
+    it "includes the display name when present" do
+      @user.display_name("get_displayed")
+      expect(@user.to_json).to include(%{"display_name":"get_displayed"})
+    end
+
+    it "does not include the display name if not present" do
+      expect(@json).not_to include("display_name")
+    end
+
+    it "includes the first name when present" do
+      @user.first_name("char")
+      expect(@user.to_json).to include(%{"first_name":"char"})
+    end
+
+    it "does not include the first name if not present" do
+      expect(@json).not_to include("first_name")
+    end
+
+    it "includes the middle name when present" do
+      @user.middle_name("man")
+      expect(@user.to_json).to include(%{"middle_name":"man"})
+    end
+
+    it "does not include the middle name if not present" do
+      expect(@json).not_to include("middle_name")
+    end
+
+    it "includes the last name when present" do
+      @user.last_name("der")
+      expect(@user.to_json).to include(%{"last_name":"der"})
+    end
+
+    it "does not include the last name if not present" do
+      expect(@json).not_to include("last_name")
+    end
+
+    it "includes the email when present" do
+      @user.email("charmander at pokemon.poke")
+      expect(@user.to_json).to include(%{"email":"charmander at pokemon.poke"})
+    end
+
+    it "does not include the email if not present" do
+      expect(@json).not_to include("email")
+    end
+
+    it "includes the public key when present" do
+      @user.public_key("crowes")
+      expect(@user.to_json).to include(%{"public_key":"crowes"})
+    end
+
+    it "does not include the public key if not present" do
+      expect(@json).not_to include("public_key")
+    end
+
+    it "includes the private key when present" do
+      @user.private_key("monkeypants")
+      expect(@user.to_json).to include(%q{"private_key":"monkeypants"})
+    end
+
+    it "does not include the private key if not present" do
+      expect(@json).not_to include("private_key")
+    end
+
+    it "includes the password if present" do
+      @user.password "password"
+      expect(@user.to_json).to include(%q{"password":"password"})
+    end
+
+    it "does not include the password if not present" do
+      expect(@json).not_to include("password")
+    end
+
+    include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
+      let(:jsonable) { @user }
+    end
+  end
+
+  describe "when deserializing from JSON" do
+    before(:each) do
+      user = {
+        "username" => "mr_spinks",
+        "display_name" => "displayed",
+        "first_name" => "char",
+        "middle_name" => "man",
+        "last_name" => "der",
+        "email" => "charmander at pokemon.poke",
+        "password" => "password",
+        "public_key" => "turtles",
+        "private_key" => "pandas",
+        "create_key" => false,
+      }
+      @user = Chef::UserV1.from_json(Chef::JSONCompat.to_json(user))
+    end
+
+    it "should deserialize to a Chef::UserV1 object" do
+      expect(@user).to be_a_kind_of(Chef::UserV1)
+    end
+
+    it "preserves the username" do
+      expect(@user.username).to eq("mr_spinks")
+    end
+
+    it "preserves the display name if present" do
+      expect(@user.display_name).to eq("displayed")
+    end
+
+    it "preserves the first name if present" do
+      expect(@user.first_name).to eq("char")
+    end
+
+    it "preserves the middle name if present" do
+      expect(@user.middle_name).to eq("man")
+    end
+
+    it "preserves the last name if present" do
+      expect(@user.last_name).to eq("der")
+    end
+
+    it "preserves the email if present" do
+      expect(@user.email).to eq("charmander at pokemon.poke")
+    end
+
+    it "includes the password if present" do
+      expect(@user.password).to eq("password")
+    end
+
+    it "preserves the public key if present" do
+      expect(@user.public_key).to eq("turtles")
+    end
+
+    it "includes the private key if present" do
+      expect(@user.private_key).to eq("pandas")
+    end
+
+    it "includes the create key status if not nil" do
+      expect(@user.create_key).to be_falsey
+    end
+  end
+
+  describe "Versioned API Interactions" do
+    let(:response_406) { OpenStruct.new(:code => "406") }
+    let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
+
+    before (:each) do
+      @user = Chef::UserV1.new
+      allow(@user).to receive(:chef_root_rest_v0).and_return(double("chef rest root v0 object"))
+      allow(@user).to receive(:chef_root_rest_v1).and_return(double("chef rest root v1 object"))
+    end
+
+    describe "update" do
+      before do
+        # populate all fields that are valid between V0 and V1
+        @user.username "some_username"
+        @user.display_name "some_display_name"
+        @user.first_name "some_first_name"
+        @user.middle_name "some_middle_name"
+        @user.last_name "some_last_name"
+        @user.email "some_email"
+        @user.password "some_password"
+      end
+
+      let(:payload) {
+        {
+          :username => "some_username",
+          :display_name => "some_display_name",
+          :first_name => "some_first_name",
+          :middle_name => "some_middle_name",
+          :last_name => "some_last_name",
+          :email => "some_email",
+          :password => "some_password",
+        }
+      }
+
+      context "when server API V1 is valid on the Chef Server receiving the request" do
+        context "when the user submits valid data" do
+          it "properly updates the user" do
+            expect(@user.chef_root_rest_v1).to receive(:put).with("users/some_username", payload).and_return({})
+            @user.update
+          end
+        end
+      end
+
+      context "when server API V1 is not valid on the Chef Server receiving the request" do
+        let(:payload) {
+          {
+            :username => "some_username",
+            :display_name => "some_display_name",
+            :first_name => "some_first_name",
+            :middle_name => "some_middle_name",
+            :last_name => "some_last_name",
+            :email => "some_email",
+            :password => "some_password",
+            :public_key => "some_public_key",
+          }
+        }
+
+        before do
+          @user.public_key "some_public_key"
+          allow(@user.chef_root_rest_v1).to receive(:put)
+        end
+
+        context "when the server returns a 400" do
+          let(:response_400) { OpenStruct.new(:code => "400") }
+          let(:exception_400) { Net::HTTPServerException.new("400 Bad Request", response_400) }
+
+          context "when the 400 was due to public / private key fields no longer being supported" do
+            let(:response_body_400) { '{"error":["Since Server API v1, all keys must be updated via the keys endpoint. "]}' }
+
+            before do
+              allow(response_400).to receive(:body).and_return(response_body_400)
+              allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
+            end
+
+            it "proceeds with the V0 PUT since it can handle public / private key fields" do
+              expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({})
+              @user.update
+            end
+
+            it "does not call server_client_api_version_intersection, since we know to proceed with V0 in this case" do
+              expect(@user).to_not receive(:server_client_api_version_intersection)
+              allow(@user.chef_root_rest_v0).to receive(:put).and_return({})
+              @user.update
+            end
+          end # when the 400 was due to public / private key fields
+
+          context "when the 400 was NOT due to public / private key fields no longer being supported" do
+            let(:response_body_400) { '{"error":["Some other error. "]}' }
+
+            before do
+              allow(response_400).to receive(:body).and_return(response_body_400)
+              allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_400)
+            end
+
+            it "will not proceed with the V0 PUT since the original bad request was not key related" do
+              expect(@user.chef_root_rest_v0).to_not receive(:put).with("users/some_username", payload)
+              expect { @user.update }.to raise_error(exception_400)
+            end
+
+            it "raises the original error" do
+              expect { @user.update }.to raise_error(exception_400)
+            end
+
+          end
+        end # when the server returns a 400
+
+        context "when the server returns a 406" do
+          # from spec/support/shared/unit/api_versioning.rb
+          it_should_behave_like "version handling" do
+            let(:object)    { @user }
+            let(:method)    { :update }
+            let(:http_verb) { :put }
+            let(:rest_v1)   { @user.chef_root_rest_v1 }
+          end
+
+          context "when the server supports API V0" do
+            before do
+              allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
+              allow(@user.chef_root_rest_v1).to receive(:put).and_raise(exception_406)
+            end
+
+            it "properly updates the user" do
+              expect(@user.chef_root_rest_v0).to receive(:put).with("users/some_username", payload).and_return({})
+              @user.update
+            end
+          end # when the server supports API V0
+        end # when the server returns a 406
+
+      end # when server API V1 is not valid on the Chef Server receiving the request
+    end # update
+
+    describe "create" do
+      let(:payload) {
+        {
+          :username => "some_username",
+          :display_name => "some_display_name",
+          :first_name => "some_first_name",
+          :last_name => "some_last_name",
+          :email => "some_email",
+          :password => "some_password",
+        }
+      }
+      before do
+        @user.username "some_username"
+        @user.display_name "some_display_name"
+        @user.first_name "some_first_name"
+        @user.last_name "some_last_name"
+        @user.email "some_email"
+        @user.password "some_password"
+      end
+
+      # from spec/support/shared/unit/user_and_client_shared.rb
+      it_should_behave_like "user or client create" do
+        let(:object)  { @user }
+        let(:error)   { Chef::Exceptions::InvalidUserAttribute }
+        let(:rest_v0) { @user.chef_root_rest_v0 }
+        let(:rest_v1) { @user.chef_root_rest_v1 }
+        let(:url)     { "users" }
+      end
+
+      context "when handling API V1" do
+        it "creates a new user via the API with a middle_name when it exists" do
+          @user.middle_name "some_middle_name"
+          expect(@user.chef_root_rest_v1).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
+          @user.create
+        end
+      end # when server API V1 is valid on the Chef Server receiving the request
+
+      context "when API V1 is not supported by the server" do
+        # from spec/support/shared/unit/api_versioning.rb
+        it_should_behave_like "version handling" do
+          let(:object)    { @user }
+          let(:method)    { :create }
+          let(:http_verb) { :post }
+          let(:rest_v1)   { @user.chef_root_rest_v1 }
+        end
+      end
+
+      context "when handling API V0" do
+        before do
+          allow(@user).to receive(:server_client_api_version_intersection).and_return([0])
+          allow(@user.chef_root_rest_v1).to receive(:post).and_raise(exception_406)
+        end
+
+        it "creates a new user via the API with a middle_name when it exists" do
+          @user.middle_name "some_middle_name"
+          expect(@user.chef_root_rest_v0).to receive(:post).with("users", payload.merge({ :middle_name => "some_middle_name" })).and_return({})
+          @user.create
+        end
+      end # when server API V1 is not valid on the Chef Server receiving the request
+
+    end # create
+
+    # DEPRECATION
+    # This can be removed after API V0 support is gone
+    describe "reregister" do
+      let(:payload) {
+        {
+          "username" => "some_username"
+        }
+      }
+
+      before do
+        @user.username "some_username"
+      end
+
+      context "when server API V0 is valid on the Chef Server receiving the request" do
+        it "creates a new object via the API" do
+          expect(@user.chef_root_rest_v0).to receive(:put).with("users/#{@user.username}", payload.merge({ "private_key" => true })).and_return({})
+          @user.reregister
+        end
+      end # when server API V0 is valid on the Chef Server receiving the request
+
+      context "when server API V0 is not supported by the Chef Server" do
+        # from spec/support/shared/unit/api_versioning.rb
+        it_should_behave_like "user and client reregister" do
+          let(:object)    { @user }
+          let(:rest_v0)   { @user.chef_root_rest_v0 }
+        end
+      end # when server API V0 is not supported by the Chef Server
+    end # reregister
+
+  end # Versioned API Interactions
+
+  describe "API Interactions" do
+    before (:each) do
+      @user = Chef::UserV1.new
+      @user.username "foobar"
+      @http_client = double("Chef::ServerAPI mock")
+      allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
+    end
+
+    describe "list" do
+      before(:each) do
+        Chef::Config[:chef_server_url] = "http://www.example.com"
+        @osc_response = { "admin" => "http://www.example.com/users/admin" }
+        @ohc_response = [ { "user" => { "username" => "admin" } } ]
+        allow(Chef::UserV1).to receive(:load).with("admin").and_return(@user)
+        @osc_inflated_response = { "admin" => @user }
+      end
+
+      it "lists all clients on an OHC/OPC server" do
+        allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
+        # We expect that Chef::UserV1.list will give a consistent response
+        # so OHC API responses should be transformed to OSC-style output.
+        expect(Chef::UserV1.list).to eq(@osc_response)
+      end
+
+      it "inflate all clients on an OHC/OPC server" do
+        allow(@http_client).to receive(:get).with("users").and_return(@ohc_response)
+        expect(Chef::UserV1.list(true)).to eq(@osc_inflated_response)
+      end
+    end
+
+    describe "read" do
+      it "loads a named user from the API" do
+        expect(@http_client).to receive(:get).with("users/foobar").and_return({ "username" => "foobar", "admin" => true, "public_key" => "pubkey" })
+        user = Chef::UserV1.load("foobar")
+        expect(user.username).to eq("foobar")
+        expect(user.public_key).to eq("pubkey")
+      end
+    end
+
+    describe "destroy" do
+      it "deletes the specified user via the API" do
+        expect(@http_client).to receive(:delete).with("users/foobar")
+        @user.destroy
+      end
+    end
+  end
+end
diff --git a/spec/unit/util/backup_spec.rb b/spec/unit/util/backup_spec.rb
index f548e82..3454e07 100644
--- a/spec/unit/util/backup_spec.rb
+++ b/spec/unit/util/backup_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 describe Chef::Util::Backup do
 
@@ -71,15 +70,15 @@ describe Chef::Util::Backup do
       end
 
       it "should not delete anything if this is the only backup" do
-        expect(@backup).to receive(:sorted_backup_files).and_return(['a'])
+        expect(@backup).to receive(:sorted_backup_files).and_return(["a"])
         expect(@backup).not_to receive(:delete_backup)
         @backup.backup!
       end
 
       it "should keep only 1 backup copy" do
-        expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b', 'c'])
-        expect(@backup).to receive(:delete_backup).with('b')
-        expect(@backup).to receive(:delete_backup).with('c')
+        expect(@backup).to receive(:sorted_backup_files).and_return(["a", "b", "c"])
+        expect(@backup).to receive(:delete_backup).with("b")
+        expect(@backup).to receive(:delete_backup).with("c")
         @backup.backup!
       end
     end
@@ -90,15 +89,15 @@ describe Chef::Util::Backup do
       end
 
       it "should not delete anything if we only have one other backup" do
-        expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b'])
+        expect(@backup).to receive(:sorted_backup_files).and_return(["a", "b"])
         expect(@backup).not_to receive(:delete_backup)
         @backup.backup!
       end
 
       it "should keep only 2 backup copies" do
-        expect(@backup).to receive(:sorted_backup_files).and_return(['a', 'b', 'c', 'd'])
-        expect(@backup).to receive(:delete_backup).with('c')
-        expect(@backup).to receive(:delete_backup).with('d')
+        expect(@backup).to receive(:sorted_backup_files).and_return(["a", "b", "c", "d"])
+        expect(@backup).to receive(:delete_backup).with("c")
+        expect(@backup).to receive(:delete_backup).with("d")
         @backup.backup!
       end
     end
@@ -106,7 +105,7 @@ describe Chef::Util::Backup do
 
   describe "backup_filename" do
     it "should return a timestamped path" do
-      expect(@backup).to receive(:path).and_return('/a/b/c.txt')
+      expect(@backup).to receive(:path).and_return("/a/b/c.txt")
       expect(@backup.send(:backup_filename)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
     end
     it "should strip the drive letter off for windows" do
@@ -114,21 +113,21 @@ describe Chef::Util::Backup do
       expect(@backup.send(:backup_filename)).to match(%r|^\\a\\b\\c.txt.chef-\d{14}.\d{6}$|)
     end
     it "should strip the drive letter off for windows (with forwardslashes)" do
-      expect(@backup).to receive(:path).and_return('c:/a/b/c.txt')
+      expect(@backup).to receive(:path).and_return("c:/a/b/c.txt")
       expect(@backup.send(:backup_filename)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
     end
   end
 
   describe "backup_path" do
     it "uses the file's directory when Chef::Config[:file_backup_path] is nil" do
-      expect(@backup).to receive(:path).and_return('/a/b/c.txt')
+      expect(@backup).to receive(:path).and_return("/a/b/c.txt")
       Chef::Config[:file_backup_path] = nil
       expect(@backup.send(:backup_path)).to match(%r|^/a/b/c.txt.chef-\d{14}.\d{6}$|)
     end
 
     it "uses the configured Chef::Config[:file_backup_path]" do
-      expect(@backup).to receive(:path).and_return('/a/b/c.txt')
-      Chef::Config[:file_backup_path] = '/backupdir'
+      expect(@backup).to receive(:path).and_return("/a/b/c.txt")
+      Chef::Config[:file_backup_path] = "/backupdir"
       expect(@backup.send(:backup_path)).to match(%r|^/backupdir[\\/]+a/b/c.txt.chef-\d{14}.\d{6}$|)
     end
 
diff --git a/spec/unit/util/diff_spec.rb b/spec/unit/util/diff_spec.rb
index b0a57a3..29c645b 100644
--- a/spec/unit/util/diff_spec.rb
+++ b/spec/unit/util/diff_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Lamont Granquist (<lamont at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Lamont Granquist (<lamont at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,8 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
-require 'tmpdir'
+require "spec_helper"
+require "tmpdir"
 
 shared_context "using file paths with spaces" do
   let!(:old_tempfile) { Tempfile.new("chef-util diff-spec") }
@@ -553,11 +552,11 @@ describe Chef::Util::Diff, :uses_diff => true do
 
   let(:plain_ascii) { "This is a text file.\nWith more than one line.\nAnd a \tTab.\nAnd lets make sure that other printable chars work too: ~!@\#$%^&*()`:\"<>?{}|_+,./;'[]\\-=\n" }
   # these are all byte sequences that are illegal in the other encodings... (but they may legally transcode)
-  let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" }  # unicode em-dash
+  let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" } # unicode em-dash
   let(:latin_1) { "It is more metal.\nif you have an \xFDmlaut.\n" } # NB: changed to y-with-diaresis, but i'm American so I don't know the difference
   let(:shift_jis) { "I have no idea what this character is:\n \x83\x80.\n" } # seriously, no clue, but \x80 is nice and illegal in other encodings
 
-  let(:differ) do  # subject
+  let(:differ) do # subject
     differ = Chef::Util::Diff.new
     differ.diff(old_file, new_file)
     differ
@@ -569,11 +568,9 @@ describe Chef::Util::Diff, :uses_diff => true do
     it_behaves_like "a diff util"
   end
 
-
   describe "when file path doesn't have spaces" do
     include_context "using file paths without spaces"
 
     it_behaves_like "a diff util"
   end
 end
-
diff --git a/spec/unit/util/dsc/configuration_generator_spec.rb b/spec/unit/util/dsc/configuration_generator_spec.rb
index 9fbd3aa..d59423e 100644
--- a/spec/unit/util/dsc/configuration_generator_spec.rb
+++ b/spec/unit/util/dsc/configuration_generator_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Jay Mundrawala <jmundrawala at getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Jay Mundrawala <jmundrawala at chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,25 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/dsc/configuration_generator'
+require "chef"
+require "chef/util/dsc/configuration_generator"
 
 describe Chef::Util::DSC::ConfigurationGenerator do
   let(:conf_man) do
     node = Chef::Node.new
-    Chef::Util::DSC::ConfigurationGenerator.new(node, 'tmp')
+    Chef::Util::DSC::ConfigurationGenerator.new(node, "tmp")
   end
 
   describe '#validate_configuration_name!' do
-    it 'should not raise an error if a name contains all upper case letters' do
+    it "should not raise an error if a name contains all upper case letters" do
       conf_man.send(:validate_configuration_name!, "HELLO")
     end
 
-    it 'should not raise an error if the name contains all lower case letters' do
+    it "should not raise an error if the name contains all lower case letters" do
       conf_man.send(:validate_configuration_name!, "hello")
     end
 
-    it 'should not raise an error if no special characters are used except _' do
+    it "should not raise an error if no special characters are used except _" do
       conf_man.send(:validate_configuration_name!, "hello_world")
     end
 
@@ -48,67 +48,67 @@ describe Chef::Util::DSC::ConfigurationGenerator do
   end
 
   describe "#get_merged_configuration_flags" do
-    context 'when strings are used as switches' do
-      it 'should merge the hash if there are no restricted switches' do
-        merged = conf_man.send(:get_merged_configuration_flags!, {'flag' => 'a'}, 'hello')
+    context "when strings are used as switches" do
+      it "should merge the hash if there are no restricted switches" do
+        merged = conf_man.send(:get_merged_configuration_flags!, { "flag" => "a" }, "hello")
         expect(merged).to include(:flag)
-        expect(merged[:flag]).to eql('a')
+        expect(merged[:flag]).to eql("a")
         expect(merged).to include(:outputpath)
       end
 
-      it 'should raise an ArgumentError if you try to override outputpath' do
+      it "should raise an ArgumentError if you try to override outputpath" do
         expect {
-          conf_man.send(:get_merged_configuration_flags!, {'outputpath' => 'a'}, 'hello')
+          conf_man.send(:get_merged_configuration_flags!, { "outputpath" => "a" }, "hello")
         }.to raise_error(ArgumentError)
       end
 
-      it 'should be case insensitive for switches that are not allowed' do
+      it "should be case insensitive for switches that are not allowed" do
         expect {
-          conf_man.send(:get_merged_configuration_flags!, {'OutputPath' => 'a'}, 'hello')
+          conf_man.send(:get_merged_configuration_flags!, { "OutputPath" => "a" }, "hello")
         }.to raise_error(ArgumentError)
       end
 
-      it 'should be case insensitive to switches that are allowed' do
-        merged = conf_man.send(:get_merged_configuration_flags!, {'FLAG' => 'a'}, 'hello')
+      it "should be case insensitive to switches that are allowed" do
+        merged = conf_man.send(:get_merged_configuration_flags!, { "FLAG" => "a" }, "hello")
         expect(merged).to include(:flag)
       end
     end
 
-    context 'when symbols are used as switches' do
-      it 'should merge the hash if there are no restricted switches' do
-        merged = conf_man.send(:get_merged_configuration_flags!, {:flag => 'a'}, 'hello')
+    context "when symbols are used as switches" do
+      it "should merge the hash if there are no restricted switches" do
+        merged = conf_man.send(:get_merged_configuration_flags!, { :flag => "a" }, "hello")
         expect(merged).to include(:flag)
-        expect(merged[:flag]).to eql('a')
+        expect(merged[:flag]).to eql("a")
         expect(merged).to include(:outputpath)
       end
 
-      it 'should raise an ArgumentError if you try to override outputpath' do
+      it "should raise an ArgumentError if you try to override outputpath" do
         expect {
-          conf_man.send(:get_merged_configuration_flags!, {:outputpath => 'a'}, 'hello')
+          conf_man.send(:get_merged_configuration_flags!, { :outputpath => "a" }, "hello")
         }.to raise_error(ArgumentError)
       end
 
-      it 'should be case insensitive for switches that are not allowed' do
+      it "should be case insensitive for switches that are not allowed" do
         expect {
-          conf_man.send(:get_merged_configuration_flags!, {:OutputPath => 'a'}, 'hello')
+          conf_man.send(:get_merged_configuration_flags!, { :OutputPath => "a" }, "hello")
         }.to raise_error(ArgumentError)
       end
 
-      it 'should be case insensitive to switches that are allowed' do
-        merged = conf_man.send(:get_merged_configuration_flags!, {:FLAG => 'a'}, 'hello')
+      it "should be case insensitive to switches that are allowed" do
+        merged = conf_man.send(:get_merged_configuration_flags!, { :FLAG => "a" }, "hello")
         expect(merged).to include(:flag)
       end
     end
 
-    context 'when there are no flags' do
-      it 'should supply an output path if configuration_flags is an empty hash' do
-        merged = conf_man.send(:get_merged_configuration_flags!, {}, 'hello')
+    context "when there are no flags" do
+      it "should supply an output path if configuration_flags is an empty hash" do
+        merged = conf_man.send(:get_merged_configuration_flags!, {}, "hello")
         expect(merged).to include(:outputpath)
         expect(merged.length).to eql(1)
       end
 
-      it 'should supply an output path if configuration_flags is an empty hash' do
-        merged = conf_man.send(:get_merged_configuration_flags!, nil, 'hello')
+      it "should supply an output path if configuration_flags is an empty hash" do
+        merged = conf_man.send(:get_merged_configuration_flags!, nil, "hello")
         expect(merged).to include(:outputpath)
         expect(merged.length).to eql(1)
       end
@@ -127,10 +127,10 @@ describe Chef::Util::DSC::ConfigurationGenerator do
     it "should write the input to a file" do
       allow(File).to receive(:open).and_yield(file_like_object)
       allow(File).to receive(:join) do |a, b|
-        [a,b].join("++")
+        [a, b].join("++")
       end
       allow(file_like_object).to receive(:write)
-      conf_man.send(:write_document_generation_script, 'file', 'hello', {})
+      conf_man.send(:write_document_generation_script, "file", "hello", {})
       expect(file_like_object).to have_received(:write)
     end
   end
@@ -140,27 +140,27 @@ describe Chef::Util::DSC::ConfigurationGenerator do
       # These tests seem way too implementation specific. Unfortunately, File and Dir
       # need to be mocked because they are OS specific
       allow(File).to receive(:join) do |a, b|
-        [a,b].join("++")
+        [a, b].join("++")
       end
 
-      allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'hello.mof', 'f3']}
-      expect(conf_man.send(:find_configuration_document, 'hello')).to eql('tmp++hello++hello.mof')
+      allow(Dir).to receive(:entries).with("tmp++hello") { ["f1", "f2", "hello.mof", "f3"] }
+      expect(conf_man.send(:find_configuration_document, "hello")).to eql("tmp++hello++hello.mof")
     end
 
     it "should return nil if the mof file is not found" do
       allow(File).to receive(:join) do |a, b|
-        [a,b].join("++")
+        [a, b].join("++")
       end
-      allow(Dir).to receive(:entries).with("tmp++hello") {['f1', 'f2', 'f3']}
-      expect(conf_man.send(:find_configuration_document, 'hello')).to be_nil
+      allow(Dir).to receive(:entries).with("tmp++hello") { ["f1", "f2", "f3"] }
+      expect(conf_man.send(:find_configuration_document, "hello")).to be_nil
     end
   end
 
   describe "#configuration_code" do
     it "should build dsc" do
-      dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {})
+      dsc = conf_man.send(:configuration_code, "archive{}", "hello", {})
       found_configuration = false
-      dsc.split(';').each do |command|
+      dsc.split(";").each do |command|
         if command.downcase =~ /\s*configuration\s+'hello'\s*\{\s*node\s+'localhost'\s*\{\s*archive\s*\{\s*\}\s*\}\s*\}\s*/
           found_configuration = true
         end
@@ -169,25 +169,25 @@ describe Chef::Util::DSC::ConfigurationGenerator do
     end
     context "with imports" do
       it "should import all resources when a module has an empty list" do
-        dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => []})
+        dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => [] })
         expect(dsc).to match(/Import-DscResource -ModuleName FooModule\s*\n/)
       end
 
       it "should import all resources when a module has a list with *" do
-        dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', '*', 'BarResource']})
+        dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => ["FooResource", "*", "BarResource"] })
         expect(dsc).to match(/Import-DscResource -ModuleName FooModule\s*\n/)
       end
 
       it "should import specific resources when a module has list without * that is not empty" do
-        dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', 'BarResource']})
+        dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => ["FooResource", "BarResource"] })
         expect(dsc).to match(/Import-DscResource -ModuleName FooModule -Name FooResource,BarResource/)
       end
 
       it "should import multiple modules with multiple import statements" do
-        dsc = conf_man.send(:configuration_code, 'archive{}', 'hello', {'FooModule' => ['FooResource', 'BarResource'], 'BazModule' => []})
+        dsc = conf_man.send(:configuration_code, "archive{}", "hello", { "FooModule" => ["FooResource", "BarResource"], "BazModule" => [] })
         expect(dsc).to match(/Import-DscResource -ModuleName FooModule -Name FooResource,BarResource/)
         expect(dsc).to match(/Import-DscResource -ModuleName BazModule\s*\n/)
-      end 
+      end
     end
   end
 end
diff --git a/spec/unit/util/dsc/lcm_output_parser_spec.rb b/spec/unit/util/dsc/lcm_output_parser_spec.rb
index 3d44e07..69eb872 100644
--- a/spec/unit/util/dsc/lcm_output_parser_spec.rb
+++ b/spec/unit/util/dsc/lcm_output_parser_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,24 @@
 # limitations under the License.
 #
 
-require 'chef/util/dsc/lcm_output_parser'
+require "chef/util/dsc/lcm_output_parser"
 
 describe Chef::Util::DSC::LocalConfigurationManager::Parser do
-  context 'empty input parameter' do
-    it 'raises an exception when there are no valid lines' do
+  context "empty input parameter" do
+    it "raises an exception when there are no valid lines" do
       str = <<-EOF
-                
+
       EOF
-      expect {Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)}.to raise_error(Chef::Exceptions::LCMParser)
+      expect { Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) }.to raise_error(Chef::Exceptions::LCMParser)
     end
 
-    it 'raises an exception for a nil input' do
-      expect {Chef::Util::DSC::LocalConfigurationManager::Parser::parse(nil)}.to raise_error(Chef::Exceptions::LCMParser)
+    it "raises an exception for a nil input" do
+      expect { Chef::Util::DSC::LocalConfigurationManager::Parser::parse(nil) }.to raise_error(Chef::Exceptions::LCMParser)
     end
   end
 
-  context 'correctly formatted output from lcm' do
-    it 'returns a single resource when only 1 logged with the correct name' do
+  context "correctly formatted output from lcm" do
+    it "returns a single resource when only 1 logged with the correct name" do
       str = <<EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ] [name]
@@ -42,10 +42,10 @@ logtype: [machinename]: LCM:  [ End    Set      ]
 EOF
       resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
       expect(resources.length).to eq(1)
-      expect(resources[0].name).to eq('[name]')
+      expect(resources[0].name).to eq("[name]")
     end
 
-    it 'identifies when a resource changes the state of the system' do
+    it "identifies when a resource changes the state of the system" do
       str = <<EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ] [name]
@@ -58,7 +58,7 @@ EOF
       expect(resources[0].changes_state?).to be_truthy
     end
 
-    it 'preserves the log provided for how the system changed the state' do
+    it "preserves the log provided for how the system changed the state" do
       str = <<EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ] [name]
@@ -69,10 +69,10 @@ logtype: [machinename]: LCM:  [ End    Resource ] [name]
 logtype: [machinename]: LCM:  [ End    Set      ]
 EOF
       resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
-      expect(resources[0].change_log).to match_array(["[name]","[message]","[name]"])
+      expect(resources[0].change_log).to match_array(["[name]", "[message]", "[name]"])
     end
 
-    it 'should return false for changes_state?' do
+    it "should return false for changes_state?" do
       str = <<EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ] [name]
@@ -84,7 +84,7 @@ EOF
       expect(resources[0].changes_state?).to be_falsey
     end
 
-    it 'should return an empty array for change_log if changes_state? is false' do
+    it "should return an empty array for change_log if changes_state? is false" do
       str = <<EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ] [name]
@@ -97,8 +97,8 @@ EOF
     end
   end
 
-  context 'Incorrectly formatted output from LCM' do
-    it 'should allow missing a [End Resource] when its the last one and still find all the resource' do
+  context "Incorrectly formatted output from LCM" do
+    it "should allow missing a [End Resource] when its the last one and still find all the resource" do
       str = <<-EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ]  [name]
@@ -119,7 +119,7 @@ EOF
       expect(resources[1].changes_state?).to be_truthy
     end
 
-    it 'should allow missing a [End Resource] when its the first one and still find all the resource' do
+    it "should allow missing a [End Resource] when its the first one and still find all the resource" do
       str = <<-EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ]  [name]
@@ -140,7 +140,7 @@ EOF
       expect(resources[1].changes_state?).to be_truthy
     end
 
-    it 'should allow missing set and end resource and assume an unconverged resource in this case' do
+    it "should allow missing set and end resource and assume an unconverged resource in this case" do
       str = <<-EOF
 logtype: [machinename]: LCM:  [ Start  Set      ]
 logtype: [machinename]: LCM:  [ Start  Resource ]  [name]
@@ -156,9 +156,9 @@ logtype: [machinename]: LCM:  [ End    Set      ]
 EOF
       resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str)
       expect(resources[0].changes_state?).to be_truthy
-      expect(resources[0].name).to eql('[name]')
+      expect(resources[0].name).to eql("[name]")
       expect(resources[1].changes_state?).to be_truthy
-      expect(resources[1].name).to eql('[name2]')
+      expect(resources[1].name).to eql("[name2]")
     end
   end
 end
diff --git a/spec/unit/util/dsc/local_configuration_manager_spec.rb b/spec/unit/util/dsc/local_configuration_manager_spec.rb
index 1cff9e4..15cf383 100644
--- a/spec/unit/util/dsc/local_configuration_manager_spec.rb
+++ b/spec/unit/util/dsc/local_configuration_manager_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Adam Edwards <adamed at getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Adam Edwards <adamed at chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,12 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/dsc/local_configuration_manager'
+require "chef"
+require "chef/util/dsc/local_configuration_manager"
 
 describe Chef::Util::DSC::LocalConfigurationManager do
 
-  let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, 'tmp') }
+  let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, "tmp") }
 
   let(:normal_lcm_output) { <<-EOH
 logtype: [machinename]: LCM:  [ Start  Set      ]
@@ -50,12 +50,12 @@ EOH
     double("LCM cmdlet status", :stderr => lcm_standard_error, :return_value => lcm_standard_output, :succeeded? => lcm_cmdlet_success)
   }
 
-  describe 'test_configuration method invocation' do
-    context 'when interacting with the LCM using a PowerShell cmdlet' do
+  describe "test_configuration method invocation" do
+    context "when interacting with the LCM using a PowerShell cmdlet" do
       before(:each) do
         allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
       end
-      context 'that returns successfully' do
+      context "that returns successfully" do
         before(:each) do
           allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status)
         end
@@ -64,16 +64,16 @@ EOH
         let(:lcm_standard_error) { nil }
         let(:lcm_cmdlet_success) { true }
 
-        it 'should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds' do
-          test_configuration_result = lcm.test_configuration('config', {})
+        it "should successfully return resource information for normally formatted output when cmdlet the cmdlet succeeds" do
+          test_configuration_result = lcm.test_configuration("config", {})
           expect(test_configuration_result.class).to be(Array)
           expect(test_configuration_result.length).to be > 0
           expect(Chef::Log).not_to receive(:warn)
         end
       end
 
-      context 'that fails due to missing what-if switch in DSC resource cmdlet implementation' do
-        let(:lcm_standard_output) { '' }
+      context "that fails due to missing what-if switch in DSC resource cmdlet implementation" do
+        let(:lcm_standard_output) { "" }
         let(:lcm_standard_error) { no_whatif_lcm_output }
         let(:lcm_cmdlet_success) { false }
 
@@ -81,59 +81,58 @@ EOH
           expect(lcm.send(:whatif_not_supported?, no_whatif_lcm_output)).to be_truthy
         end
 
-        it 'should should return a (possibly empty) array of ResourceInfo instances' do
+        it "should should return a (possibly empty) array of ResourceInfo instances" do
           expect(Chef::Log).to receive(:warn).at_least(:once)
           expect(lcm).to receive(:whatif_not_supported?).and_call_original
           test_configuration_result = nil
-          expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+          expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
           expect(test_configuration_result.class).to be(Array)
         end
       end
 
-      context 'that fails due to a DSC resource not being imported before StartDSCConfiguration -whatif is executed' do
-        let(:lcm_standard_output) { '' }
+      context "that fails due to a DSC resource not being imported before StartDSCConfiguration -whatif is executed" do
+        let(:lcm_standard_output) { "" }
         let(:lcm_standard_error) { dsc_resource_import_failure_output }
         let(:lcm_cmdlet_success) { false }
 
-        it 'should log a warning if the message is formatted as expected when a resource import failure occurs' do
+        it "should log a warning if the message is formatted as expected when a resource import failure occurs" do
           expect(Chef::Log).to receive(:warn).at_least(:once)
           expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
           test_configuration_result = nil
-          expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+          expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
         end
 
-        it 'should return a (possibly empty) array of ResourceInfo instances' do
+        it "should return a (possibly empty) array of ResourceInfo instances" do
           expect(Chef::Log).to receive(:warn).at_least(:once)
           test_configuration_result = nil
-          expect {test_configuration_result = lcm.test_configuration('config', {})}.not_to raise_error
+          expect { test_configuration_result = lcm.test_configuration("config", {}) }.not_to raise_error
           expect(test_configuration_result.class).to be(Array)
         end
       end
 
-      context 'that fails due to an unknown PowerShell cmdlet error' do
-        let(:lcm_standard_output) { 'some output' }
-        let(:lcm_standard_error) { 'Abort, Retry, Fail?' }
+      context "that fails due to an unknown PowerShell cmdlet error" do
+        let(:lcm_standard_output) { "some output" }
+        let(:lcm_standard_error) { "Abort, Retry, Fail?" }
         let(:lcm_cmdlet_success) { false }
 
-        it 'should log a warning' do
+        it "should log a warning" do
           expect(Chef::Log).to receive(:warn).at_least(:once)
           expect(lcm).to receive(:dsc_module_import_failure?).and_call_original
-          expect {lcm.test_configuration('config', {})}.not_to raise_error
+          expect { lcm.test_configuration("config", {}) }.not_to raise_error
         end
       end
     end
 
-    it 'should identify a correctly formatted error message as a resource import failure' do
+    it "should identify a correctly formatted error message as a resource import failure" do
       expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output)).to be(true)
     end
 
-    it 'should not identify an incorrectly formatted error message as a resource import failure' do
-      expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('module', 'gibberish'))).to be(false)
+    it "should not identify an incorrectly formatted error message as a resource import failure" do
+      expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub("module", "gibberish"))).to be(false)
     end
 
-    it 'should not identify a message without a CimException reference as a resource import failure' do
-      expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false)
+    it "should not identify a message without a CimException reference as a resource import failure" do
+      expect(lcm.send(:dsc_module_import_failure?, dsc_resource_import_failure_output.gsub("CimException", "ArgumentException"))).to be(false)
     end
   end
 end
-
diff --git a/spec/unit/util/dsc/resource_store.rb b/spec/unit/util/dsc/resource_store.rb
index a89e73f..84b3919 100644
--- a/spec/unit/util/dsc/resource_store.rb
+++ b/spec/unit/util/dsc/resource_store.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala <jdm at chef.io>
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,61 +16,61 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/dsc/resource_store'
+require "chef"
+require "chef/util/dsc/resource_store"
 
 describe Chef::Util::DSC::ResourceStore do
   let(:resource_store) { Chef::Util::DSC::ResourceStore.new }
   let(:resource_a) { {
-    'ResourceType' => 'AFoo',
-    'Name' => 'Foo',
-    'Module' => {'Name' => 'ModuleA'}
+    "ResourceType" => "AFoo",
+    "Name" => "Foo",
+    "Module" => { "Name" => "ModuleA" },
     }
   }
 
   let(:resource_b) { {
-    'ResourceType' => 'BFoo',
-    'Name' => 'Foo',
-    'Module' => {'Name' => 'ModuleB'}
+    "ResourceType" => "BFoo",
+    "Name" => "Foo",
+    "Module" => { "Name" => "ModuleB" },
     }
   }
 
-  context 'when resources are not cached' do
+  context "when resources are not cached" do
     context 'when calling #resources' do
-      it 'returns an empty array' do
+      it "returns an empty array" do
         expect(resource_store.resources).to eql([])
       end
     end
 
     context 'when calling #find' do
-      it 'returns an empty list if it cannot find any matching resources' do
+      it "returns an empty list if it cannot find any matching resources" do
         expect(resource_store).to receive(:query_resource).and_return([])
-        expect(resource_store.find('foo')).to eql([])
+        expect(resource_store.find("foo")).to eql([])
       end
 
-      it 'returns the resource if it is found (comparisons are case insensitive)' do
+      it "returns the resource if it is found (comparisons are case insensitive)" do
         expect(resource_store).to receive(:query_resource).and_return([resource_a])
-        expect(resource_store.find('foo')).to eql([resource_a])
+        expect(resource_store.find("foo")).to eql([resource_a])
       end
 
-      it 'returns multiple resoures if they are found' do
+      it "returns multiple resoures if they are found" do
         expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_b])
-        expect(resource_store.find('foo')).to include(resource_a, resource_b)
+        expect(resource_store.find("foo")).to include(resource_a, resource_b)
       end
 
-      it 'deduplicates resources by ResourceName' do
+      it "deduplicates resources by ResourceName" do
         expect(resource_store).to receive(:query_resource).and_return([resource_a, resource_a])
-        resource_store.find('foo')
+        resource_store.find("foo")
         expect(resource_store.resources).to eq([resource_a])
       end
     end
   end
 
-  context 'when resources are cached' do
-    it 'recalls resources from the cache if present' do
+  context "when resources are cached" do
+    it "recalls resources from the cache if present" do
       expect(resource_store).not_to receive(:query_resource)
       expect(resource_store).to receive(:resources).and_return([resource_a])
-      resource_store.find('foo')
+      resource_store.find("foo")
     end
   end
 end
diff --git a/spec/unit/util/editor_spec.rb b/spec/unit/util/editor_spec.rb
index 968302d..9db7e85 100644
--- a/spec/unit/util/editor_spec.rb
+++ b/spec/unit/util/editor_spec.rb
@@ -1,14 +1,14 @@
-require 'spec_helper'
-require 'chef/util/editor'
+require "spec_helper"
+require "chef/util/editor"
 
 describe Chef::Util::Editor do
   describe '#initialize' do
-    it 'takes an Enumerable of lines' do
+    it "takes an Enumerable of lines" do
       editor = described_class.new(File.open(__FILE__))
       expect(editor.lines).to be == IO.readlines(__FILE__)
     end
 
-    it 'makes a copy of an Array' do
+    it "makes a copy of an Array" do
       array = Array.new
       editor = described_class.new(array)
       expect(editor.lines).to_not be(array)
@@ -16,137 +16,137 @@ describe Chef::Util::Editor do
   end
 
   subject(:editor) { described_class.new(input_lines) }
-  let(:input_lines) { ['one', 'two', 'two', 'three'] }
+  let(:input_lines) { ["one", "two", "two", "three"] }
 
   describe '#append_line_after' do
-    context 'when there is no match' do
-      subject(:execute) { editor.append_line_after('missing', 'new') }
+    context "when there is no match" do
+      subject(:execute) { editor.append_line_after("missing", "new") }
 
-      it('returns the number of added lines') { is_expected.to eq(0) }
-      it 'does not add any lines' do
+      it("returns the number of added lines") { is_expected.to eq(0) }
+      it "does not add any lines" do
         expect { execute }.to_not change { editor.lines }
       end
     end
 
-    context 'when there is a match' do
-      subject(:execute) { editor.append_line_after('two', 'new') }
+    context "when there is a match" do
+      subject(:execute) { editor.append_line_after("two", "new") }
 
-      it('returns the number of added lines') { is_expected.to eq(2) }
-      it 'adds a line after each match' do
+      it("returns the number of added lines") { is_expected.to eq(2) }
+      it "adds a line after each match" do
         execute
-        expect(editor.lines).to be == ['one', 'two', 'new', 'two', 'new', 'three']
+        expect(editor.lines).to be == ["one", "two", "new", "two", "new", "three"]
       end
     end
 
-    it 'matches a Regexp' do
-      expect(editor.append_line_after(/^ee/, 'new')).to be == 0
-      expect(editor.append_line_after(/ee$/, 'new')).to be == 1
+    it "matches a Regexp" do
+      expect(editor.append_line_after(/^ee/, "new")).to be == 0
+      expect(editor.append_line_after(/ee$/, "new")).to be == 1
     end
   end
 
   describe '#append_line_if_missing' do
-    context 'when there is no match' do
-      subject(:execute) { editor.append_line_if_missing('missing', 'new') }
+    context "when there is no match" do
+      subject(:execute) { editor.append_line_if_missing("missing", "new") }
 
-      it('returns the number of added lines') { is_expected.to eq(1) }
-      it 'adds a line to the end' do
+      it("returns the number of added lines") { is_expected.to eq(1) }
+      it "adds a line to the end" do
         execute
-        expect(editor.lines).to be == ['one', 'two', 'two', 'three', 'new']
+        expect(editor.lines).to be == ["one", "two", "two", "three", "new"]
       end
     end
 
-    context 'when there is a match' do
-      subject(:execute) { editor.append_line_if_missing('one', 'new') }
+    context "when there is a match" do
+      subject(:execute) { editor.append_line_if_missing("one", "new") }
 
-      it('returns the number of added lines') { is_expected.to eq(0) }
-      it 'does not add any lines' do
+      it("returns the number of added lines") { is_expected.to eq(0) }
+      it "does not add any lines" do
         expect { execute }.to_not change { editor.lines }
       end
     end
 
-    it 'matches a Regexp' do
-      expect(editor.append_line_if_missing(/ee$/, 'new')).to be == 0
-      expect(editor.append_line_if_missing(/^ee/, 'new')).to be == 1
+    it "matches a Regexp" do
+      expect(editor.append_line_if_missing(/ee$/, "new")).to be == 0
+      expect(editor.append_line_if_missing(/^ee/, "new")).to be == 1
     end
   end
 
   describe '#remove_lines' do
-    context 'when there is no match' do
-      subject(:execute) { editor.remove_lines('missing') }
+    context "when there is no match" do
+      subject(:execute) { editor.remove_lines("missing") }
 
-      it('returns the number of removed lines') { is_expected.to eq(0) }
-      it 'does not remove any lines' do
+      it("returns the number of removed lines") { is_expected.to eq(0) }
+      it "does not remove any lines" do
         expect { execute }.to_not change { editor.lines }
       end
     end
 
-    context 'when there is a match' do
-      subject(:execute) { editor.remove_lines('two') }
+    context "when there is a match" do
+      subject(:execute) { editor.remove_lines("two") }
 
-      it('returns the number of removed lines') { is_expected.to eq(2) }
-      it 'removes the matching lines' do
+      it("returns the number of removed lines") { is_expected.to eq(2) }
+      it "removes the matching lines" do
         execute
-        expect(editor.lines).to be == ['one', 'three']
+        expect(editor.lines).to be == ["one", "three"]
       end
     end
 
-    it 'matches a Regexp' do
+    it "matches a Regexp" do
       expect(editor.remove_lines(/^ee/)).to be == 0
       expect(editor.remove_lines(/ee$/)).to be == 1
     end
   end
 
   describe '#replace' do
-    context 'when there is no match' do
-      subject(:execute) { editor.replace('missing', 'new') }
+    context "when there is no match" do
+      subject(:execute) { editor.replace("missing", "new") }
 
-      it('returns the number of changed lines') { is_expected.to eq(0) }
-      it 'does not change any lines' do
+      it("returns the number of changed lines") { is_expected.to eq(0) }
+      it "does not change any lines" do
         expect { execute }.to_not change { editor.lines }
       end
     end
 
-    context 'when there is a match' do
-      subject(:execute) { editor.replace('two', 'new') }
+    context "when there is a match" do
+      subject(:execute) { editor.replace("two", "new") }
 
-      it('returns the number of changed lines') { is_expected.to eq(2) }
-      it 'replaces the matching portions' do
+      it("returns the number of changed lines") { is_expected.to eq(2) }
+      it "replaces the matching portions" do
         execute
-        expect(editor.lines).to be == ['one', 'new', 'new', 'three']
+        expect(editor.lines).to be == ["one", "new", "new", "three"]
       end
     end
 
-    it 'matches a Regexp' do
-      expect(editor.replace(/^ee/, 'new')).to be == 0
-      expect(editor.replace(/ee$/, 'new')).to be == 1
-      expect(editor.lines).to be == ['one', 'two', 'two', 'thrnew']
+    it "matches a Regexp" do
+      expect(editor.replace(/^ee/, "new")).to be == 0
+      expect(editor.replace(/ee$/, "new")).to be == 1
+      expect(editor.lines).to be == ["one", "two", "two", "thrnew"]
     end
   end
 
   describe '#replace_lines' do
-    context 'when there is no match' do
-      subject(:execute) { editor.replace_lines('missing', 'new') }
+    context "when there is no match" do
+      subject(:execute) { editor.replace_lines("missing", "new") }
 
-      it('returns the number of changed lines') { is_expected.to eq(0) }
-      it 'does not change any lines' do
+      it("returns the number of changed lines") { is_expected.to eq(0) }
+      it "does not change any lines" do
         expect { execute }.to_not change { editor.lines }
       end
     end
 
-    context 'when there is a match' do
-      subject(:execute) { editor.replace_lines('two', 'new') }
+    context "when there is a match" do
+      subject(:execute) { editor.replace_lines("two", "new") }
 
-      it('returns the number of replaced lines') { is_expected.to eq(2) }
-      it 'replaces the matching line' do
+      it("returns the number of replaced lines") { is_expected.to eq(2) }
+      it "replaces the matching line" do
         execute
-        expect(editor.lines).to be == ['one', 'new', 'new', 'three']
+        expect(editor.lines).to be == ["one", "new", "new", "three"]
       end
     end
 
-    it 'matches a Regexp' do
-      expect(editor.replace_lines(/^ee/, 'new')).to be == 0
-      expect(editor.replace_lines(/ee$/, 'new')).to be == 1
-      expect(editor.lines).to be == ['one', 'two', 'two', 'new']
+    it "matches a Regexp" do
+      expect(editor.replace_lines(/^ee/, "new")).to be == 0
+      expect(editor.replace_lines(/ee$/, "new")).to be == 1
+      expect(editor.lines).to be == ["one", "two", "two", "new"]
     end
   end
 end
diff --git a/spec/unit/util/file_edit_spec.rb b/spec/unit/util/file_edit_spec.rb
index b99cf2f..1a71d1d 100644
--- a/spec/unit/util/file_edit_spec.rb
+++ b/spec/unit/util/file_edit_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Nuo Yan (<nuo at opscode.com>)
-# Copyright:: Copyright (c) 2008 Opscode, Inc.
+# Author:: Nuo Yan (<nuo at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,8 @@
 # limitations under the License.
 #
 
-require 'spec_helper'
-require 'tempfile'
+require "spec_helper"
+require "tempfile"
 
 describe Chef::Util::FileEdit do
 
@@ -93,7 +93,7 @@ twice
   end
 
   let(:target_file) do
-    f = Tempfile.open('file_edit_spec')
+    f = Tempfile.open("file_edit_spec")
     f.write(starting_content)
     f.close
     f
@@ -111,7 +111,7 @@ twice
     end
 
     it "should throw an exception if the input file does not exist" do
-      expect{Chef::Util::FileEdit.new("nonexistfile")}.to raise_error(ArgumentError)
+      expect { Chef::Util::FileEdit.new("nonexistfile") }.to raise_error(ArgumentError)
     end
 
     # CHEF-5018: people have monkey patched this and it has accidentally been broken
@@ -124,7 +124,7 @@ twice
     let(:hosts_content) { "" }
 
     it "should not throw an exception" do
-      expect{ fedit }.not_to raise_error
+      expect { fedit }.not_to raise_error
     end
   end
 
diff --git a/spec/unit/util/path_helper_spec.rb b/spec/unit/util/path_helper_spec.rb
deleted file mode 100644
index 23db958..0000000
--- a/spec/unit/util/path_helper_spec.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-#
-# Author:: Bryan McLellan <btm at loftninjas.org>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'chef/util/path_helper'
-require 'spec_helper'
-
-describe Chef::Util::PathHelper do
-  PathHelper = Chef::Util::PathHelper
-
-  [ false, true ].each do |is_windows|
-    context "on #{is_windows ? "windows" : "unix"}" do
-      before(:each) do
-        allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
-      end
-
-      describe "join" do
-        it "joins components when some end with separators" do
-          expected = PathHelper.cleanpath("/foo/bar/baz")
-          expected = "C:#{expected}" if is_windows
-          expect(PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar", "baz")).to eq(expected)
-        end
-
-        it "joins components when some end and start with separators" do
-          expected = PathHelper.cleanpath("/foo/bar/baz")
-          expected = "C:#{expected}" if is_windows
-          expect(PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar/", "/baz")).to eq(expected)
-        end
-
-        it "joins components that don't end in separators" do
-          expected = PathHelper.cleanpath("/foo/bar/baz")
-          expected = "C:#{expected}" if is_windows
-          expect(PathHelper.join(is_windows ? 'C:\\foo' : "/foo", "bar", "baz")).to eq(expected)
-        end
-
-        it "joins starting with '' resolve to absolute paths" do
-          expect(PathHelper.join('', 'a', 'b')).to eq("#{PathHelper.path_separator}a#{PathHelper.path_separator}b")
-        end
-
-        it "joins ending with '' add a / to the end" do
-          expect(PathHelper.join('a', 'b', '')).to eq("a#{PathHelper.path_separator}b#{PathHelper.path_separator}")
-        end
-
-        if is_windows
-          it "joins components on Windows when some end with unix separators" do
-            expect(PathHelper.join('C:\\foo/', "bar", "baz")).to eq('C:\\foo\\bar\\baz')
-          end
-        end
-      end
-
-      if is_windows
-        it "path_separator is \\" do
-          expect(PathHelper.path_separator).to eq('\\')
-        end
-      else
-        it "path_separator is /" do
-          expect(PathHelper.path_separator).to eq('/')
-        end
-      end
-
-      if is_windows
-        it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
-          expect(PathHelper.cleanpath('/a/b\\c/d/')).to eq('\\a\\b\\c\\d')
-        end
-        it "cleanpath does not remove leading double backslash" do
-          expect(PathHelper.cleanpath('\\\\a/b\\c/d/')).to eq('\\\\a\\b\\c\\d')
-        end
-      else
-        it "cleanpath removes extra slashes alone" do
-          expect(PathHelper.cleanpath('/a///b/c/d/')).to eq('/a/b/c/d')
-        end
-      end
-
-      describe "dirname" do
-        it "dirname('abc') is '.'" do
-          expect(PathHelper.dirname('abc')).to eq('.')
-        end
-        it "dirname('/') is '/'" do
-          expect(PathHelper.dirname(PathHelper.path_separator)).to eq(PathHelper.path_separator)
-        end
-        it "dirname('a/b/c') is 'a/b'" do
-          expect(PathHelper.dirname(PathHelper.join('a', 'b', 'c'))).to eq(PathHelper.join('a', 'b'))
-        end
-        it "dirname('a/b/c/') is 'a/b'" do
-          expect(PathHelper.dirname(PathHelper.join('a', 'b', 'c', ''))).to eq(PathHelper.join('a', 'b'))
-        end
-        it "dirname('/a/b/c') is '/a/b'" do
-          expect(PathHelper.dirname(PathHelper.join('', 'a', 'b', 'c'))).to eq(PathHelper.join('', 'a', 'b'))
-        end
-      end
-    end
-  end
-
-  describe "validate_path" do
-    context "on windows" do
-      before(:each) do
-        # pass by default
-        allow(Chef::Platform).to receive(:windows?).and_return(true)
-        allow(PathHelper).to receive(:printable?).and_return(true)
-        allow(PathHelper).to receive(:windows_max_length_exceeded?).and_return(false)
-      end
-
-      it "returns the path if the path passes the tests" do
-        expect(PathHelper.validate_path("C:\\ThisIsRigged")).to eql("C:\\ThisIsRigged")
-      end
-
-      it "does not raise an error if everything looks great" do
-        expect { PathHelper.validate_path("C:\\cool path\\dude.exe") }.not_to raise_error
-      end
-
-      it "raises an error if the path has invalid characters" do
-        allow(PathHelper).to receive(:printable?).and_return(false)
-        expect { PathHelper.validate_path("Newline!\n") }.to raise_error(Chef::Exceptions::ValidationFailed)
-      end
-
-      it "Adds the \\\\?\\ prefix if the path exceeds MAX_LENGTH and does not have it" do
-        long_path = "C:\\" + "a" * 250 + "\\" + "b" * 250
-        prefixed_long_path = "\\\\?\\" + long_path
-        allow(PathHelper).to receive(:windows_max_length_exceeded?).and_return(true)
-        expect(PathHelper.validate_path(long_path)).to eql(prefixed_long_path)
-      end
-    end
-  end
-
-  describe "windows_max_length_exceeded?" do
-    it "returns true if the path is too long (259 + NUL) for the API" do
-      expect(PathHelper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 6)).to be_truthy
-    end
-
-    it "returns false if the path is not too long (259 + NUL) for the standard API" do
-      expect(PathHelper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 5)).to be_falsey
-    end
-
-    it "returns false if the path is over 259 characters but uses the \\\\?\\ prefix" do
-      expect(PathHelper.windows_max_length_exceeded?("\\\\?\\C:\\" + "a" * 250 + "\\" + "b" * 250)).to be_falsey
-    end
-  end
-
-  describe "printable?" do
-    it "returns true if the string contains no non-printable characters" do
-      expect(PathHelper.printable?("C:\\Program Files (x86)\\Microsoft Office\\Files.lst")).to be_truthy
-    end
-
-    it "returns true when given 'abc' in unicode" do
-      expect(PathHelper.printable?("\u0061\u0062\u0063")).to be_truthy
-    end
-
-    it "returns true when given japanese unicode" do
-      expect(PathHelper.printable?("\uff86\uff87\uff88")).to be_truthy
-    end
-
-    it "returns false if the string contains a non-printable character" do
-      expect(PathHelper.printable?("\my files\work\notes.txt")).to be_falsey
-    end
-
-    # This isn't necessarily a requirement, but here to be explicit about functionality.
-    it "returns false if the string contains a newline or tab" do
-      expect(PathHelper.printable?("\tThere's no way,\n\t *no* way,\n\t that you came from my loins.\n")).to be_falsey
-    end
-  end
-
-  describe "canonical_path" do
-    context "on windows", :windows_only do
-      it "returns an absolute path with backslashes instead of slashes" do
-        expect(PathHelper.canonical_path("\\\\?\\C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
-      end
-
-      it "adds the \\\\?\\ prefix if it is missing" do
-        expect(PathHelper.canonical_path("C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
-      end
-
-      it "returns a lowercase path" do
-        expect(PathHelper.canonical_path("\\\\?\\C:\\CASE\\INSENSITIVE")).to eq("\\\\?\\c:\\case\\insensitive")
-      end
-    end
-
-    context "not on windows", :unix_only  do
-      it "returns a canonical path" do
-        expect(PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default")).to eq("/etc/apache.d/sites-available/default")
-      end
-    end
-  end
-
-  describe "paths_eql?" do
-    it "returns true if the paths are the same" do
-      allow(PathHelper).to receive(:canonical_path).with("bandit").and_return("c:/bandit/bandit")
-      allow(PathHelper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
-      expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_truthy
-    end
-
-    it "returns false if the paths are different" do
-      allow(PathHelper).to receive(:canonical_path).with("bandit").and_return("c:/Bo/Bandit")
-      allow(PathHelper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
-      expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_falsey
-    end
-  end
-
-  describe "escape_glob" do
-    it "escapes characters reserved by glob" do
-      path = "C:\\this\\*path\\[needs]\\escaping?"
-      escaped_path = "C:\\\\this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
-      expect(PathHelper.escape_glob(path)).to eq(escaped_path)
-    end
-
-    context "when given more than one argument" do
-      it "joins, cleanpaths, and escapes characters reserved by glob" do
-        args = ["this/*path", "[needs]", "escaping?"]
-        escaped_path = if windows?
-          "this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
-        else
-          "this/\\*path/\\[needs\\]/escaping\\?"
-        end
-        expect(PathHelper).to receive(:join).with(*args).and_call_original
-        expect(PathHelper).to receive(:cleanpath).and_call_original
-        expect(PathHelper.escape_glob(*args)).to eq(escaped_path)
-      end
-    end
-  end
-
-  describe "all_homes" do
-    before do
-      stub_const('ENV', env)
-      allow(Chef::Platform).to receive(:windows?).and_return(is_windows)
-    end
-
-    context "on windows" do
-      let (:is_windows) { true }
-    end
-
-    context "on unix" do
-      let (:is_windows) { false }
-
-      context "when HOME is not set" do
-        let (:env) { {} }
-        it "returns an empty array" do
-          expect(PathHelper.all_homes).to eq([])
-        end
-      end
-    end
-  end
-end
diff --git a/spec/unit/util/powershell/cmdlet_spec.rb b/spec/unit/util/powershell/cmdlet_spec.rb
index 5ddf928..5c0e66a 100644
--- a/spec/unit/util/powershell/cmdlet_spec.rb
+++ b/spec/unit/util/powershell/cmdlet_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Jay Mundrawala <jdm at getchef.com>
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# Author:: Jay Mundrawala <jdm at chef.io>
+# Copyright:: Copyright 2014-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,25 +16,25 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/powershell/cmdlet'
+require "chef"
+require "chef/util/powershell/cmdlet"
 
 describe Chef::Util::Powershell::Cmdlet do
   before (:all) do
     @node = Chef::Node.new
-    @cmdlet = Chef::Util::Powershell::Cmdlet.new(@node, 'Some-Commandlet')
+    @cmdlet = Chef::Util::Powershell::Cmdlet.new(@node, "Some-Commandlet")
   end
 
   describe '#validate_switch_name!' do
-    it 'should not raise an error if a name contains all upper case letters' do
+    it "should not raise an error if a name contains all upper case letters" do
       @cmdlet.send(:validate_switch_name!, "HELLO")
     end
 
-    it 'should not raise an error if the name contains all lower case letters' do
+    it "should not raise an error if the name contains all lower case letters" do
       @cmdlet.send(:validate_switch_name!, "hello")
     end
 
-    it 'should not raise an error if no special characters are used except _' do
+    it "should not raise an error if no special characters are used except _" do
       @cmdlet.send(:validate_switch_name!, "hello_world")
     end
 
@@ -55,52 +55,52 @@ describe Chef::Util::Powershell::Cmdlet do
       end
     end
 
-    it 'does not do anything to a string without special characters' do
-      expect(@cmdlet.send(:escape_parameter_value, 'stuff')).to eql('stuff')
+    it "does not do anything to a string without special characters" do
+      expect(@cmdlet.send(:escape_parameter_value, "stuff")).to eql("stuff")
     end
   end
 
   describe '#escape_string_parameter_value' do
     it "surrounds a string with ''" do
-      expect(@cmdlet.send(:escape_string_parameter_value, 'stuff')).to eql("'stuff'")
+      expect(@cmdlet.send(:escape_string_parameter_value, "stuff")).to eql("'stuff'")
     end
   end
 
   describe '#command_switches_string' do
-    it 'raises an ArgumentError if the key is not a symbol' do
+    it "raises an ArgumentError if the key is not a symbol" do
       expect {
-        @cmdlet.send(:command_switches_string, {'foo' => 'bar'})
+        @cmdlet.send(:command_switches_string, { "foo" => "bar" })
       }.to raise_error(ArgumentError)
     end
 
-    it 'does not allow invalid switch names' do
+    it "does not allow invalid switch names" do
       expect {
-        @cmdlet.send(:command_switches_string, {:foo! => 'bar'})
+        @cmdlet.send(:command_switches_string, { :foo! => "bar" })
       }.to raise_error(ArgumentError)
     end
 
-    it 'ignores switches with a false value' do
-      expect(@cmdlet.send(:command_switches_string, {foo: false})).to eql('')
+    it "ignores switches with a false value" do
+      expect(@cmdlet.send(:command_switches_string, { foo: false })).to eql("")
     end
 
-    it 'should correctly handle a value type of string' do
-      expect(@cmdlet.send(:command_switches_string, {foo: 'bar'})).to eql("-foo 'bar'")
+    it "should correctly handle a value type of string" do
+      expect(@cmdlet.send(:command_switches_string, { foo: "bar" })).to eql("-foo 'bar'")
     end
 
-    it 'should correctly handle a value type of string even when it is 0 length' do
-      expect(@cmdlet.send(:command_switches_string, {foo: ''})).to eql("-foo ''")
+    it "should correctly handle a value type of string even when it is 0 length" do
+      expect(@cmdlet.send(:command_switches_string, { foo: "" })).to eql("-foo ''")
     end
 
-    it 'should not quote integers' do
-      expect(@cmdlet.send(:command_switches_string, {foo: 1})).to eql("-foo 1")
+    it "should not quote integers" do
+      expect(@cmdlet.send(:command_switches_string, { foo: 1 })).to eql("-foo 1")
     end
 
-    it 'should not quote floats' do
-      expect(@cmdlet.send(:command_switches_string, {foo: 1.0})).to eql("-foo 1.0")
+    it "should not quote floats" do
+      expect(@cmdlet.send(:command_switches_string, { foo: 1.0 })).to eql("-foo 1.0")
     end
 
-    it 'has just the switch when the value is true' do
-      expect(@cmdlet.send(:command_switches_string, {foo: true})).to eql("-foo")
+    it "has just the switch when the value is true" do
+      expect(@cmdlet.send(:command_switches_string, { foo: true })).to eql("-foo")
     end
   end
 end
diff --git a/spec/unit/util/powershell/ps_credential_spec.rb b/spec/unit/util/powershell/ps_credential_spec.rb
index bac58b0..6f65174 100644
--- a/spec/unit/util/powershell/ps_credential_spec.rb
+++ b/spec/unit/util/powershell/ps_credential_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Jay Mundrawala <jdm at chef.io>
-# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,29 @@
 # limitations under the License.
 #
 
-require 'chef'
-require 'chef/util/powershell/ps_credential'
+require "chef"
+require "chef/util/powershell/ps_credential"
 
 describe Chef::Util::Powershell::PSCredential do
-  let (:username) { 'foo' }
-  let (:password) { 'password' }
+  let (:username) { "foo" }
+  let (:password) { "ThIsIsThEpAsSwOrD" }
 
-  context 'when username and password are provided' do
-    let(:ps_credential) { Chef::Util::Powershell::PSCredential.new(username, password)}
-    context 'when calling to_psobject' do
-      it 'should create the script to create a PSCredential when calling' do
-        allow(ps_credential).to receive(:encrypt).with(password).and_return('encrypted')
+  context "when username and password are provided" do
+    let(:ps_credential) { Chef::Util::Powershell::PSCredential.new(username, password) }
+    context "when calling to_psobject" do
+      it "should create the script to create a PSCredential when calling" do
+        allow(ps_credential).to receive(:encrypt).with(password).and_return("encrypted")
         expect(ps_credential.to_psobject).to eq(
         "New-Object System.Management.Automation.PSCredential("\
             "'#{username}',('encrypted' | ConvertTo-SecureString))")
       end
     end
+
+    context "when to_text is called" do
+      it "should not contain the password" do
+        allow(ps_credential).to receive(:encrypt).with(password).and_return("encrypted")
+        expect(ps_credential.to_text).not_to match(/#{password}/)
+      end
+    end
   end
 end
diff --git a/spec/unit/util/selinux_spec.rb b/spec/unit/util/selinux_spec.rb
index 0ed138c..609ff02 100644
--- a/spec/unit/util/selinux_spec.rb
+++ b/spec/unit/util/selinux_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Serdar Sutay (<serdar at opscode.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Author:: Serdar Sutay (<serdar at chef.io>)
+# Copyright:: Copyright 2013-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,7 @@
 # limitations under the License.
 #
 
-
-require 'spec_helper'
+require "spec_helper"
 
 describe Chef::Util::Selinux do
   class TestClass
@@ -40,7 +39,7 @@ describe Chef::Util::Selinux do
   end
 
   it "each part of ENV['PATH'] should be checked" do
-    expected_paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+    expected_paths = ENV["PATH"].split(File::PATH_SEPARATOR) + [ "/bin", "/usr/bin", "/sbin", "/usr/sbin" ]
 
     expected_paths.each do |bin_path|
       selinux_path = File.join(bin_path, "selinuxenabled")
@@ -62,7 +61,7 @@ describe Chef::Util::Selinux do
     describe "when selinux is enabled" do
       before do
         cmd_result = double("Cmd Result", :exitstatus => 0)
-        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
       end
 
       it "should report selinux is enabled" do
@@ -75,7 +74,7 @@ describe Chef::Util::Selinux do
     describe "when selinux is disabled" do
       before do
         cmd_result = double("Cmd Result", :exitstatus => 1)
-        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
       end
 
       it "should report selinux is disabled" do
@@ -88,11 +87,11 @@ describe Chef::Util::Selinux do
     describe "when selinux gives an unexpected status" do
       before do
         cmd_result = double("Cmd Result", :exitstatus => 101)
-        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result)
+        expect(@test_instance).to receive(:shell_out!).once.with(@selinux_enabled_path, { :returns => [0, 1] }).and_return(cmd_result)
       end
 
       it "should throw an error" do
-        expect {@test_instance.selinux_enabled?}.to raise_error(RuntimeError)
+        expect { @test_instance.selinux_enabled? }.to raise_error(RuntimeError)
       end
     end
   end
diff --git a/spec/unit/util/threaded_job_queue_spec.rb b/spec/unit/util/threaded_job_queue_spec.rb
index 2262632..8a89943 100644
--- a/spec/unit/util/threaded_job_queue_spec.rb
+++ b/spec/unit/util/threaded_job_queue_spec.rb
@@ -1,4 +1,4 @@
-# Copyright:: Copyright (c) 2014 Opscode, Inc.
+# Copyright:: Copyright 2014-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
+require "spec_helper"
 
 class WorkerThreadError < StandardError
 end
diff --git a/spec/unit/version/platform_spec.rb b/spec/unit/version/platform_spec.rb
index dd425b3..cd2d37f 100644
--- a/spec/unit/version/platform_spec.rb
+++ b/spec/unit/version/platform_spec.rb
@@ -1,5 +1,5 @@
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +14,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/version/platform'
+require "spec_helper"
+require "chef/version/platform"
 
 describe Chef::Version::Platform do
 
   it "is a subclass of Chef::Version" do
-    v = Chef::Version::Platform.new('1.1')
+    v = Chef::Version::Platform.new("1.1")
     expect(v).to be_an_instance_of(Chef::Version::Platform)
     expect(v).to be_a_kind_of(Chef::Version)
   end
@@ -30,7 +30,7 @@ describe Chef::Version::Platform do
   end
 
   describe "when creating valid Versions" do
-    good_versions = %w(1 1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003 1.2-STABLE 10.0-BETA3 9.1-RELEASE-p3)
+    good_versions = %w{1 1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003 1.2-STABLE 10.0-BETA3 9.1-RELEASE-p3}
     good_versions.each do |v|
       it "should accept '#{v}'" do
         Chef::Version::Platform.new v
@@ -58,4 +58,3 @@ describe Chef::Version::Platform do
   end
 
 end
-
diff --git a/spec/unit/version_class_spec.rb b/spec/unit/version_class_spec.rb
index fe14885..5543fbe 100644
--- a/spec/unit/version_class_spec.rb
+++ b/spec/unit/version_class_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/version_class'
+require "spec_helper"
+require "chef/version_class"
 
 describe Chef::Version do
   before do
@@ -44,7 +44,7 @@ describe Chef::Version do
   end
 
   describe "when creating valid Versions" do
-    good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003)
+    good_versions = %w{1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003}
     good_versions.each do |v|
       it "should accept '#{v}'" do
         Chef::Version.new v
@@ -90,7 +90,7 @@ describe Chef::Version do
                   ["1.2", "1.3.0"],
                   ["1.2", "1.3"],
                   ["1.2", "2.1.1"],
-                  ["1.2", "2.1"]
+                  ["1.2", "2.1"],
                  ]
       examples.each do |smaller, larger|
         sm = Chef::Version.new(smaller)
@@ -105,7 +105,7 @@ describe Chef::Version do
       a = %w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1}.map do |s|
         Chef::Version.new(s)
       end
-      got = a.sort.map {|v| v.to_s }
+      got = a.sort.map { |v| v.to_s }
       expect(got).to eq(%w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1})
     end
 
@@ -158,7 +158,7 @@ describe Chef::Version do
        [ "1.2.2", :>=, "1.2.1", true ],
        [ "1.2.2", :==, "1.2.1", false ],
        [ "1.2.2", :<=, "1.2.1", false ],
-       [ "1.2.2", :<, "1.2.1", false ]
+       [ "1.2.2", :<, "1.2.1", false ],
       ].each do |spec|
         it "(#{spec.first(3).join(' ')}) should be #{spec[3]}" do
           got = Chef::Version.new(spec[0]).send(spec[1],
@@ -169,4 +169,3 @@ describe Chef::Version do
     end
   end
 end
-
diff --git a/spec/unit/version_constraint/platform_spec.rb b/spec/unit/version_constraint/platform_spec.rb
index f38eb49..593a47b 100644
--- a/spec/unit/version_constraint/platform_spec.rb
+++ b/spec/unit/version_constraint/platform_spec.rb
@@ -1,5 +1,5 @@
 # Author:: Xabier de Zuazo (<xabier at onddo.com>)
-# Copyright:: Copyright (c) 2013 Onddo Labs, SL.
+# Copyright:: Copyright 2013-2016, Onddo Labs, SL.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/version_constraint/platform'
+require "spec_helper"
+require "chef/version_constraint/platform"
 
 describe Chef::VersionConstraint::Platform do
 
@@ -43,4 +43,3 @@ describe Chef::VersionConstraint::Platform do
 
   end
 end
-
diff --git a/spec/unit/version_constraint_spec.rb b/spec/unit/version_constraint_spec.rb
index 0ae502f..f83af03 100644
--- a/spec/unit/version_constraint_spec.rb
+++ b/spec/unit/version_constraint_spec.rb
@@ -1,6 +1,6 @@
 #
-# Author:: Seth Falcon (<seth at opscode.com>)
-# Copyright:: Copyright 2010 Opscode, Inc.
+# Author:: Seth Falcon (<seth at chef.io>)
+# Copyright:: Copyright 2010-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-require 'spec_helper'
-require 'chef/version_constraint'
+require "spec_helper"
+require "chef/version_constraint"
 
 describe Chef::VersionConstraint do
   describe "validation" do
@@ -88,7 +88,7 @@ describe Chef::VersionConstraint do
         expect(@vc).to include Chef::Version.new("1.4")
       end
       it "Chef::CookbookVersion" do
-        cv = Chef::CookbookVersion.new("alice", '/tmp/blah.txt')
+        cv = Chef::CookbookVersion.new("alice", "/tmp/blah.txt")
         cv.version = "1.4"
         expect(@vc).to include cv
       end
@@ -149,31 +149,31 @@ describe Chef::VersionConstraint do
     end
   end
 
-  describe 'to_s' do
-    it 'shows a patch-level if one is given' do
-      vc = Chef::VersionConstraint.new '~> 1.2.0'
+  describe "to_s" do
+    it "shows a patch-level if one is given" do
+      vc = Chef::VersionConstraint.new "~> 1.2.0"
 
-      expect(vc.to_s).to eq('~> 1.2.0')
+      expect(vc.to_s).to eq("~> 1.2.0")
     end
 
-    it 'shows no patch-level if one is not given' do
-      vc = Chef::VersionConstraint.new '~> 1.2'
+    it "shows no patch-level if one is not given" do
+      vc = Chef::VersionConstraint.new "~> 1.2"
 
-      expect(vc.to_s).to eq('~> 1.2')
+      expect(vc.to_s).to eq("~> 1.2")
     end
   end
 
-  describe 'inspect' do
-    it 'shows a patch-level if one is given' do
-      vc = Chef::VersionConstraint.new '~> 1.2.0'
+  describe "inspect" do
+    it "shows a patch-level if one is given" do
+      vc = Chef::VersionConstraint.new "~> 1.2.0"
 
-      expect(vc.inspect).to eq('(~> 1.2.0)')
+      expect(vc.inspect).to eq("(~> 1.2.0)")
     end
 
-    it 'shows no patch-level if one is not given' do
-      vc = Chef::VersionConstraint.new '~> 1.2'
+    it "shows no patch-level if one is not given" do
+      vc = Chef::VersionConstraint.new "~> 1.2"
 
-      expect(vc.inspect).to eq('(~> 1.2)')
+      expect(vc.inspect).to eq("(~> 1.2)")
     end
   end
 end
diff --git a/spec/unit/win32/registry_spec.rb b/spec/unit/win32/registry_spec.rb
new file mode 100644
index 0000000..1523ac1
--- /dev/null
+++ b/spec/unit/win32/registry_spec.rb
@@ -0,0 +1,394 @@
+#
+# Author:: Prajakta Purohit (prajakta at chef.io)
+# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Win32::Registry do
+  include_context "Win32"
+
+  let(:value1) { { :name => "one", :type => :string, :data => "1" } }
+  let(:value1_upcase_name) { { :name => "ONE", :type => :string, :data => "1" } }
+  let(:key_path) { 'HKCU\Software\OpscodeNumbers' }
+  let(:key) { 'Software\OpscodeNumbers' }
+  let(:key_parent) { "Software" }
+  let(:key_to_delete) { "OpscodeNumbers" }
+  let(:sub_key) { "OpscodePrimes" }
+  let(:missing_key_path) { 'HKCU\Software' }
+  let(:registry) { Chef::Win32::Registry.new() }
+  let(:hive_mock) { double("::Win32::Registry::KHKEY_CURRENT_USER") }
+  let(:reg_mock) { double("reg") }
+
+  before(:all) do
+    Win32::Registry = Class.new
+    Win32::Registry::Error = Class.new(RuntimeError)
+  end
+
+  before(:each) do
+    allow_any_instance_of(Chef::Win32::Registry).to receive(:machine_architecture).and_return(:x86_64)
+
+    #Making the values for registry constants available on unix
+    Win32::Registry::KEY_SET_VALUE = 0x0002
+    Win32::Registry::KEY_QUERY_VALUE = 0x0001
+    Win32::Registry::KEY_WRITE = 0x00020000 | 0x0002 | 0x0004
+    Win32::Registry::KEY_READ = 0x00020000 | 0x0001 | 0x0008 | 0x0010
+  end
+
+  after(:each) do
+    Win32::Registry.send(:remove_const, "KEY_SET_VALUE") if defined?(Win32::Registry::KEY_SET_VALUE)
+    Win32::Registry.send(:remove_const, "KEY_QUERY_VALUE") if defined?(Win32::Registry::KEY_QUERY_VALUE)
+    Win32::Registry.send(:remove_const, "KEY_READ") if defined?(Win32::Registry::KEY_READ)
+    Win32::Registry.send(:remove_const, "KEY_WRITE") if defined?(Win32::Registry::KEY_WRITE)
+  end
+
+  describe "get_values" do
+    it "gets all values for a key if the key exists" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:map)
+      registry.get_values(key_path)
+    end
+
+    it "throws an exception if key does not exist" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      expect { registry.get_values(key_path) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+  end
+
+  describe "set_value" do
+    it "does nothing if key and hive and value exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:data_exists?).with(key_path, value1).and_return(true)
+      registry.set_value(key_path, value1)
+    end
+    it "does nothing if case insensitive key and hive and value exist" do
+      expect(registry).to receive(:key_exists!).with(key_path.downcase).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path.downcase).and_return([hive_mock, key])
+      expect(registry).to receive(:value_exists?).with(key_path.downcase, value1).and_return(true)
+      expect(registry).to receive(:data_exists?).with(key_path.downcase, value1).and_return(true)
+      registry.set_value(key_path.downcase, value1)
+    end
+    it "does nothing if key and hive and value with a case insensitive name exist" do
+      expect(registry).to receive(:key_exists!).with(key_path.downcase).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path.downcase).and_return([hive_mock, key])
+      expect(registry).to receive(:value_exists?).with(key_path.downcase, value1_upcase_name).and_return(true)
+      expect(registry).to receive(:data_exists?).with(key_path.downcase, value1_upcase_name).and_return(true)
+      registry.set_value(key_path.downcase, value1_upcase_name)
+    end
+    it "updates value if key and hive and value exist, but data is different" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:data_exists?).with(key_path, value1).and_return(false)
+      expect(hive_mock).to receive(:open).with(key, Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry).to receive(:get_type_from_name).with(:string).and_return(1)
+      expect(reg_mock).to receive(:write).with("one", 1, "1")
+      registry.set_value(key_path, value1)
+    end
+
+    it "creates value if the key exists and the value does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry).to receive(:get_type_from_name).with(:string).and_return(1)
+      expect(reg_mock).to receive(:write).with("one", 1, "1")
+      registry.set_value(key_path, value1)
+    end
+
+    it "should raise an exception if the key does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      expect { registry.set_value(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+  end
+
+  describe "delete_value" do
+    it "deletes value if value exists" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:delete_value).with("one").and_return(true)
+      registry.delete_value(key_path, value1)
+    end
+
+    it "raises an exception if the key does not exist" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      registry.delete_value(key_path, value1)
+    end
+
+    it "does nothing if the value does not exist" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
+      registry.delete_value(key_path, value1)
+    end
+  end
+
+  describe "create_key" do
+    it "creates key if intermediate keys are missing and recursive is set to true" do
+      expect(registry).to receive(:keys_missing?).with(key_path).and_return(true)
+      expect(registry).to receive(:create_missing).with(key_path)
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(false)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | registry.registry_system_architecture)
+      registry.create_key(key_path, true)
+    end
+
+    it "raises an exception if intermediate keys are missing and recursive is set to false" do
+      expect(registry).to receive(:keys_missing?).with(key_path).and_return(true)
+      expect { registry.create_key(key_path, false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+    end
+
+    it "does nothing if the key exists" do
+      expect(registry).to receive(:keys_missing?).with(key_path).and_return(true)
+      expect(registry).to receive(:create_missing).with(key_path)
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(true)
+      registry.create_key(key_path, true)
+    end
+
+    it "create key if intermediate keys not missing and recursive is set to false" do
+      expect(registry).to receive(:keys_missing?).with(key_path).and_return(false)
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(false)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | registry.registry_system_architecture)
+      registry.create_key(key_path, false)
+    end
+
+    it "create key if intermediate keys not missing and recursive is set to true" do
+      expect(registry).to receive(:keys_missing?).with(key_path).and_return(false)
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(false)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:create).with(key, ::Win32::Registry::KEY_WRITE | registry.registry_system_architecture)
+      registry.create_key(key_path, true)
+    end
+  end
+
+  describe "delete_key", :windows_only do
+    it "deletes key if it has subkeys and recursive is set to true" do
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(true)
+      expect(registry).to receive(:has_subkeys?).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key_parent, ::Win32::Registry::KEY_WRITE | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:delete_key).with(key_to_delete, true).and_return(true)
+      registry.delete_key(key_path, true)
+    end
+
+    it "raises an exception if it has subkeys but recursive is set to false" do
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(true)
+      expect(registry).to receive(:has_subkeys?).with(key_path).and_return(true)
+      expect { registry.delete_key(key_path, false) }.to raise_error(Chef::Exceptions::Win32RegNoRecursive)
+    end
+
+    it "deletes key if the key exists and has no subkeys" do
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(true)
+      expect(registry).to receive(:has_subkeys?).with(key_path).and_return(false)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key_parent, ::Win32::Registry::KEY_WRITE | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:delete_key).with(key_to_delete, true).and_return(true)
+      registry.delete_key(key_path, true)
+    end
+  end
+
+  describe "key_exists?" do
+    it "returns true if key_exists" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry.key_exists?(key_path)).to eq(true)
+    end
+
+    it "returns false if key does not exist" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_raise(::Win32::Registry::Error)
+      expect(registry.key_exists?(key_path)).to eq(false)
+    end
+  end
+
+  describe "key_exists!" do
+    it "throws an exception if the key_parent does not exist" do
+      expect(registry).to receive(:key_exists?).with(key_path).and_return(false)
+      expect { registry.key_exists!(key_path) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+  end
+
+  describe "hive_exists?" do
+    it "returns true if the hive exists" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      registry.hive_exists?(key_path) == true
+    end
+
+    it "returns false if the hive does not exist" do
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegHiveMissing)
+      registry.hive_exists?(key_path) == false
+    end
+  end
+
+  describe "has_subkeys?" do
+    it "returns true if the key has subkeys" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:each_key).and_yield(key)
+      registry.has_subkeys?(key_path) == true
+    end
+
+    it "returns false if the key does not have subkeys" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:each_key).and_return(no_args())
+      expect(registry.has_subkeys?(key_path)).to eq(false)
+    end
+
+    it "throws an exception if the key does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      expect { registry.set_value(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+  end
+
+  describe "get_subkeys" do
+    it "returns the subkeys if they exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:each_key).and_yield(sub_key)
+      registry.get_subkeys(key_path)
+    end
+  end
+
+  describe "value_exists?" do
+    it "throws an exception if the key does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      expect { registry.value_exists?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "returns true if the value exists" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:any?).and_yield("one")
+      registry.value_exists?(key_path, value1) == true
+    end
+
+    it "returns false if the value does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:any?).and_yield(no_args())
+      registry.value_exists?(key_path, value1) == false
+    end
+  end
+
+  describe "data_exists?" do
+    it "throws an exception if the key does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing)
+      expect { registry.data_exists?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegKeyMissing)
+    end
+
+    it "returns true if the data exists" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(registry).to receive(:get_type_from_name).with(:string).and_return(1)
+      expect(reg_mock).to receive(:each).with(no_args()).and_yield("one", 1, "1")
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry.data_exists?(key_path, value1)).to eq(true)
+    end
+
+    it "returns false if the data does not exist" do
+      expect(registry).to receive(:key_exists!).with(key_path).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry).to receive(:get_type_from_name).with(:string).and_return(1)
+      expect(reg_mock).to receive(:each).with(no_args()).and_yield("one", 1, "2")
+      expect(registry.data_exists?(key_path, value1)).to eq(false)
+    end
+  end
+
+  describe "value_exists!" do
+    it "does nothing if the value exists" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(true)
+      registry.value_exists!(key_path, value1)
+    end
+
+    it "throws an exception if the value does not exist" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
+      expect { registry.value_exists!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+    end
+  end
+
+  describe "data_exists!" do
+    it "does nothing if the data exists" do
+      expect(registry).to receive(:data_exists?).with(key_path, value1).and_return(true)
+      registry.data_exists!(key_path, value1)
+    end
+
+    it "throws an exception if the data does not exist" do
+      expect(registry).to receive(:data_exists?).with(key_path, value1).and_return(false)
+      expect { registry.data_exists!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegDataMissing)
+    end
+  end
+
+  describe "type_matches?" do
+    it "returns true if type matches" do
+      expect(registry).to receive(:value_exists!).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(registry).to receive(:get_type_from_name).with(:string).and_return(1)
+      expect(reg_mock).to receive(:each).and_yield("one", 1)
+      expect(registry.type_matches?(key_path, value1)).to eq(true)
+    end
+
+    it "returns false if type does not match" do
+      expect(registry).to receive(:value_exists!).with(key_path, value1).and_return(true)
+      expect(registry).to receive(:get_hive_and_key).with(key_path).and_return([hive_mock, key])
+      expect(hive_mock).to receive(:open).with(key, ::Win32::Registry::KEY_READ | registry.registry_system_architecture).and_yield(reg_mock)
+      expect(reg_mock).to receive(:each).and_yield("two", 2)
+      expect(registry.type_matches?(key_path, value1)).to eq(false)
+    end
+
+    it "throws an exception if value does not exist" do
+      expect(registry).to receive(:value_exists?).with(key_path, value1).and_return(false)
+      expect { registry.type_matches?(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegValueMissing)
+    end
+  end
+
+  describe "type_matches!" do
+    it "does nothing if the type_matches" do
+      expect(registry).to receive(:type_matches?).with(key_path, value1).and_return(true)
+      registry.type_matches!(key_path, value1)
+    end
+
+    it "throws an exception if the type does not match" do
+      expect(registry).to receive(:type_matches?).with(key_path, value1).and_return(false)
+      expect { registry.type_matches!(key_path, value1) }.to raise_error(Chef::Exceptions::Win32RegTypesMismatch)
+    end
+  end
+
+  describe "keys_missing?" do
+    it "returns true if the keys are missing" do
+      expect(registry).to receive(:key_exists?).with(missing_key_path).and_return(false)
+      expect(registry.keys_missing?(key_path)).to eq(true)
+    end
+
+    it "returns false if no keys in the path are missing" do
+      expect(registry).to receive(:key_exists?).with(missing_key_path).and_return(true)
+      expect(registry.keys_missing?(key_path)).to eq(false)
+    end
+  end
+end
diff --git a/spec/unit/windows_service_spec.rb b/spec/unit/windows_service_spec.rb
index bc5e781..3f9419b 100644
--- a/spec/unit/windows_service_spec.rb
+++ b/spec/unit/windows_service_spec.rb
@@ -1,6 +1,6 @@
 #
 # Author:: Mukta Aphale (<mukta.aphale at clogeny.com>)
-# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# Copyright:: Copyright 2013-2016, Chef Software, Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,57 +15,102 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-require 'spec_helper'
+require "spec_helper"
 if Chef::Platform.windows?
-  require 'chef/application/windows_service'
+  require "chef/application/windows_service"
 end
 
 describe "Chef::Application::WindowsService", :windows_only do
-  let (:instance) {Chef::Application::WindowsService.new}
-  let (:shell_out_result) {Object.new}
-  let (:tempfile) {Tempfile.new "log_file"}
+  let(:shell_out_result) { double("shellout", stdout: nil, stderr: nil) }
+  let(:config_options) do
+    {
+      log_location: STDOUT,
+      config_file: "test_config_file",
+      log_level: :info,
+    }
+  end
+  let(:timeout) { 7200 }
+  let(:shellout_options) do
+    {
+      :timeout => timeout,
+      :logger => Chef::Log,
+    }
+  end
+
   before do
-    allow(instance).to receive(:parse_options)
-    allow(shell_out_result).to receive(:stdout)
-    allow(shell_out_result).to receive(:stderr)
+    Chef::Config.merge!(config_options)
+    allow(subject).to receive(:configure_chef)
+    allow(subject).to receive(:parse_options)
+    allow(MonoLogger).to receive(:new)
+    allow(subject).to receive(:running?).and_return(true, false)
+    allow(subject).to receive(:state).and_return(4)
+    subject.service_init
   end
-  it "runs chef-client in new process" do
-    expect(instance).to receive(:configure_chef).twice
-    instance.service_init
-    expect(instance).to receive(:run_chef_client).and_call_original
-    expect(instance).to receive(:shell_out).and_return(shell_out_result)
-    allow(instance).to receive(:running?).and_return(true, false)
-    allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
-    allow(instance).to receive(:state).and_return(4)
-    instance.service_main
+
+  subject { Chef::Application::WindowsService.new }
+
+  it "passes DEFAULT_LOG_LOCATION to chef-client instead of STDOUT" do
+    expect(subject).to receive(:shell_out).with(
+      "chef-client.bat  --no-fork -c test_config_file -L #{Chef::Application::WindowsService::DEFAULT_LOG_LOCATION}",
+      shellout_options,
+    ).and_return(shell_out_result)
+    subject.service_main
   end
 
-  context 'when running chef-client' do
-    it "passes config params to new process with a default timeout of 2 hours (7200 seconds)" do
-      Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
-      expect(instance).to receive(:configure_chef).twice
-      instance.service_init
-      allow(instance).to receive(:running?).and_return(true, false)
-      allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
-      allow(instance).to receive(:state).and_return(4)
-      expect(instance).to receive(:run_chef_client).and_call_original
-      expect(instance).to receive(:shell_out).with("chef-client  --no-fork -c test_config_file -L #{tempfile.path}", {:timeout => 7200}).and_return(shell_out_result)
-      instance.service_main
+  context "has a log location configured" do
+    let(:tempfile) { Tempfile.new "log_file" }
+    let(:config_options) do
+      {
+        log_location: tempfile.path,
+        config_file: "test_config_file",
+        log_level: :info,
+      }
+    end
+
+    after do
       tempfile.unlink
     end
 
-    it "passes config params to new process with a the timeout specified in the config" do
-      Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
+    it "uses the configured log location" do
+      expect(subject).to receive(:shell_out).with(
+        "chef-client.bat  --no-fork -c test_config_file -L #{tempfile.path}",
+        shellout_options,
+      ).and_return(shell_out_result)
+      subject.service_main
+    end
+
+    context "configured to Event Logger" do
+      let(:config_options) do
+        {
+          log_location: Chef::Log::WinEvt.new,
+          config_file: "test_config_file",
+          log_level: :info,
+        }
+      end
+
+      it "does not pass log location to new process" do
+        expect(subject).to receive(:shell_out).with(
+          "chef-client.bat  --no-fork -c test_config_file",
+          shellout_options,
+        ).and_return(shell_out_result)
+        subject.service_main
+      end
+    end
+  end
+
+  context "configueres a watchdog timeout" do
+    let(:timeout) { 10 }
+
+    before do
       Chef::Config[:windows_service][:watchdog_timeout] = 10
-      expect(instance).to receive(:configure_chef).twice
-      instance.service_init
-      allow(instance).to receive(:running?).and_return(true, false)
-      allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
-      allow(instance).to receive(:state).and_return(4)
-      expect(instance).to receive(:run_chef_client).and_call_original
-      expect(instance).to receive(:shell_out).with("chef-client  --no-fork -c test_config_file -L #{tempfile.path}", {:timeout => 10}).and_return(shell_out_result)
-      instance.service_main
-      tempfile.unlink
+    end
+
+    it "passes watchdog timeout to new process" do
+      expect(subject).to receive(:shell_out).with(
+        "chef-client.bat  --no-fork -c test_config_file -L #{Chef::Application::WindowsService::DEFAULT_LOG_LOCATION}",
+        shellout_options,
+      ).and_return(shell_out_result)
+      subject.service_main
     end
   end
 end
diff --git a/spec/unit/workstation_config_loader_spec.rb b/spec/unit/workstation_config_loader_spec.rb
deleted file mode 100644
index 72631f3..0000000
--- a/spec/unit/workstation_config_loader_spec.rb
+++ /dev/null
@@ -1,283 +0,0 @@
-#
-# Author:: Daniel DeLeo (<dan at getchef.com>)
-# Copyright:: Copyright (c) 2014 Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require 'spec_helper'
-require 'tempfile'
-require 'chef/workstation_config_loader'
-
-describe Chef::WorkstationConfigLoader do
-
-  let(:explicit_config_location) { nil }
-
-  let(:env) { {} }
-
-  let(:config_loader) do
-    described_class.new(explicit_config_location).tap do |c|
-      allow(c).to receive(:env).and_return(env)
-    end
-  end
-
-  # Test methods that do I/O or reference external state which are stubbed out
-  # elsewhere.
-  describe "external dependencies" do
-    let(:config_loader) { described_class.new(nil) }
-
-    it "delegates to ENV for env" do
-      expect(config_loader.env).to equal(ENV)
-    end
-
-    it "tests a path's existence" do
-      expect(config_loader.path_exists?('/nope/nope/nope/nope/frab/jab/nab')).to be(false)
-      expect(config_loader.path_exists?(__FILE__)).to be(true)
-    end
-
-  end
-
-  describe "locating the config file" do
-    context "without an explicit config" do
-
-      before do
-        allow(config_loader).to receive(:path_exists?).with(an_instance_of(String)).and_return(false)
-      end
-
-      it "has no config if HOME is not set" do
-        expect(config_loader.config_location).to be(nil)
-        expect(config_loader.no_config_found?).to be(true)
-      end
-
-      context "when HOME is set and contains a knife.rb" do
-
-        let(:home) { "/Users/example.user" }
-
-        before do
-          allow(Chef::Util::PathHelper).to receive(:home).with('.chef').and_yield(File.join(home, '.chef'))
-          allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/knife.rb").and_return(true)
-        end
-
-        it "uses the config in HOME/.chef/knife.rb" do
-          expect(config_loader.config_location).to eq("#{home}/.chef/knife.rb")
-        end
-
-        context "and has a config.rb" do
-
-          before do
-            allow(config_loader).to receive(:path_exists?).with("#{home}/.chef/config.rb").and_return(true)
-          end
-
-          it "uses the config in HOME/.chef/config.rb" do
-            expect(config_loader.config_location).to eq("#{home}/.chef/config.rb")
-          end
-
-          context "and/or a parent dir contains a .chef dir" do
-
-            let(:env_pwd) { "/path/to/cwd" }
-
-            before do
-              if Chef::Platform.windows?
-                env["CD"] = env_pwd
-              else
-                env["PWD"] = env_pwd
-              end
-
-              allow(config_loader).to receive(:path_exists?).with("#{env_pwd}/.chef/knife.rb").and_return(true)
-              allow(File).to receive(:exist?).with("#{env_pwd}/.chef").and_return(true)
-              allow(File).to receive(:directory?).with("#{env_pwd}/.chef").and_return(true)
-            end
-
-            it "prefers the config from parent_dir/.chef" do
-              expect(config_loader.config_location).to eq("#{env_pwd}/.chef/knife.rb")
-            end
-
-            context "and the parent dir's .chef dir has a config.rb" do
-
-              before do
-                allow(config_loader).to receive(:path_exists?).with("#{env_pwd}/.chef/config.rb").and_return(true)
-              end
-
-              it "prefers the config from parent_dir/.chef" do
-                expect(config_loader.config_location).to eq("#{env_pwd}/.chef/config.rb")
-              end
-
-              context "and/or the current working directory contains a .chef dir" do
-
-                let(:cwd) { Dir.pwd }
-
-                before do
-                  allow(config_loader).to receive(:path_exists?).with("#{cwd}/knife.rb").and_return(true)
-                end
-
-                it "prefers a knife.rb located in the cwd" do
-                  expect(config_loader.config_location).to eq("#{cwd}/knife.rb")
-                end
-
-                context "and the CWD's .chef dir has a config.rb" do
-
-                  before do
-                    allow(config_loader).to receive(:path_exists?).with("#{cwd}/config.rb").and_return(true)
-                  end
-
-                  it "prefers a config located in the cwd" do
-                    expect(config_loader.config_location).to eq("#{cwd}/config.rb")
-                  end
-
-
-                  context "and/or KNIFE_HOME is set" do
-
-                    let(:knife_home) { "/path/to/knife/home" }
-
-                    before do
-                      env["KNIFE_HOME"] = knife_home
-                      allow(config_loader).to receive(:path_exists?).with("#{knife_home}/knife.rb").and_return(true)
-                    end
-
-                    it "prefers a knife located in KNIFE_HOME" do
-                      expect(config_loader.config_location).to eq("/path/to/knife/home/knife.rb")
-                    end
-
-                    context "and KNIFE_HOME contains a config.rb" do
-
-                      before do
-                        env["KNIFE_HOME"] = knife_home
-                        allow(config_loader).to receive(:path_exists?).with("#{knife_home}/config.rb").and_return(true)
-                      end
-
-                      it "prefers a config.rb located in KNIFE_HOME" do
-                        expect(config_loader.config_location).to eq("/path/to/knife/home/config.rb")
-                      end
-
-                    end
-
-                  end
-                end
-              end
-            end
-          end
-        end
-      end
-
-      context "when the current working dir is inside a symlinked directory" do
-        before do
-          # pwd according to your shell is /home/someuser/prod/chef-repo, but
-          # chef-repo is a symlink to /home/someuser/codes/chef-repo
-          env["CD"] = "/home/someuser/prod/chef-repo" # windows
-          env["PWD"] = "/home/someuser/prod/chef-repo" # unix
-
-          allow(Dir).to receive(:pwd).and_return("/home/someuser/codes/chef-repo")
-        end
-
-        it "loads the config from the non-dereferenced directory path" do
-          expect(File).to receive(:exist?).with("/home/someuser/prod/chef-repo/.chef").and_return(false)
-          expect(File).to receive(:exist?).with("/home/someuser/prod/.chef").and_return(true)
-          expect(File).to receive(:directory?).with("/home/someuser/prod/.chef").and_return(true)
-
-          expect(config_loader).to receive(:path_exists?).with("/home/someuser/prod/.chef/knife.rb").and_return(true)
-
-          expect(config_loader.config_location).to eq("/home/someuser/prod/.chef/knife.rb")
-        end
-      end
-    end
-
-    context "when given an explicit config to load" do
-
-      let(:explicit_config_location) { "/path/to/explicit/config.rb" }
-
-      it "prefers the explicit config" do
-        expect(config_loader.config_location).to eq(explicit_config_location)
-      end
-
-    end
-  end
-
-
-  describe "loading the config file" do
-
-    context "when no explicit config is specifed and no implicit config is found" do
-
-      before do
-        allow(config_loader).to receive(:path_exists?).with(an_instance_of(String)).and_return(false)
-      end
-
-      it "skips loading" do
-        expect(config_loader.config_location).to be(nil)
-        expect(config_loader.load).to be(false)
-      end
-
-    end
-
-    context "when an explicit config is given but it doesn't exist" do
-
-      let(:explicit_config_location) { "/nope/nope/nope/frab/jab/nab" }
-
-      it "raises a configuration error" do
-        expect { config_loader.load }.to raise_error(Chef::Exceptions::ConfigurationError)
-      end
-
-    end
-
-    context "when the config file exists" do
-
-      let(:config_content) { "" }
-
-      let(:explicit_config_location) do
-        # could use described_class, but remove all ':' from the path if so.
-        t = Tempfile.new("Chef-WorkstationConfigLoader-rspec-test")
-        t.print(config_content)
-        t.close
-        t.path
-      end
-
-      after { File.unlink(explicit_config_location) if File.exists?(explicit_config_location) }
-
-      context "and is valid" do
-
-        let(:config_content) { "config_file_evaluated(true)" }
-
-        it "loads the config" do
-          expect(config_loader.load).to be(true)
-          expect(Chef::Config.config_file_evaluated).to be(true)
-        end
-
-        it "sets Chef::Config.config_file" do
-          config_loader.load
-          expect(Chef::Config.config_file).to eq(explicit_config_location)
-        end
-      end
-
-      context "and has a syntax error" do
-
-        let(:config_content) { "{{{{{:{{" }
-
-        it "raises a ConfigurationError" do
-          expect { config_loader.load }.to raise_error(Chef::Exceptions::ConfigurationError)
-        end
-      end
-
-      context "and raises a ruby exception during evaluation" do
-
-        let(:config_content) { ":foo\n:bar\nraise 'oops'\n:baz\n" }
-
-        it "raises a ConfigurationError" do
-          expect { config_loader.load }.to raise_error(Chef::Exceptions::ConfigurationError)
-        end
-      end
-
-    end
-
-  end
-
-end
diff --git a/tasks/cbgb.rb b/tasks/cbgb.rb
new file mode 100644
index 0000000..9aa6700
--- /dev/null
+++ b/tasks/cbgb.rb
@@ -0,0 +1,84 @@
+#
+# Author:: Thom May (tmay at chef.io)
+# Author:: Nathen Harvey (nharvey at chef.io)
+# Copyright:: Copyright 2015-2016, Chef Software, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "rake"
+
+CBGB_SOURCE = File.join(File.dirname(__FILE__), "..", "CBGB.toml")
+CBGB_TARGET = File.join(File.dirname(__FILE__), "..", "CBGB.md")
+
+begin
+  require "tomlrb"
+
+  task :default => :generate
+
+  namespace :cbgb do
+    desc "Generate MarkDown version of CBGB file"
+    task :generate do
+      cbgb = Tomlrb.load_file CBGB_SOURCE
+      out = "<!-- This is a generated file. Please do not edit directly -->\n"
+      out << "<!-- Modify CBGB.toml file and run `rake cbgb:generate` to regenerate -->\n\n"
+      out << "# " + cbgb["Preamble"]["title"] + "\n\n"
+      out << cbgb["Preamble"]["text"] + "\n"
+      out << "# Board of Governors\n\n"
+      out << "## " + cbgb["Org"]["Lead"]["title"] + "\n\n"
+      out << person(cbgb["people"], cbgb["Org"]["Lead"]["person"]) + "\n\n"
+      out << "### " + cbgb["Org"]["Contributors"]["title"] + "\n\n"
+      out << cbgb(cbgb["people"], cbgb["Org"]["Contributors"]["governers"]) + "\n\n"
+      out << "### " + cbgb["Org"]["Corporate-Contributors"]["title"] + "\n\n"
+      out << cbgb(cbgb["corporations"], cbgb["Org"]["Corporate-Contributors"]["governers"]) + "\n\n"
+      out << "### " + cbgb["Org"]["Lieutenants"]["title"] + "\n\n"
+      out << cbgb(cbgb["people"], cbgb["Org"]["Lieutenants"]["governers"]) + "\n\n"
+      File.open(CBGB_TARGET, "w") { |fn|
+        fn.write out
+      }
+    end
+  end
+
+  def components(list, cmp)
+    out = ""
+    cmp.each do |k, v|
+      out << "\n#### #{v['title'].gsub('#', '\\#')}\n"
+      out << cbgb(list, v["cbgb"])
+    end
+    out
+  end
+
+  def cbgb(list, people)
+    o = ""
+    people.each do |p|
+      o << person(list, p) + "\n"
+    end
+    o
+  end
+
+  def person(list, person)
+    if list[person].has_key?("GitHub")
+      out = "* [#{list[person]["Name"]}](https://github.com/#{list[person]["GitHub"]})"
+    else
+      out =  "* #{list[person]["Name"]}"
+    end
+    if list[person].has_key?("Person")
+      out << " - #{list[person]["Person"]}"
+    end
+    out
+  end
+
+rescue LoadError
+  STDERR.puts "\n*** TomlRb not available.\n\n"
+end
diff --git a/tasks/external_tests.rb b/tasks/external_tests.rb
new file mode 100644
index 0000000..f6fd79c
--- /dev/null
+++ b/tasks/external_tests.rb
@@ -0,0 +1,64 @@
+require "tempfile"
+require "bundler"
+
+CURRENT_GEM_NAME = "chef"
+CURRENT_GEM_PATH = File.expand_path("../..", __FILE__)
+
+def bundle_exec_with_chef(test_gem, commands)
+  gem_path = Bundler.environment.specs[test_gem].first.full_gem_path
+  gemfile_path = File.join(gem_path, "Gemfile.#{CURRENT_GEM_NAME}-external-test")
+  gemfile = File.open(gemfile_path, "w")
+  begin
+    IO.read(File.join(gem_path, "Gemfile")).each_line do |line|
+      if line =~ /^\s*gemspec/
+        next
+      elsif line =~ /^\s*gem '#{CURRENT_GEM_NAME}'|\s*gem "#{CURRENT_GEM_NAME}"/
+        next
+      elsif line =~ /^\s*dev_gem\s*['"](.+)['"]\s*$/
+        line = "gem '#{$1}', github: 'poise/#{$1}'"
+      elsif line =~ /\s*gem\s*['"]#{test_gem}['"]/ # foodcritic      end
+        next
+      end
+      gemfile.puts(line)
+    end
+    gemfile.puts("gem #{CURRENT_GEM_NAME.inspect}, path: #{CURRENT_GEM_PATH.inspect}")
+    gemfile.puts("gemspec path: #{gem_path.inspect}")
+    gemfile.close
+    Dir.chdir(gem_path) do
+      Bundler.with_clean_env do
+        unless system({ "BUNDLE_GEMFILE" => gemfile_path, "RUBYOPT" => nil, "GEMFILE_MOD" => nil }, "bundle update")
+          raise "Error running bundle update of #{gemfile_path} in #{gem_path}: #{$?.exitstatus}\nGemfile:\n#{IO.read(gemfile_path)}"
+        end
+        Array(commands).each do |command|
+          unless system({ "BUNDLE_GEMFILE" => gemfile_path, "RUBYOPT" => nil, "GEMFILE_MOD" => nil }, "bundle exec #{command}")
+            raise "Error running bundle exec #{command} in #{gem_path} with BUNDLE_GEMFILE=#{gemfile_path}: #{$?.exitstatus}\nGemfile:\n#{IO.read(gemfile_path)}"
+          end
+        end
+      end
+    end
+  ensure
+    File.delete(gemfile_path) if File.exist?(gemfile_path)
+  end
+end
+
+EXTERNAL_PROJECTS = {
+  "chef-zero"             => [ "rake spec", "rake cheffs" ],
+  "cheffish"              => "rake spec",
+  "chef-provisioning"     => "rake spec",
+  "chef-provisioning-aws" => "rake spec",
+  "chef-sugar"            => "rake",
+  "foodcritic"            => "rake test",
+  "chefspec"              => "rake",
+  "chef-rewind"           => "rake spec",
+  "poise"                 => "rake spec",
+  "halite"                => "rake spec",
+  "knife-windows"         => "rake unit_spec",
+}
+
+task :external_specs => EXTERNAL_PROJECTS.keys.map { |g| :"#{g.sub("-", "_")}_spec" }
+
+EXTERNAL_PROJECTS.each do |test_gem, commands|
+  task :"#{test_gem.gsub("-", "_")}_spec" do
+    bundle_exec_with_chef(test_gem, commands)
+  end
+end
diff --git a/tasks/maintainers.rb b/tasks/maintainers.rb
new file mode 100644
index 0000000..535edda
--- /dev/null
+++ b/tasks/maintainers.rb
@@ -0,0 +1,210 @@
+#
+# Copyright:: Copyright 2015-2016, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "rake"
+
+SOURCE = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.toml")
+TARGET = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.md")
+
+# The list of repositories that teams should own
+REPOSITORIES = ["chef/chef", "chef/chef-census", "chef/chef-repo",
+                "chef/client-docs", "chef/ffi-yajl", "chef/libyajl2-gem",
+                "chef/mixlib-authentication", "chef/mixlib-cli",
+                "chef/mixlib-config", "chef/mixlib-install", "chef/mixlib-log",
+                "chef/mixlib-shellout", "chef/ohai", "chef/omnibus-chef"]
+
+begin
+  require "tomlrb"
+  require "octokit"
+  require "pp"
+  task :default => :generate
+
+  namespace :maintainers do
+    desc "Generate MarkDown version of MAINTAINERS file"
+    task :generate do
+      out = "<!-- This is a generated file. Please do not edit directly -->\n\n"
+      out << "# " + source["Preamble"]["title"] + "\n\n"
+      out << source["Preamble"]["text"] + "\n"
+
+      # The project lead is a special case
+      out << "# " + source["Org"]["Lead"]["title"] + "\n\n"
+      out << format_person(source["Org"]["Lead"]["person"]) + "\n\n"
+
+      out << format_components(source["Org"]["Components"])
+      File.open(TARGET, "w") { |fn|
+        fn.write out
+      }
+    end
+
+    desc "Synchronize GitHub teams"
+    # there's a special @chef/client-maintainers team that's everyone
+    # and then there's a team per component
+    task :synchronize do
+      Octokit.auto_paginate = true
+      get_github_teams
+      prepare_teams(source["Org"]["Components"].dup)
+      sync_teams!
+    end
+  end
+
+  def github
+    @github ||= Octokit::Client.new(:netrc => true)
+  end
+
+  def source
+    @source ||= Tomlrb.load_file SOURCE
+  end
+
+  def teams
+    @teams ||= { "client-maintainers" => { "title" => "Client Maintainers" } }
+  end
+
+  def add_members(team, name)
+    teams["client-maintainers"]["members"] ||= []
+    teams["client-maintainers"]["members"] << name
+    teams[team] ||= {}
+    teams[team]["members"] ||= []
+    teams[team]["members"] << name
+  end
+
+  def set_team_title(team, title)
+    teams[team] ||= {}
+    teams[team]["title"] = title
+  end
+
+  def gh_teams
+    @gh_teams ||= {}
+  end
+
+  # we have to resolve team names to ids. While we're at it, we can get the privacy
+  # setting, so we know whether we need to update it
+  def get_github_teams
+    github.org_teams("chef").each do |team|
+      gh_teams[team[:slug]] = { "id" => team[:id], "privacy" => team[:privacy] }
+    end
+  end
+
+  def get_github_team(team)
+    github.team_members(gh_teams[team]["id"]).map do |member|
+      member[:login]
+    end.sort.uniq.map(&:downcase)
+  rescue
+    []
+  end
+
+  def create_team(team)
+    puts "creating new github team: #{team} with title: #{teams[team]["title"]} "
+    t = github.create_team("chef", name: team, description: teams[team]["title"],
+                                   privacy: "closed", repo_names: REPOSITORIES,
+                                   accept: "application/vnd.github.ironman-preview+json")
+    gh_teams[team] = { "id" => t[:id], "privacy" => t[:privacy] }
+  end
+
+  def compare_teams(current, desired)
+    # additions are the subtraction of the current state from the desired state
+    # deletions are the subtraction of the desired state from the current state
+    [desired - current, current - desired]
+  end
+
+  def prepare_teams(cmp)
+    %w{text paths}.each { |k| cmp.delete(k) }
+    if cmp.key?("team")
+      team = cmp.delete("team")
+      add_members(team, cmp.delete("lieutenant")) if cmp.key?("lieutenant")
+      add_members(team, cmp.delete("maintainers")) if cmp.key?("maintainers")
+      set_team_title(team, cmp.delete("title"))
+    else
+      %w{maintainers lieutenant title}.each { |k| cmp.delete(k) }
+    end
+    cmp.each { |_k, v| prepare_teams(v) }
+  end
+
+  def update_team(team, additions, deletions)
+    create_team(team) unless gh_teams.key?(team)
+    update_team_privacy(team)
+    add_team_members(team, additions)
+    remove_team_members(team, deletions)
+  rescue
+    puts "failed for #{team}"
+  end
+
+  def update_team_privacy(team)
+    return if gh_teams[team]["privacy"] == "closed"
+    puts "Setting #{team} privacy to closed from #{gh_teams[team]["privacy"]}"
+    github.update_team(gh_teams[team]["id"], privacy: "closed",
+                                             accept: "application/vnd.github.ironman-preview+json")
+  end
+
+  def add_team_members(team, additions)
+    additions.each do |member|
+      puts "Adding #{member} to #{team}"
+      github.add_team_membership(gh_teams[team]["id"], member, role: "member",
+                                                               accept: "application/vnd.github.ironman-preview+json")
+    end
+  end
+
+  def remove_team_members(team, deletions)
+    deletions.each do |member|
+      puts "Removing #{member} from #{team}"
+      github.remove_team_membership(gh_teams[team]["id"], member,
+                                    accept: "application/vnd.github.ironman-preview+json")
+    end
+  end
+
+  def sync_teams!
+    teams.each do |name, details|
+      current = get_github_team(name)
+      desired = details["members"].flatten.sort.uniq.map(&:downcase)
+      additions, deletions = compare_teams(current, desired)
+      update_team(name, additions, deletions)
+    end
+  end
+
+  def get_person(person)
+    source["people"][person]
+  end
+
+  def format_components(cmp)
+    out = "## " + cmp.delete("title") + "\n\n"
+    out << cmp.delete("text") + "\n" if cmp.has_key?("text")
+    out << "To mention the team, use @chef/#{cmp.delete("team")}\n\n" if cmp.has_key?("team")
+    if cmp.has_key?("lieutenant")
+      out << "### Lieutenant\n\n"
+      out << format_person(cmp.delete("lieutenant")) + "\n\n"
+    end
+    out << format_maintainers(cmp.delete("maintainers")) + "\n" if cmp.has_key?("maintainers")
+    cmp.delete("paths")
+    cmp.each { |k, v| out << format_components(v) }
+    out
+  end
+
+  def format_maintainers(people)
+    o = "### Maintainers\n\n"
+    people.each do |p|
+      o << format_person(p) + "\n"
+    end
+    o
+  end
+
+  def format_person(person)
+    mnt = get_person(person)
+    "* [#{mnt["Name"]}](https://github.com/#{mnt["GitHub"]})"
+  end
+
+rescue LoadError
+  STDERR.puts "\n*** TomlRb not available.\n\n"
+end
diff --git a/tasks/rspec.rb b/tasks/rspec.rb
index a6fc5a9..a52960f 100644
--- a/tasks/rspec.rb
+++ b/tasks/rspec.rb
@@ -1,7 +1,7 @@
 #
-# Author:: Adam Jacob (<adam at opscode.com>)
-# Author:: Daniel DeLeo (<dan at opscode.com>)
-# Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
+# Author:: Adam Jacob (<adam at chef.io>)
+# Author:: Daniel DeLeo (<dan at chef.io>)
+# Copyright:: Copyright 2008-2016, Chef Software Inc.
 # License:: Apache License, Version 2.0
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,53 +17,69 @@
 # limitations under the License.
 #
 
-require 'rubygems'
-require 'rake'
+require "rubygems"
+require "rake"
 
 CHEF_ROOT = File.join(File.dirname(__FILE__), "..")
 
 begin
-  require 'rspec/core/rake_task'
+  require "rspec/core/rake_task"
+
+  desc "Run specs for Chef's Components"
+  task :component_specs do
+    Dir.chdir("chef-config") do
+      Bundler.with_clean_env do
+        sh("bundle install")
+        sh("bundle exec rake spec")
+      end
+    end
+  end
 
   task :default => :spec
 
+  task :spec => :component_specs
+
   desc "Run standard specs (minus long running specs)"
   RSpec::Core::RakeTask.new(:spec) do |t|
+    t.rspec_opts = %w{--profile}
     # right now this just limits to functional + unit, but could also remove
     # individual tests marked long-running
-    t.pattern = FileList['spec/{functional,unit}/**/*_spec.rb']
+    t.pattern = FileList["spec/**/*_spec.rb"]
   end
 
   namespace :spec do
     desc "Run all specs in spec directory with RCov"
     RSpec::Core::RakeTask.new(:rcov) do |t|
-      t.pattern = FileList['spec/**/*_spec.rb']
+      t.rspec_opts = %w{--profile}
+      t.pattern = FileList["spec/**/*_spec.rb"]
       t.rcov = true
       t.rcov_opts = lambda do
-        IO.readlines("#{CHEF_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
+        IO.readlines("#{CHEF_ROOT}/spec/rcov.opts").map { |l| l.chomp.split " " }.flatten
       end
     end
 
     desc "Run all specs in spec directory"
     RSpec::Core::RakeTask.new(:all) do |t|
-      t.pattern = FileList['spec/**/*_spec.rb']
+      t.rspec_opts = %w{--profile}
+      t.pattern = FileList["spec/**/*_spec.rb"]
     end
 
     desc "Print Specdoc for all specs"
     RSpec::Core::RakeTask.new(:doc) do |t|
-      t.rspec_opts = ["--format", "specdoc", "--dry-run"]
-      t.pattern = FileList['spec/**/*_spec.rb']
+      t.rspec_opts = %w{--format specdoc --dry-run --profile}
+      t.pattern = FileList["spec/**/*_spec.rb"]
     end
 
     desc "Run the specs under spec/unit with activesupport loaded"
     RSpec::Core::RakeTask.new(:activesupport) do |t|
-      t.rspec_opts = ["--require active_support/core_ext"]
-      t.pattern = FileList['spec/unit/**/*_spec.rb']
+      t.rspec_opts = %w{--require active_support/core_ext --profile}
+      t.pattern = FileList["spec/unit/**/*_spec.rb"]
     end
 
     [:unit, :functional, :integration, :stress].each do |sub|
       desc "Run the specs under spec/#{sub}"
       RSpec::Core::RakeTask.new(sub) do |t|
+        t.rspec_opts = %w{--profile}
         t.pattern = FileList["spec/#{sub}/**/*_spec.rb"]
       end
     end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/chef.git



More information about the Pkg-ruby-extras-commits mailing list